diff options
Diffstat (limited to 'OpenSim/Region')
52 files changed, 13697 insertions, 1415 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 3d3c324..6a0da7b 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs | |||
@@ -812,16 +812,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
812 | } | 812 | } |
813 | } | 813 | } |
814 | 814 | ||
815 | public void SendGenericMessage(string method, List<string> message) | 815 | public void SendGenericMessage(string method, List<byte[]> message) |
816 | { | 816 | { |
817 | GenericMessagePacket gmp = new GenericMessagePacket(); | 817 | GenericMessagePacket gmp = new GenericMessagePacket(); |
818 | gmp.MethodData.Method = Util.StringToBytes256(method); | 818 | gmp.MethodData.Method = Util.StringToBytes256(method); |
819 | gmp.ParamList = new GenericMessagePacket.ParamListBlock[message.Count]; | 819 | gmp.ParamList = new GenericMessagePacket.ParamListBlock[message.Count]; |
820 | int i = 0; | 820 | int i = 0; |
821 | foreach (string val in message) | 821 | foreach (byte[] val in message) |
822 | { | 822 | { |
823 | gmp.ParamList[i] = new GenericMessagePacket.ParamListBlock(); | 823 | gmp.ParamList[i] = new GenericMessagePacket.ParamListBlock(); |
824 | gmp.ParamList[i++].Parameter = Util.StringToBytes256(val); | 824 | gmp.ParamList[i++].Parameter = val; |
825 | } | 825 | } |
826 | OutPacket(gmp, ThrottleOutPacketType.Task); | 826 | OutPacket(gmp, ThrottleOutPacketType.Task); |
827 | } | 827 | } |
@@ -1020,6 +1020,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1020 | public virtual void SendLayerData(float[] map) | 1020 | public virtual void SendLayerData(float[] map) |
1021 | { | 1021 | { |
1022 | Util.FireAndForget(DoSendLayerData, map); | 1022 | Util.FireAndForget(DoSendLayerData, map); |
1023 | |||
1024 | // Send it sync, and async. It's not that much data | ||
1025 | // and it improves user experience just so much! | ||
1026 | DoSendLayerData(map); | ||
1023 | } | 1027 | } |
1024 | 1028 | ||
1025 | /// <summary> | 1029 | /// <summary> |
@@ -1032,16 +1036,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1032 | 1036 | ||
1033 | try | 1037 | try |
1034 | { | 1038 | { |
1035 | //for (int y = 0; y < 16; y++) | 1039 | for (int y = 0; y < 16; y++) |
1036 | //{ | 1040 | { |
1037 | // for (int x = 0; x < 16; x++) | 1041 | for (int x = 0; x < 16; x+=4) |
1038 | // { | 1042 | { |
1039 | // SendLayerData(x, y, map); | 1043 | SendLayerPacket(x, y, map); |
1040 | // } | 1044 | } |
1041 | //} | 1045 | } |
1042 | |||
1043 | // Send LayerData in a spiral pattern. Fun! | ||
1044 | SendLayerTopRight(map, 0, 0, 15, 15); | ||
1045 | } | 1046 | } |
1046 | catch (Exception e) | 1047 | catch (Exception e) |
1047 | { | 1048 | { |
@@ -1049,51 +1050,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1049 | } | 1050 | } |
1050 | } | 1051 | } |
1051 | 1052 | ||
1052 | private void SendLayerTopRight(float[] map, int x1, int y1, int x2, int y2) | ||
1053 | { | ||
1054 | // Row | ||
1055 | for (int i = x1; i <= x2; i++) | ||
1056 | SendLayerData(i, y1, map); | ||
1057 | |||
1058 | // Column | ||
1059 | for (int j = y1 + 1; j <= y2; j++) | ||
1060 | SendLayerData(x2, j, map); | ||
1061 | |||
1062 | if (x2 - x1 > 0) | ||
1063 | SendLayerBottomLeft(map, x1, y1 + 1, x2 - 1, y2); | ||
1064 | } | ||
1065 | |||
1066 | void SendLayerBottomLeft(float[] map, int x1, int y1, int x2, int y2) | ||
1067 | { | ||
1068 | // Row in reverse | ||
1069 | for (int i = x2; i >= x1; i--) | ||
1070 | SendLayerData(i, y2, map); | ||
1071 | |||
1072 | // Column in reverse | ||
1073 | for (int j = y2 - 1; j >= y1; j--) | ||
1074 | SendLayerData(x1, j, map); | ||
1075 | |||
1076 | if (x2 - x1 > 0) | ||
1077 | SendLayerTopRight(map, x1 + 1, y1, x2, y2 - 1); | ||
1078 | } | ||
1079 | |||
1080 | /// <summary> | 1053 | /// <summary> |
1081 | /// Sends a set of four patches (x, x+1, ..., x+3) to the client | 1054 | /// Sends a set of four patches (x, x+1, ..., x+3) to the client |
1082 | /// </summary> | 1055 | /// </summary> |
1083 | /// <param name="map">heightmap</param> | 1056 | /// <param name="map">heightmap</param> |
1084 | /// <param name="px">X coordinate for patches 0..12</param> | 1057 | /// <param name="px">X coordinate for patches 0..12</param> |
1085 | /// <param name="py">Y coordinate for patches 0..15</param> | 1058 | /// <param name="py">Y coordinate for patches 0..15</param> |
1086 | // private void SendLayerPacket(float[] map, int y, int x) | 1059 | private void SendLayerPacket(int x, int y, float[] map) |
1087 | // { | 1060 | { |
1088 | // int[] patches = new int[4]; | 1061 | int[] patches = new int[4]; |
1089 | // patches[0] = x + 0 + y * 16; | 1062 | patches[0] = x + 0 + y * 16; |
1090 | // patches[1] = x + 1 + y * 16; | 1063 | patches[1] = x + 1 + y * 16; |
1091 | // patches[2] = x + 2 + y * 16; | 1064 | patches[2] = x + 2 + y * 16; |
1092 | // patches[3] = x + 3 + y * 16; | 1065 | patches[3] = x + 3 + y * 16; |
1093 | 1066 | ||
1094 | // Packet layerpack = LLClientView.TerrainManager.CreateLandPacket(map, patches); | 1067 | float[] heightmap = (map.Length == 65536) ? |
1095 | // OutPacket(layerpack, ThrottleOutPacketType.Land); | 1068 | map : |
1096 | // } | 1069 | LLHeightFieldMoronize(map); |
1070 | |||
1071 | try | ||
1072 | { | ||
1073 | Packet layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches); | ||
1074 | OutPacket(layerpack, ThrottleOutPacketType.Land); | ||
1075 | } | ||
1076 | catch | ||
1077 | { | ||
1078 | for (int px = x ; px < x + 4 ; px++) | ||
1079 | SendLayerData(px, y, map); | ||
1080 | } | ||
1081 | } | ||
1097 | 1082 | ||
1098 | /// <summary> | 1083 | /// <summary> |
1099 | /// Sends a specified patch to a client | 1084 | /// Sends a specified patch to a client |
@@ -3371,7 +3356,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3371 | 3356 | ||
3372 | objupdate.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1]; | 3357 | objupdate.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1]; |
3373 | objupdate.ObjectData[0] = CreateAvatarUpdateBlock(data); | 3358 | objupdate.ObjectData[0] = CreateAvatarUpdateBlock(data); |
3374 | |||
3375 | OutPacket(objupdate, ThrottleOutPacketType.Task); | 3359 | OutPacket(objupdate, ThrottleOutPacketType.Task); |
3376 | } | 3360 | } |
3377 | 3361 | ||
@@ -3422,8 +3406,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3422 | terse.ObjectData[i] = m_avatarTerseUpdates.Dequeue(); | 3406 | terse.ObjectData[i] = m_avatarTerseUpdates.Dequeue(); |
3423 | } | 3407 | } |
3424 | 3408 | ||
3425 | // HACK: Using the task category until the tiered reprioritization code is in | 3409 | OutPacket(terse, ThrottleOutPacketType.State); |
3426 | OutPacket(terse, ThrottleOutPacketType.Task); | ||
3427 | } | 3410 | } |
3428 | 3411 | ||
3429 | public void SendCoarseLocationUpdate(List<UUID> users, List<Vector3> CoarseLocations) | 3412 | public void SendCoarseLocationUpdate(List<UUID> users, List<Vector3> CoarseLocations) |
@@ -4814,6 +4797,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4814 | (x.CameraLeftAxis != lastarg.CameraLeftAxis) || | 4797 | (x.CameraLeftAxis != lastarg.CameraLeftAxis) || |
4815 | (x.CameraUpAxis != lastarg.CameraUpAxis) || | 4798 | (x.CameraUpAxis != lastarg.CameraUpAxis) || |
4816 | (x.ControlFlags != lastarg.ControlFlags) || | 4799 | (x.ControlFlags != lastarg.ControlFlags) || |
4800 | (x.ControlFlags != 0) || | ||
4817 | (x.Far != lastarg.Far) || | 4801 | (x.Far != lastarg.Far) || |
4818 | (x.Flags != lastarg.Flags) || | 4802 | (x.Flags != lastarg.Flags) || |
4819 | (x.State != lastarg.State) || | 4803 | (x.State != lastarg.State) || |
diff --git a/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs b/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs index 6dacbba..e3e8718 100644 --- a/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs | |||
@@ -49,7 +49,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat | |||
49 | private int m_shoutdistance = 100; | 49 | private int m_shoutdistance = 100; |
50 | private int m_whisperdistance = 10; | 50 | private int m_whisperdistance = 10; |
51 | private List<Scene> m_scenes = new List<Scene>(); | 51 | private List<Scene> m_scenes = new List<Scene>(); |
52 | 52 | private string m_adminPrefix = ""; | |
53 | internal object m_syncy = new object(); | 53 | internal object m_syncy = new object(); |
54 | 54 | ||
55 | internal IConfig m_config; | 55 | internal IConfig m_config; |
@@ -76,6 +76,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat | |||
76 | m_whisperdistance = config.Configs["Chat"].GetInt("whisper_distance", m_whisperdistance); | 76 | m_whisperdistance = config.Configs["Chat"].GetInt("whisper_distance", m_whisperdistance); |
77 | m_saydistance = config.Configs["Chat"].GetInt("say_distance", m_saydistance); | 77 | m_saydistance = config.Configs["Chat"].GetInt("say_distance", m_saydistance); |
78 | m_shoutdistance = config.Configs["Chat"].GetInt("shout_distance", m_shoutdistance); | 78 | m_shoutdistance = config.Configs["Chat"].GetInt("shout_distance", m_shoutdistance); |
79 | m_adminPrefix = config.Configs["Chat"].GetString("admin_prefix", ""); | ||
79 | } | 80 | } |
80 | 81 | ||
81 | public virtual void AddRegion(Scene scene) | 82 | public virtual void AddRegion(Scene scene) |
@@ -185,6 +186,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat | |||
185 | protected virtual void DeliverChatToAvatars(ChatSourceType sourceType, OSChatMessage c) | 186 | protected virtual void DeliverChatToAvatars(ChatSourceType sourceType, OSChatMessage c) |
186 | { | 187 | { |
187 | string fromName = c.From; | 188 | string fromName = c.From; |
189 | string fromNamePrefix = ""; | ||
188 | UUID fromID = UUID.Zero; | 190 | UUID fromID = UUID.Zero; |
189 | string message = c.Message; | 191 | string message = c.Message; |
190 | IScene scene = c.Scene; | 192 | IScene scene = c.Scene; |
@@ -207,7 +209,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat | |||
207 | fromPos = avatar.AbsolutePosition; | 209 | fromPos = avatar.AbsolutePosition; |
208 | fromName = avatar.Name; | 210 | fromName = avatar.Name; |
209 | fromID = c.Sender.AgentId; | 211 | fromID = c.Sender.AgentId; |
210 | 212 | if (avatar.GodLevel > 200) | |
213 | { | ||
214 | fromNamePrefix = m_adminPrefix; | ||
215 | } | ||
211 | break; | 216 | break; |
212 | 217 | ||
213 | case ChatSourceType.Object: | 218 | case ChatSourceType.Object: |
@@ -227,7 +232,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat | |||
227 | s.ForEachScenePresence( | 232 | s.ForEachScenePresence( |
228 | delegate(ScenePresence presence) | 233 | delegate(ScenePresence presence) |
229 | { | 234 | { |
230 | TrySendChatMessage(presence, fromPos, regionPos, fromID, fromName, c.Type, message, sourceType); | 235 | TrySendChatMessage(presence, fromPos, regionPos, fromID, fromNamePrefix+fromName, c.Type, message, sourceType); |
231 | } | 236 | } |
232 | ); | 237 | ); |
233 | } | 238 | } |
@@ -266,25 +271,29 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat | |||
266 | } | 271 | } |
267 | 272 | ||
268 | // m_log.DebugFormat("[CHAT] Broadcast: fromID {0} fromName {1}, cType {2}, sType {3}", fromID, fromName, cType, sourceType); | 273 | // m_log.DebugFormat("[CHAT] Broadcast: fromID {0} fromName {1}, cType {2}, sType {3}", fromID, fromName, cType, sourceType); |
269 | 274 | if (c.Scene != null) | |
270 | ((Scene)c.Scene).ForEachScenePresence( | 275 | { |
271 | delegate(ScenePresence presence) | 276 | ((Scene)c.Scene).ForEachScenePresence |
272 | { | 277 | ( |
273 | // ignore chat from child agents | 278 | delegate(ScenePresence presence) |
274 | if (presence.IsChildAgent) return; | 279 | { |
275 | 280 | // ignore chat from child agents | |
276 | IClientAPI client = presence.ControllingClient; | 281 | if (presence.IsChildAgent) return; |
277 | 282 | ||
278 | // don't forward SayOwner chat from objects to | 283 | IClientAPI client = presence.ControllingClient; |
279 | // non-owner agents | 284 | |
280 | if ((c.Type == ChatTypeEnum.Owner) && | 285 | // don't forward SayOwner chat from objects to |
281 | (null != c.SenderObject) && | 286 | // non-owner agents |
282 | (((SceneObjectPart)c.SenderObject).OwnerID != client.AgentId)) | 287 | if ((c.Type == ChatTypeEnum.Owner) && |
283 | return; | 288 | (null != c.SenderObject) && |
284 | 289 | (((SceneObjectPart)c.SenderObject).OwnerID != client.AgentId)) | |
285 | client.SendChatMessage(c.Message, (byte)cType, CenterOfRegion, fromName, fromID, | 290 | return; |
286 | (byte)sourceType, (byte)ChatAudibleLevel.Fully); | 291 | |
287 | }); | 292 | client.SendChatMessage(c.Message, (byte)cType, CenterOfRegion, fromName, fromID, |
293 | (byte)sourceType, (byte)ChatAudibleLevel.Fully); | ||
294 | } | ||
295 | ); | ||
296 | } | ||
288 | } | 297 | } |
289 | 298 | ||
290 | 299 | ||
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs index 450897c..257c221 100644 --- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs | |||
@@ -168,19 +168,22 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
168 | List<GridInstantMessage>msglist = SynchronousRestObjectPoster.BeginPostObject<UUID, List<GridInstantMessage>>( | 168 | List<GridInstantMessage>msglist = SynchronousRestObjectPoster.BeginPostObject<UUID, List<GridInstantMessage>>( |
169 | "POST", m_RestURL+"/RetrieveMessages/", client.AgentId); | 169 | "POST", m_RestURL+"/RetrieveMessages/", client.AgentId); |
170 | 170 | ||
171 | foreach (GridInstantMessage im in msglist) | 171 | if (msglist != null) |
172 | { | 172 | { |
173 | // client.SendInstantMessage(im); | 173 | foreach (GridInstantMessage im in msglist) |
174 | 174 | { | |
175 | // Send through scene event manager so all modules get a chance | 175 | // client.SendInstantMessage(im); |
176 | // to look at this message before it gets delivered. | 176 | |
177 | // | 177 | // Send through scene event manager so all modules get a chance |
178 | // Needed for proper state management for stored group | 178 | // to look at this message before it gets delivered. |
179 | // invitations | 179 | // |
180 | // | 180 | // Needed for proper state management for stored group |
181 | Scene s = FindScene(client.AgentId); | 181 | // invitations |
182 | if (s != null) | 182 | // |
183 | s.EventManager.TriggerIncomingInstantMessage(im); | 183 | Scene s = FindScene(client.AgentId); |
184 | if (s != null) | ||
185 | s.EventManager.TriggerIncomingInstantMessage(im); | ||
186 | } | ||
184 | } | 187 | } |
185 | } | 188 | } |
186 | 189 | ||
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs index d9a021f..b60b32b 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs | |||
@@ -389,7 +389,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer | |||
389 | { | 389 | { |
390 | // Check if this is ours to handle | 390 | // Check if this is ours to handle |
391 | // | 391 | // |
392 | m_log.Info("OnFridInstantMessage"); | 392 | //m_log.Info("OnFridInstantMessage"); |
393 | if (msg.dialog != (byte) InstantMessageDialog.InventoryOffered) | 393 | if (msg.dialog != (byte) InstantMessageDialog.InventoryOffered) |
394 | return; | 394 | return; |
395 | 395 | ||
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Interregion/RESTInterregionComms.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Interregion/RESTInterregionComms.cs index 44458d1..0357c60 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Interregion/RESTInterregionComms.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Interregion/RESTInterregionComms.cs | |||
@@ -331,12 +331,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Interregion | |||
331 | { | 331 | { |
332 | //m_log.Debug("[CONNECTION DEBUGGING]: AgentHandler Called"); | 332 | //m_log.Debug("[CONNECTION DEBUGGING]: AgentHandler Called"); |
333 | 333 | ||
334 | m_log.Debug("---------------------------"); | 334 | /* m_log.Debug("---------------------------"); |
335 | m_log.Debug(" >> uri=" + request["uri"]); | 335 | m_log.Debug(" >> uri=" + request["uri"]); |
336 | m_log.Debug(" >> content-type=" + request["content-type"]); | 336 | m_log.Debug(" >> content-type=" + request["content-type"]); |
337 | m_log.Debug(" >> http-method=" + request["http-method"]); | 337 | m_log.Debug(" >> http-method=" + request["http-method"]); |
338 | m_log.Debug("---------------------------\n"); | 338 | m_log.Debug("---------------------------\n"); */ |
339 | |||
340 | Hashtable responsedata = new Hashtable(); | 339 | Hashtable responsedata = new Hashtable(); |
341 | responsedata["content_type"] = "text/html"; | 340 | responsedata["content_type"] = "text/html"; |
342 | responsedata["keepalive"] = false; | 341 | responsedata["keepalive"] = false; |
@@ -581,11 +580,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Interregion | |||
581 | { | 580 | { |
582 | m_log.Debug("[CONNECTION DEBUGGING]: ObjectHandler Called"); | 581 | m_log.Debug("[CONNECTION DEBUGGING]: ObjectHandler Called"); |
583 | 582 | ||
584 | m_log.Debug("---------------------------"); | 583 | /* m_log.Debug("---------------------------"); |
585 | m_log.Debug(" >> uri=" + request["uri"]); | 584 | m_log.Debug(" >> uri=" + request["uri"]); |
586 | m_log.Debug(" >> content-type=" + request["content-type"]); | 585 | m_log.Debug(" >> content-type=" + request["content-type"]); |
587 | m_log.Debug(" >> http-method=" + request["http-method"]); | 586 | m_log.Debug(" >> http-method=" + request["http-method"]); |
588 | m_log.Debug("---------------------------\n"); | 587 | m_log.Debug("---------------------------\n"); */ |
589 | 588 | ||
590 | Hashtable responsedata = new Hashtable(); | 589 | Hashtable responsedata = new Hashtable(); |
591 | responsedata["content_type"] = "text/html"; | 590 | responsedata["content_type"] = "text/html"; |
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs index 52add23..68d13b7 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs | |||
@@ -247,21 +247,20 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
247 | // Fix ownership/creator of inventory items | 247 | // Fix ownership/creator of inventory items |
248 | // Not doing so results in inventory items | 248 | // Not doing so results in inventory items |
249 | // being no copy/no mod for everyone | 249 | // being no copy/no mod for everyone |
250 | lock (part.TaskInventory) | 250 | part.TaskInventory.LockItemsForRead(true); |
251 | TaskInventoryDictionary inv = part.TaskInventory; | ||
252 | foreach (KeyValuePair<UUID, TaskInventoryItem> kvp in inv) | ||
251 | { | 253 | { |
252 | TaskInventoryDictionary inv = part.TaskInventory; | 254 | if (!ResolveUserUuid(kvp.Value.OwnerID)) |
253 | foreach (KeyValuePair<UUID, TaskInventoryItem> kvp in inv) | ||
254 | { | 255 | { |
255 | if (!ResolveUserUuid(kvp.Value.OwnerID)) | 256 | kvp.Value.OwnerID = masterAvatarId; |
256 | { | 257 | } |
257 | kvp.Value.OwnerID = masterAvatarId; | 258 | if (!ResolveUserUuid(kvp.Value.CreatorID)) |
258 | } | 259 | { |
259 | if (!ResolveUserUuid(kvp.Value.CreatorID)) | 260 | kvp.Value.CreatorID = masterAvatarId; |
260 | { | ||
261 | kvp.Value.CreatorID = masterAvatarId; | ||
262 | } | ||
263 | } | 261 | } |
264 | } | 262 | } |
263 | part.TaskInventory.LockItemsForRead(false); | ||
265 | } | 264 | } |
266 | 265 | ||
267 | if (m_scene.AddRestoredSceneObject(sceneObject, true, false)) | 266 | if (m_scene.AddRestoredSceneObject(sceneObject, true, false)) |
diff --git a/OpenSim/Region/CoreModules/World/Meta7Windlight/Meta7WindlightModule.cs b/OpenSim/Region/CoreModules/World/Meta7Windlight/Meta7WindlightModule.cs new file mode 100644 index 0000000..72b0b38 --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Meta7Windlight/Meta7WindlightModule.cs | |||
@@ -0,0 +1,274 @@ | |||
1 | /* | ||
2 | * Copyright (c) Thomas Grimshaw and Magne Metaverse Research | ||
3 | * | ||
4 | * This module is not open source. All rights reserved. | ||
5 | * Unauthorised copying, distribution or public display is prohibited. | ||
6 | * | ||
7 | */ | ||
8 | |||
9 | using System; | ||
10 | using System.Collections.Generic; | ||
11 | using System.IO; | ||
12 | using System.Reflection; | ||
13 | using OpenMetaverse; | ||
14 | using log4net; | ||
15 | using Nini.Config; | ||
16 | using OpenSim.Data; | ||
17 | using OpenSim.Framework; | ||
18 | using OpenSim.Region.CoreModules.Framework.InterfaceCommander; | ||
19 | using OpenSim.Region.Framework.Interfaces; | ||
20 | using OpenSim.Region.Framework.Scenes; | ||
21 | |||
22 | |||
23 | namespace OpenSim.Region.CoreModules.World.Meta7Windlight | ||
24 | { | ||
25 | public class Meta7WindlightModule : IRegionModule, ICommandableModule | ||
26 | { | ||
27 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
28 | private readonly Commander m_commander = new Commander("windlight"); | ||
29 | private Scene m_scene; | ||
30 | private static bool m_enableWindlight; | ||
31 | |||
32 | #region ICommandableModule Members | ||
33 | |||
34 | public ICommander CommandInterface | ||
35 | { | ||
36 | get { return m_commander; } | ||
37 | } | ||
38 | |||
39 | #endregion | ||
40 | |||
41 | #region IRegionModule Members | ||
42 | |||
43 | public static bool EnableWindlight | ||
44 | { | ||
45 | get | ||
46 | { | ||
47 | return m_enableWindlight; | ||
48 | } | ||
49 | set | ||
50 | { | ||
51 | } | ||
52 | } | ||
53 | |||
54 | public void Initialise(Scene scene, IConfigSource config) | ||
55 | { | ||
56 | m_scene = scene; | ||
57 | m_scene.RegisterModuleInterface<IRegionModule>(this); | ||
58 | m_scene.EventManager.OnPluginConsole += EventManager_OnPluginConsole; | ||
59 | |||
60 | // ini file settings | ||
61 | try | ||
62 | { | ||
63 | m_enableWindlight = config.Configs["Meta7Windlight"].GetBoolean("enable_windlight", false); | ||
64 | } | ||
65 | catch (Exception) | ||
66 | { | ||
67 | m_log.Debug("[WINDLIGHT]: ini failure for enable_windlight - using default"); | ||
68 | } | ||
69 | |||
70 | if (m_enableWindlight) | ||
71 | { | ||
72 | m_scene.EventManager.OnMakeRootAgent += EventManager_OnMakeRootAgent; | ||
73 | m_scene.EventManager.OnSaveNewWindlightProfile += EventManager_OnSaveNewWindlightProfile; | ||
74 | m_scene.EventManager.OnSendNewWindlightProfileTargeted += EventManager_OnSendNewWindlightProfileTargeted; | ||
75 | } | ||
76 | |||
77 | InstallCommands(); | ||
78 | |||
79 | m_log.Debug("[WINDLIGHT]: Initialised windlight module"); | ||
80 | } | ||
81 | |||
82 | private List<byte[]> compileWindlightSettings(RegionMeta7WindlightData wl) | ||
83 | { | ||
84 | byte[] mBlock = new Byte[249]; | ||
85 | int pos = 0; | ||
86 | |||
87 | wl.waterColor.ToBytes(mBlock, 0); pos += 12; | ||
88 | Utils.FloatToBytes(wl.waterFogDensityExponent).CopyTo(mBlock, pos); pos += 4; | ||
89 | Utils.FloatToBytes(wl.underwaterFogModifier).CopyTo(mBlock, pos); pos += 4; | ||
90 | wl.reflectionWaveletScale.ToBytes(mBlock, pos); pos += 12; | ||
91 | Utils.FloatToBytes(wl.fresnelScale).CopyTo(mBlock, pos); pos += 4; | ||
92 | Utils.FloatToBytes(wl.fresnelOffset).CopyTo(mBlock, pos); pos += 4; | ||
93 | Utils.FloatToBytes(wl.refractScaleAbove).CopyTo(mBlock, pos); pos += 4; | ||
94 | Utils.FloatToBytes(wl.refractScaleBelow).CopyTo(mBlock, pos); pos += 4; | ||
95 | Utils.FloatToBytes(wl.blurMultiplier).CopyTo(mBlock, pos); pos += 4; | ||
96 | wl.bigWaveDirection.ToBytes(mBlock, pos); pos += 8; | ||
97 | wl.littleWaveDirection.ToBytes(mBlock, pos); pos += 8; | ||
98 | wl.normalMapTexture.ToBytes(mBlock, pos); pos += 16; | ||
99 | wl.horizon.ToBytes(mBlock, pos); pos += 16; | ||
100 | Utils.FloatToBytes(wl.hazeHorizon).CopyTo(mBlock, pos); pos += 4; | ||
101 | wl.blueDensity.ToBytes(mBlock, pos); pos += 16; | ||
102 | Utils.FloatToBytes(wl.hazeDensity).CopyTo(mBlock, pos); pos += 4; | ||
103 | Utils.FloatToBytes(wl.densityMultiplier).CopyTo(mBlock, pos); pos += 4; | ||
104 | Utils.FloatToBytes(wl.distanceMultiplier).CopyTo(mBlock, pos); pos += 4; | ||
105 | wl.sunMoonColor.ToBytes(mBlock, pos); pos += 16; | ||
106 | Utils.FloatToBytes(wl.sunMoonPosition).CopyTo(mBlock, pos); pos += 4; | ||
107 | wl.ambient.ToBytes(mBlock, pos); pos += 16; | ||
108 | Utils.FloatToBytes(wl.eastAngle).CopyTo(mBlock, pos); pos += 4; | ||
109 | Utils.FloatToBytes(wl.sunGlowFocus).CopyTo(mBlock, pos); pos += 4; | ||
110 | Utils.FloatToBytes(wl.sunGlowSize).CopyTo(mBlock, pos); pos += 4; | ||
111 | Utils.FloatToBytes(wl.sceneGamma).CopyTo(mBlock, pos); pos += 4; | ||
112 | Utils.FloatToBytes(wl.starBrightness).CopyTo(mBlock, pos); pos += 4; | ||
113 | wl.cloudColor.ToBytes(mBlock, pos); pos += 16; | ||
114 | wl.cloudXYDensity.ToBytes(mBlock, pos); pos += 12; | ||
115 | Utils.FloatToBytes(wl.cloudCoverage).CopyTo(mBlock, pos); pos += 4; | ||
116 | Utils.FloatToBytes(wl.cloudScale).CopyTo(mBlock, pos); pos += 4; | ||
117 | wl.cloudDetailXYDensity.ToBytes(mBlock, pos); pos += 12; | ||
118 | Utils.FloatToBytes(wl.cloudScrollX).CopyTo(mBlock, pos); pos += 4; | ||
119 | Utils.FloatToBytes(wl.cloudScrollY).CopyTo(mBlock, pos); pos += 4; | ||
120 | Utils.UInt16ToBytes(wl.maxAltitude).CopyTo(mBlock, pos); pos += 2; | ||
121 | mBlock[pos] = Convert.ToByte(wl.cloudScrollXLock); pos++; | ||
122 | mBlock[pos] = Convert.ToByte(wl.cloudScrollYLock); pos++; | ||
123 | mBlock[pos] = Convert.ToByte(wl.drawClassicClouds); pos++; | ||
124 | List<byte[]> param = new List<byte[]>(); | ||
125 | param.Add(mBlock); | ||
126 | return param; | ||
127 | } | ||
128 | public void SendProfileToClient(ScenePresence presence) | ||
129 | { | ||
130 | IClientAPI client = presence.ControllingClient; | ||
131 | if (m_enableWindlight) | ||
132 | { | ||
133 | if (presence.IsChildAgent == false) | ||
134 | { | ||
135 | List<byte[]> param = compileWindlightSettings(m_scene.RegionInfo.WindlightSettings); | ||
136 | client.SendGenericMessage("Windlight", param); | ||
137 | } | ||
138 | } | ||
139 | else | ||
140 | { | ||
141 | //We probably don't want to spam chat with this.. probably | ||
142 | //m_log.Debug("[WINDLIGHT]: Module disabled"); | ||
143 | } | ||
144 | } | ||
145 | public void SendProfileToClient(ScenePresence presence, RegionMeta7WindlightData wl) | ||
146 | { | ||
147 | IClientAPI client = presence.ControllingClient; | ||
148 | if (m_enableWindlight) | ||
149 | { | ||
150 | if (presence.IsChildAgent == false) | ||
151 | { | ||
152 | List<byte[]> param = compileWindlightSettings(wl); | ||
153 | client.SendGenericMessage("Windlight", param); | ||
154 | } | ||
155 | } | ||
156 | else | ||
157 | { | ||
158 | //We probably don't want to spam chat with this.. probably | ||
159 | //m_log.Debug("[WINDLIGHT]: Module disabled"); | ||
160 | } | ||
161 | } | ||
162 | private void EventManager_OnMakeRootAgent(ScenePresence presence) | ||
163 | { | ||
164 | m_log.Debug("[WINDLIGHT]: Sending windlight scene to new client"); | ||
165 | SendProfileToClient(presence); | ||
166 | } | ||
167 | private void EventManager_OnSendNewWindlightProfileTargeted(RegionMeta7WindlightData wl, UUID pUUID) | ||
168 | { | ||
169 | ScenePresence Sc; | ||
170 | if (m_scene.TryGetAvatar(pUUID,out Sc)) | ||
171 | { | ||
172 | SendProfileToClient(Sc,wl); | ||
173 | } | ||
174 | } | ||
175 | private void EventManager_OnSaveNewWindlightProfile() | ||
176 | { | ||
177 | m_scene.ForEachScenePresence(SendProfileToClient); | ||
178 | } | ||
179 | |||
180 | public void PostInitialise() | ||
181 | { | ||
182 | |||
183 | } | ||
184 | |||
185 | public void Close() | ||
186 | { | ||
187 | } | ||
188 | |||
189 | public string Name | ||
190 | { | ||
191 | get { return "Meta7WindlightModule"; } | ||
192 | } | ||
193 | |||
194 | public bool IsSharedModule | ||
195 | { | ||
196 | get { return false; } | ||
197 | } | ||
198 | |||
199 | #endregion | ||
200 | |||
201 | #region events | ||
202 | |||
203 | #endregion | ||
204 | |||
205 | #region ICommandableModule Members | ||
206 | |||
207 | private void InstallCommands() | ||
208 | { | ||
209 | Command wlload = new Command("load", CommandIntentions.COMMAND_NON_HAZARDOUS, HandleLoad, "Load windlight profile from the database and broadcast"); | ||
210 | Command wlenable = new Command("enable", CommandIntentions.COMMAND_NON_HAZARDOUS, HandleEnable, "Enable the windlight plugin"); | ||
211 | Command wldisable = new Command("disable", CommandIntentions.COMMAND_NON_HAZARDOUS, HandleDisable, "Enable the windlight plugin"); | ||
212 | |||
213 | m_commander.RegisterCommand("load", wlload); | ||
214 | m_commander.RegisterCommand("enable", wlenable); | ||
215 | m_commander.RegisterCommand("disable", wldisable); | ||
216 | |||
217 | m_scene.RegisterModuleCommander(m_commander); | ||
218 | } | ||
219 | |||
220 | private void HandleLoad(Object[] args) | ||
221 | { | ||
222 | if (!m_enableWindlight) | ||
223 | { | ||
224 | m_log.InfoFormat("[WINDLIGHT]: Cannot load windlight profile, module disabled. Use 'windlight enable' first."); | ||
225 | } | ||
226 | else | ||
227 | { | ||
228 | m_log.InfoFormat("[WINDLIGHT]: Loading Windlight profile from database"); | ||
229 | m_scene.LoadWindlightProfile(); | ||
230 | m_log.InfoFormat("[WINDLIGHT]: Load complete"); | ||
231 | } | ||
232 | } | ||
233 | |||
234 | private void HandleDisable(Object[] args) | ||
235 | { | ||
236 | m_log.InfoFormat("[WINDLIGHT]: Plugin now disabled"); | ||
237 | m_enableWindlight=false; | ||
238 | } | ||
239 | |||
240 | private void HandleEnable(Object[] args) | ||
241 | { | ||
242 | m_log.InfoFormat("[WINDLIGHT]: Plugin now enabled"); | ||
243 | m_enableWindlight = true; | ||
244 | } | ||
245 | |||
246 | /// <summary> | ||
247 | /// Processes commandline input. Do not call directly. | ||
248 | /// </summary> | ||
249 | /// <param name="args">Commandline arguments</param> | ||
250 | private void EventManager_OnPluginConsole(string[] args) | ||
251 | { | ||
252 | if (args[0] == "windlight") | ||
253 | { | ||
254 | if (args.Length == 1) | ||
255 | { | ||
256 | m_commander.ProcessConsoleCommand("add", new string[0]); | ||
257 | return; | ||
258 | } | ||
259 | |||
260 | string[] tmpArgs = new string[args.Length - 2]; | ||
261 | int i; | ||
262 | for (i = 2; i < args.Length; i++) | ||
263 | { | ||
264 | tmpArgs[i - 2] = args[i]; | ||
265 | } | ||
266 | |||
267 | m_commander.ProcessConsoleCommand(args[1], tmpArgs); | ||
268 | } | ||
269 | } | ||
270 | #endregion | ||
271 | |||
272 | } | ||
273 | } | ||
274 | |||
diff --git a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs index 1dfa1b1..fd97eaa 100644 --- a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs +++ b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs | |||
@@ -453,7 +453,7 @@ namespace OpenSim.Region.Examples.SimpleModule | |||
453 | 453 | ||
454 | } | 454 | } |
455 | 455 | ||
456 | public void SendGenericMessage(string method, List<string> message) | 456 | public void SendGenericMessage(string method, List<byte[]> message) |
457 | { | 457 | { |
458 | 458 | ||
459 | } | 459 | } |
diff --git a/OpenSim/Region/Framework/Interfaces/IRegionDataStore.cs b/OpenSim/Region/Framework/Interfaces/IRegionDataStore.cs index 78bd622..7312799 100644 --- a/OpenSim/Region/Framework/Interfaces/IRegionDataStore.cs +++ b/OpenSim/Region/Framework/Interfaces/IRegionDataStore.cs | |||
@@ -103,6 +103,8 @@ namespace OpenSim.Region.Framework.Interfaces | |||
103 | 103 | ||
104 | void StoreRegionSettings(RegionSettings rs); | 104 | void StoreRegionSettings(RegionSettings rs); |
105 | RegionSettings LoadRegionSettings(UUID regionUUID); | 105 | RegionSettings LoadRegionSettings(UUID regionUUID); |
106 | RegionMeta7WindlightData LoadRegionWindlightSettings(UUID regionUUID); | ||
107 | void StoreRegionWindlightSettings(RegionMeta7WindlightData wl); | ||
106 | 108 | ||
107 | void Shutdown(); | 109 | void Shutdown(); |
108 | } | 110 | } |
diff --git a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs index fd526eb..e98f0e7 100644 --- a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs +++ b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs | |||
@@ -53,8 +53,8 @@ namespace OpenSim.Region.Framework.Scenes.Animation | |||
53 | { | 53 | { |
54 | get { return m_movementAnimation; } | 54 | get { return m_movementAnimation; } |
55 | } | 55 | } |
56 | protected string m_movementAnimation = "DEFAULT"; | 56 | // protected string m_movementAnimation = "DEFAULT"; //KF: 'DEFAULT' does not exist! |
57 | 57 | protected string m_movementAnimation = "CROUCH"; //KF: CROUCH ensures reliable Av Anim. init. | |
58 | private int m_animTickFall; | 58 | private int m_animTickFall; |
59 | private int m_animTickJump; | 59 | private int m_animTickJump; |
60 | 60 | ||
@@ -123,17 +123,22 @@ namespace OpenSim.Region.Framework.Scenes.Animation | |||
123 | /// </summary> | 123 | /// </summary> |
124 | public void TrySetMovementAnimation(string anim) | 124 | public void TrySetMovementAnimation(string anim) |
125 | { | 125 | { |
126 | //m_log.DebugFormat("Updating movement animation to {0}", anim); | 126 | //Console.WriteLine("Updating movement animation to {0}", anim); |
127 | 127 | ||
128 | if (!m_scenePresence.IsChildAgent) | 128 | if (!m_scenePresence.IsChildAgent) |
129 | { | 129 | { |
130 | if (m_animations.TrySetDefaultAnimation( | 130 | if (m_animations.TrySetDefaultAnimation( |
131 | anim, m_scenePresence.ControllingClient.NextAnimationSequenceNumber, m_scenePresence.UUID)) | 131 | anim, m_scenePresence.ControllingClient.NextAnimationSequenceNumber, m_scenePresence.UUID)) |
132 | { | 132 | { |
133 | //Console.WriteLine("TSMA {0} success.", anim); | ||
133 | // 16384 is CHANGED_ANIMATION | 134 | // 16384 is CHANGED_ANIMATION |
134 | m_scenePresence.SendScriptEventToAttachments("changed", new Object[] { 16384 }); | 135 | m_scenePresence.SendScriptEventToAttachments("changed", new Object[] { 16384 }); |
135 | SendAnimPack(); | 136 | SendAnimPack(); |
136 | } | 137 | } |
138 | else | ||
139 | { | ||
140 | //Console.WriteLine("TSMA {0} fail.", anim); | ||
141 | } | ||
137 | } | 142 | } |
138 | } | 143 | } |
139 | 144 | ||
@@ -146,10 +151,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation | |||
146 | const float PREJUMP_DELAY = 0.25f; | 151 | const float PREJUMP_DELAY = 0.25f; |
147 | 152 | ||
148 | #region Inputs | 153 | #region Inputs |
149 | if (m_scenePresence.SitGround) | 154 | |
150 | { | ||
151 | return "SIT_GROUND_CONSTRAINED"; | ||
152 | } | ||
153 | AgentManager.ControlFlags controlFlags = (AgentManager.ControlFlags)m_scenePresence.AgentControlFlags; | 155 | AgentManager.ControlFlags controlFlags = (AgentManager.ControlFlags)m_scenePresence.AgentControlFlags; |
154 | PhysicsActor actor = m_scenePresence.PhysicsActor; | 156 | PhysicsActor actor = m_scenePresence.PhysicsActor; |
155 | 157 | ||
@@ -159,11 +161,10 @@ namespace OpenSim.Region.Framework.Scenes.Animation | |||
159 | Vector3 left = Vector3.Transform(Vector3.UnitY, rotMatrix); | 161 | Vector3 left = Vector3.Transform(Vector3.UnitY, rotMatrix); |
160 | 162 | ||
161 | // Check control flags | 163 | // Check control flags |
162 | bool heldForward = | 164 | bool heldForward = ((controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_AT_POS) == AgentManager.ControlFlags.AGENT_CONTROL_AT_POS || (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_POS) == AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_POS); |
163 | (((controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_AT_POS) == AgentManager.ControlFlags.AGENT_CONTROL_AT_POS) || ((controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_POS) == AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_POS)); | 165 | bool heldBack = ((controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG) == AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG || (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_NEG) == AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_NEG); |
164 | bool heldBack = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG) == AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG; | 166 | bool heldLeft = ((controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS) == AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS || (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_POS) == AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_POS); |
165 | bool heldLeft = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS) == AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS; | 167 | bool heldRight = ((controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG) == AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG || (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_NEG) == AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_NEG); |
166 | bool heldRight = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG) == AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG; | ||
167 | //bool heldTurnLeft = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT) == AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT; | 168 | //bool heldTurnLeft = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT) == AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT; |
168 | //bool heldTurnRight = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT) == AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT; | 169 | //bool heldTurnRight = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT) == AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT; |
169 | bool heldUp = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) == AgentManager.ControlFlags.AGENT_CONTROL_UP_POS; | 170 | bool heldUp = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) == AgentManager.ControlFlags.AGENT_CONTROL_UP_POS; |
@@ -316,7 +317,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation | |||
316 | public void UpdateMovementAnimations() | 317 | public void UpdateMovementAnimations() |
317 | { | 318 | { |
318 | m_movementAnimation = GetMovementAnimation(); | 319 | m_movementAnimation = GetMovementAnimation(); |
319 | 320 | //Console.WriteLine("UMA got {0}", m_movementAnimation); | |
320 | if (m_movementAnimation == "PREJUMP" && !m_scenePresence.Scene.m_usePreJump) | 321 | if (m_movementAnimation == "PREJUMP" && !m_scenePresence.Scene.m_usePreJump) |
321 | { | 322 | { |
322 | // This was the previous behavior before PREJUMP | 323 | // This was the previous behavior before PREJUMP |
@@ -454,4 +455,4 @@ namespace OpenSim.Region.Framework.Scenes.Animation | |||
454 | m_scenePresence = null; | 455 | m_scenePresence = null; |
455 | } | 456 | } |
456 | } | 457 | } |
457 | } \ No newline at end of file | 458 | } |
diff --git a/OpenSim/Region/Framework/Scenes/EntityManager.cs b/OpenSim/Region/Framework/Scenes/EntityManager.cs index 099fcce..c246e32 100644 --- a/OpenSim/Region/Framework/Scenes/EntityManager.cs +++ b/OpenSim/Region/Framework/Scenes/EntityManager.cs | |||
@@ -40,7 +40,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
40 | private readonly Dictionary<UUID,EntityBase> m_eb_uuid = new Dictionary<UUID, EntityBase>(); | 40 | private readonly Dictionary<UUID,EntityBase> m_eb_uuid = new Dictionary<UUID, EntityBase>(); |
41 | private readonly Dictionary<uint, EntityBase> m_eb_localID = new Dictionary<uint, EntityBase>(); | 41 | private readonly Dictionary<uint, EntityBase> m_eb_localID = new Dictionary<uint, EntityBase>(); |
42 | //private readonly Dictionary<UUID, ScenePresence> m_pres_uuid = new Dictionary<UUID, ScenePresence>(); | 42 | //private readonly Dictionary<UUID, ScenePresence> m_pres_uuid = new Dictionary<UUID, ScenePresence>(); |
43 | private readonly Object m_lock = new Object(); | 43 | private System.Threading.ReaderWriterLockSlim m_lock = new System.Threading.ReaderWriterLockSlim(); |
44 | 44 | ||
45 | [Obsolete("Use Add() instead.")] | 45 | [Obsolete("Use Add() instead.")] |
46 | public void Add(UUID id, EntityBase eb) | 46 | public void Add(UUID id, EntityBase eb) |
@@ -50,7 +50,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
50 | 50 | ||
51 | public void Add(EntityBase entity) | 51 | public void Add(EntityBase entity) |
52 | { | 52 | { |
53 | lock (m_lock) | 53 | m_lock.EnterWriteLock(); |
54 | try | ||
54 | { | 55 | { |
55 | try | 56 | try |
56 | { | 57 | { |
@@ -62,11 +63,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
62 | m_log.ErrorFormat("Add Entity failed: {0}", e.Message); | 63 | m_log.ErrorFormat("Add Entity failed: {0}", e.Message); |
63 | } | 64 | } |
64 | } | 65 | } |
66 | finally | ||
67 | { | ||
68 | m_lock.ExitWriteLock(); | ||
69 | } | ||
65 | } | 70 | } |
66 | 71 | ||
67 | public void InsertOrReplace(EntityBase entity) | 72 | public void InsertOrReplace(EntityBase entity) |
68 | { | 73 | { |
69 | lock (m_lock) | 74 | m_lock.EnterWriteLock(); |
75 | try | ||
70 | { | 76 | { |
71 | try | 77 | try |
72 | { | 78 | { |
@@ -78,15 +84,24 @@ namespace OpenSim.Region.Framework.Scenes | |||
78 | m_log.ErrorFormat("Insert or Replace Entity failed: {0}", e.Message); | 84 | m_log.ErrorFormat("Insert or Replace Entity failed: {0}", e.Message); |
79 | } | 85 | } |
80 | } | 86 | } |
87 | finally | ||
88 | { | ||
89 | m_lock.ExitWriteLock(); | ||
90 | } | ||
81 | } | 91 | } |
82 | 92 | ||
83 | public void Clear() | 93 | public void Clear() |
84 | { | 94 | { |
85 | lock (m_lock) | 95 | m_lock.EnterWriteLock(); |
96 | try | ||
86 | { | 97 | { |
87 | m_eb_uuid.Clear(); | 98 | m_eb_uuid.Clear(); |
88 | m_eb_localID.Clear(); | 99 | m_eb_localID.Clear(); |
89 | } | 100 | } |
101 | finally | ||
102 | { | ||
103 | m_lock.ExitWriteLock(); | ||
104 | } | ||
90 | } | 105 | } |
91 | 106 | ||
92 | public int Count | 107 | public int Count |
@@ -123,7 +138,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
123 | 138 | ||
124 | public bool Remove(uint localID) | 139 | public bool Remove(uint localID) |
125 | { | 140 | { |
126 | lock (m_lock) | 141 | m_lock.EnterWriteLock(); |
142 | try | ||
127 | { | 143 | { |
128 | try | 144 | try |
129 | { | 145 | { |
@@ -141,11 +157,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
141 | return false; | 157 | return false; |
142 | } | 158 | } |
143 | } | 159 | } |
160 | finally | ||
161 | { | ||
162 | m_lock.ExitWriteLock(); | ||
163 | } | ||
144 | } | 164 | } |
145 | 165 | ||
146 | public bool Remove(UUID id) | 166 | public bool Remove(UUID id) |
147 | { | 167 | { |
148 | lock (m_lock) | 168 | m_lock.EnterWriteLock(); |
169 | try | ||
149 | { | 170 | { |
150 | try | 171 | try |
151 | { | 172 | { |
@@ -163,13 +184,18 @@ namespace OpenSim.Region.Framework.Scenes | |||
163 | return false; | 184 | return false; |
164 | } | 185 | } |
165 | } | 186 | } |
187 | finally | ||
188 | { | ||
189 | m_lock.ExitWriteLock(); | ||
190 | } | ||
166 | } | 191 | } |
167 | 192 | ||
168 | public List<EntityBase> GetAllByType<T>() | 193 | public List<EntityBase> GetAllByType<T>() |
169 | { | 194 | { |
170 | List<EntityBase> tmp = new List<EntityBase>(); | 195 | List<EntityBase> tmp = new List<EntityBase>(); |
171 | 196 | ||
172 | lock (m_lock) | 197 | m_lock.EnterReadLock(); |
198 | try | ||
173 | { | 199 | { |
174 | try | 200 | try |
175 | { | 201 | { |
@@ -187,23 +213,33 @@ namespace OpenSim.Region.Framework.Scenes | |||
187 | tmp = null; | 213 | tmp = null; |
188 | } | 214 | } |
189 | } | 215 | } |
216 | finally | ||
217 | { | ||
218 | m_lock.ExitReadLock(); | ||
219 | } | ||
190 | 220 | ||
191 | return tmp; | 221 | return tmp; |
192 | } | 222 | } |
193 | 223 | ||
194 | public List<EntityBase> GetEntities() | 224 | public List<EntityBase> GetEntities() |
195 | { | 225 | { |
196 | lock (m_lock) | 226 | m_lock.EnterReadLock(); |
227 | try | ||
197 | { | 228 | { |
198 | return new List<EntityBase>(m_eb_uuid.Values); | 229 | return new List<EntityBase>(m_eb_uuid.Values); |
199 | } | 230 | } |
231 | finally | ||
232 | { | ||
233 | m_lock.ExitReadLock(); | ||
234 | } | ||
200 | } | 235 | } |
201 | 236 | ||
202 | public EntityBase this[UUID id] | 237 | public EntityBase this[UUID id] |
203 | { | 238 | { |
204 | get | 239 | get |
205 | { | 240 | { |
206 | lock (m_lock) | 241 | m_lock.EnterReadLock(); |
242 | try | ||
207 | { | 243 | { |
208 | EntityBase entity; | 244 | EntityBase entity; |
209 | if (m_eb_uuid.TryGetValue(id, out entity)) | 245 | if (m_eb_uuid.TryGetValue(id, out entity)) |
@@ -211,6 +247,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
211 | else | 247 | else |
212 | return null; | 248 | return null; |
213 | } | 249 | } |
250 | finally | ||
251 | { | ||
252 | m_lock.ExitReadLock(); | ||
253 | } | ||
214 | } | 254 | } |
215 | set | 255 | set |
216 | { | 256 | { |
@@ -222,7 +262,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
222 | { | 262 | { |
223 | get | 263 | get |
224 | { | 264 | { |
225 | lock (m_lock) | 265 | m_lock.EnterReadLock(); |
266 | try | ||
226 | { | 267 | { |
227 | EntityBase entity; | 268 | EntityBase entity; |
228 | if (m_eb_localID.TryGetValue(localID, out entity)) | 269 | if (m_eb_localID.TryGetValue(localID, out entity)) |
@@ -230,6 +271,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
230 | else | 271 | else |
231 | return null; | 272 | return null; |
232 | } | 273 | } |
274 | finally | ||
275 | { | ||
276 | m_lock.ExitReadLock(); | ||
277 | } | ||
233 | } | 278 | } |
234 | set | 279 | set |
235 | { | 280 | { |
@@ -239,18 +284,28 @@ namespace OpenSim.Region.Framework.Scenes | |||
239 | 284 | ||
240 | public bool TryGetValue(UUID key, out EntityBase obj) | 285 | public bool TryGetValue(UUID key, out EntityBase obj) |
241 | { | 286 | { |
242 | lock (m_lock) | 287 | m_lock.EnterReadLock(); |
288 | try | ||
243 | { | 289 | { |
244 | return m_eb_uuid.TryGetValue(key, out obj); | 290 | return m_eb_uuid.TryGetValue(key, out obj); |
245 | } | 291 | } |
292 | finally | ||
293 | { | ||
294 | m_lock.ExitReadLock(); | ||
295 | } | ||
246 | } | 296 | } |
247 | 297 | ||
248 | public bool TryGetValue(uint key, out EntityBase obj) | 298 | public bool TryGetValue(uint key, out EntityBase obj) |
249 | { | 299 | { |
250 | lock (m_lock) | 300 | m_lock.EnterReadLock(); |
301 | try | ||
251 | { | 302 | { |
252 | return m_eb_localID.TryGetValue(key, out obj); | 303 | return m_eb_localID.TryGetValue(key, out obj); |
253 | } | 304 | } |
305 | finally | ||
306 | { | ||
307 | m_lock.ExitReadLock(); | ||
308 | } | ||
254 | } | 309 | } |
255 | 310 | ||
256 | /// <summary> | 311 | /// <summary> |
diff --git a/OpenSim/Region/Framework/Scenes/EventManager.cs b/OpenSim/Region/Framework/Scenes/EventManager.cs index 753344d..68e73b1 100644 --- a/OpenSim/Region/Framework/Scenes/EventManager.cs +++ b/OpenSim/Region/Framework/Scenes/EventManager.cs | |||
@@ -193,7 +193,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
193 | public event OnMakeChildAgentDelegate OnMakeChildAgent; | 193 | public event OnMakeChildAgentDelegate OnMakeChildAgent; |
194 | 194 | ||
195 | public delegate void OnMakeRootAgentDelegate(ScenePresence presence); | 195 | public delegate void OnMakeRootAgentDelegate(ScenePresence presence); |
196 | public delegate void OnSaveNewWindlightProfileDelegate(); | ||
197 | public delegate void OnSendNewWindlightProfileTargetedDelegate(RegionMeta7WindlightData wl, UUID user); | ||
196 | public event OnMakeRootAgentDelegate OnMakeRootAgent; | 198 | public event OnMakeRootAgentDelegate OnMakeRootAgent; |
199 | public event OnSendNewWindlightProfileTargetedDelegate OnSendNewWindlightProfileTargeted; | ||
200 | public event OnSaveNewWindlightProfileDelegate OnSaveNewWindlightProfile; | ||
197 | 201 | ||
198 | public delegate void NewInventoryItemUploadComplete(UUID avatarID, UUID assetID, string name, int userlevel); | 202 | public delegate void NewInventoryItemUploadComplete(UUID avatarID, UUID assetID, string name, int userlevel); |
199 | 203 | ||
@@ -411,6 +415,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
411 | private IncomingInstantMessage handlerUnhandledInstantMessage = null; //OnUnhandledInstantMessage; | 415 | private IncomingInstantMessage handlerUnhandledInstantMessage = null; //OnUnhandledInstantMessage; |
412 | private ClientClosed handlerClientClosed = null; //OnClientClosed; | 416 | private ClientClosed handlerClientClosed = null; //OnClientClosed; |
413 | private OnMakeChildAgentDelegate handlerMakeChildAgent = null; //OnMakeChildAgent; | 417 | private OnMakeChildAgentDelegate handlerMakeChildAgent = null; //OnMakeChildAgent; |
418 | private OnSaveNewWindlightProfileDelegate handlerSaveNewWindlightProfile = null; //OnSaveNewWindlightProfile; | ||
419 | private OnSendNewWindlightProfileTargetedDelegate handlerSendNewWindlightProfileTargeted = null; //OnSendNewWindlightProfileTargeted; | ||
414 | private OnMakeRootAgentDelegate handlerMakeRootAgent = null; //OnMakeRootAgent; | 420 | private OnMakeRootAgentDelegate handlerMakeRootAgent = null; //OnMakeRootAgent; |
415 | private OnTerrainTickDelegate handlerTerrainTick = null; // OnTerainTick; | 421 | private OnTerrainTickDelegate handlerTerrainTick = null; // OnTerainTick; |
416 | private RegisterCapsEvent handlerRegisterCaps = null; // OnRegisterCaps; | 422 | private RegisterCapsEvent handlerRegisterCaps = null; // OnRegisterCaps; |
@@ -772,6 +778,24 @@ namespace OpenSim.Region.Framework.Scenes | |||
772 | } | 778 | } |
773 | } | 779 | } |
774 | 780 | ||
781 | public void TriggerOnSendNewWindlightProfileTargeted(RegionMeta7WindlightData wl, UUID user) | ||
782 | { | ||
783 | handlerSendNewWindlightProfileTargeted = OnSendNewWindlightProfileTargeted; | ||
784 | if (handlerSendNewWindlightProfileTargeted != null) | ||
785 | { | ||
786 | handlerSendNewWindlightProfileTargeted(wl, user); | ||
787 | } | ||
788 | } | ||
789 | |||
790 | public void TriggerOnSaveNewWindlightProfile() | ||
791 | { | ||
792 | handlerSaveNewWindlightProfile = OnSaveNewWindlightProfile; | ||
793 | if (handlerSaveNewWindlightProfile != null) | ||
794 | { | ||
795 | handlerSaveNewWindlightProfile(); | ||
796 | } | ||
797 | } | ||
798 | |||
775 | public void TriggerOnMakeRootAgent(ScenePresence presence) | 799 | public void TriggerOnMakeRootAgent(ScenePresence presence) |
776 | { | 800 | { |
777 | handlerMakeRootAgent = OnMakeRootAgent; | 801 | handlerMakeRootAgent = OnMakeRootAgent; |
diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index 3044017..18ec25f 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs | |||
@@ -846,8 +846,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
846 | public void RemoveTaskInventory(IClientAPI remoteClient, UUID itemID, uint localID) | 846 | public void RemoveTaskInventory(IClientAPI remoteClient, UUID itemID, uint localID) |
847 | { | 847 | { |
848 | SceneObjectPart part = GetSceneObjectPart(localID); | 848 | SceneObjectPart part = GetSceneObjectPart(localID); |
849 | SceneObjectGroup group = part.ParentGroup; | 849 | SceneObjectGroup group = null; |
850 | if (group != null) | 850 | if (part != null) |
851 | { | ||
852 | group = part.ParentGroup; | ||
853 | } | ||
854 | if (part != null && group != null) | ||
851 | { | 855 | { |
852 | TaskInventoryItem item = group.GetInventoryItem(localID, itemID); | 856 | TaskInventoryItem item = group.GetInventoryItem(localID, itemID); |
853 | if (item == null) | 857 | if (item == null) |
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 764ac60..adf5f02 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs | |||
@@ -539,6 +539,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
539 | 539 | ||
540 | // Load region settings | 540 | // Load region settings |
541 | m_regInfo.RegionSettings = m_storageManager.DataStore.LoadRegionSettings(m_regInfo.RegionID); | 541 | m_regInfo.RegionSettings = m_storageManager.DataStore.LoadRegionSettings(m_regInfo.RegionID); |
542 | m_regInfo.WindlightSettings = m_storageManager.DataStore.LoadRegionWindlightSettings(m_regInfo.RegionID); | ||
543 | |||
542 | if (m_storageManager.EstateDataStore != null) | 544 | if (m_storageManager.EstateDataStore != null) |
543 | { | 545 | { |
544 | m_regInfo.EstateSettings = m_storageManager.EstateDataStore.LoadEstateSettings(m_regInfo.RegionID); | 546 | m_regInfo.EstateSettings = m_storageManager.EstateDataStore.LoadEstateSettings(m_regInfo.RegionID); |
@@ -886,6 +888,15 @@ namespace OpenSim.Region.Framework.Scenes | |||
886 | /// <param name="seconds">float indicating duration before restart.</param> | 888 | /// <param name="seconds">float indicating duration before restart.</param> |
887 | public virtual void Restart(float seconds) | 889 | public virtual void Restart(float seconds) |
888 | { | 890 | { |
891 | Restart(seconds, true); | ||
892 | } | ||
893 | |||
894 | /// <summary> | ||
895 | /// Given float seconds, this will restart the region. showDialog will optionally alert the users. | ||
896 | /// </summary> | ||
897 | /// <param name="seconds">float indicating duration before restart.</param> | ||
898 | public virtual void Restart(float seconds, bool showDialog) | ||
899 | { | ||
889 | // notifications are done in 15 second increments | 900 | // notifications are done in 15 second increments |
890 | // so .. if the number of seconds is less then 15 seconds, it's not really a restart request | 901 | // so .. if the number of seconds is less then 15 seconds, it's not really a restart request |
891 | // It's a 'Cancel restart' request. | 902 | // It's a 'Cancel restart' request. |
@@ -906,8 +917,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
906 | m_restartTimer.Elapsed += new ElapsedEventHandler(RestartTimer_Elapsed); | 917 | m_restartTimer.Elapsed += new ElapsedEventHandler(RestartTimer_Elapsed); |
907 | m_log.Info("[REGION]: Restarting Region in " + (seconds / 60) + " minutes"); | 918 | m_log.Info("[REGION]: Restarting Region in " + (seconds / 60) + " minutes"); |
908 | m_restartTimer.Start(); | 919 | m_restartTimer.Start(); |
909 | m_dialogModule.SendNotificationToUsersInRegion( | 920 | if (showDialog) |
921 | { | ||
922 | m_dialogModule.SendNotificationToUsersInRegion( | ||
910 | UUID.Random(), String.Empty, RegionInfo.RegionName + String.Format(": Restarting in {0} Minutes", (int)(seconds / 60.0))); | 923 | UUID.Random(), String.Empty, RegionInfo.RegionName + String.Format(": Restarting in {0} Minutes", (int)(seconds / 60.0))); |
924 | } | ||
911 | } | 925 | } |
912 | } | 926 | } |
913 | 927 | ||
@@ -1189,16 +1203,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
1189 | // Check if any objects have reached their targets | 1203 | // Check if any objects have reached their targets |
1190 | CheckAtTargets(); | 1204 | CheckAtTargets(); |
1191 | 1205 | ||
1192 | // Update SceneObjectGroups that have scheduled themselves for updates | ||
1193 | // Objects queue their updates onto all scene presences | ||
1194 | if (m_frame % m_update_objects == 0) | ||
1195 | m_sceneGraph.UpdateObjectGroups(); | ||
1196 | |||
1197 | // Run through all ScenePresences looking for updates | 1206 | // Run through all ScenePresences looking for updates |
1198 | // Presence updates and queued object updates for each presence are sent to clients | 1207 | // Presence updates and queued object updates for each presence are sent to clients |
1199 | if (m_frame % m_update_presences == 0) | 1208 | if (m_frame % m_update_presences == 0) |
1200 | m_sceneGraph.UpdatePresences(); | 1209 | m_sceneGraph.UpdatePresences(); |
1201 | 1210 | ||
1211 | // Update SceneObjectGroups that have scheduled themselves for updates | ||
1212 | // Objects queue their updates onto all scene presences | ||
1213 | if (m_frame % m_update_objects == 0) | ||
1214 | m_sceneGraph.UpdateObjectGroups(); | ||
1215 | |||
1202 | int tmpPhysicsMS2 = Util.EnvironmentTickCount(); | 1216 | int tmpPhysicsMS2 = Util.EnvironmentTickCount(); |
1203 | if ((m_frame % m_update_physics == 0) && m_physics_enabled) | 1217 | if ((m_frame % m_update_physics == 0) && m_physics_enabled) |
1204 | m_sceneGraph.UpdatePreparePhysics(); | 1218 | m_sceneGraph.UpdatePreparePhysics(); |
@@ -1505,6 +1519,19 @@ namespace OpenSim.Region.Framework.Scenes | |||
1505 | public void SaveTerrain() | 1519 | public void SaveTerrain() |
1506 | { | 1520 | { |
1507 | m_storageManager.DataStore.StoreTerrain(Heightmap.GetDoubles(), RegionInfo.RegionID); | 1521 | m_storageManager.DataStore.StoreTerrain(Heightmap.GetDoubles(), RegionInfo.RegionID); |
1522 | } | ||
1523 | |||
1524 | public void StoreWindlightProfile(RegionMeta7WindlightData wl) | ||
1525 | { | ||
1526 | m_regInfo.WindlightSettings = wl; | ||
1527 | m_storageManager.DataStore.StoreRegionWindlightSettings(wl); | ||
1528 | m_eventManager.TriggerOnSaveNewWindlightProfile(); | ||
1529 | } | ||
1530 | |||
1531 | public void LoadWindlightProfile() | ||
1532 | { | ||
1533 | m_regInfo.WindlightSettings = m_storageManager.DataStore.LoadRegionWindlightSettings(RegionInfo.RegionID); | ||
1534 | m_eventManager.TriggerOnSaveNewWindlightProfile(); | ||
1508 | } | 1535 | } |
1509 | 1536 | ||
1510 | /// <summary> | 1537 | /// <summary> |
@@ -3387,6 +3414,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
3387 | 3414 | ||
3388 | CapsModule.AddCapsHandler(agent.AgentID); | 3415 | CapsModule.AddCapsHandler(agent.AgentID); |
3389 | 3416 | ||
3417 | if ((teleportFlags & ((uint)TeleportFlags.ViaLandmark | (uint)TeleportFlags.ViaLocation | (uint)TeleportFlags.ViaLandmark | (uint)TeleportFlags.Default)) != 0) | ||
3418 | System.Threading.Thread.Sleep(2000); | ||
3419 | |||
3390 | if (!agent.child) | 3420 | if (!agent.child) |
3391 | { | 3421 | { |
3392 | if (TestBorderCross(agent.startpos,Cardinals.E)) | 3422 | if (TestBorderCross(agent.startpos,Cardinals.E)) |
@@ -3445,6 +3475,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3445 | } | 3475 | } |
3446 | } | 3476 | } |
3447 | // Honor parcel landing type and position. | 3477 | // Honor parcel landing type and position. |
3478 | /* | ||
3448 | ILandObject land = LandChannel.GetLandObject(agent.startpos.X, agent.startpos.Y); | 3479 | ILandObject land = LandChannel.GetLandObject(agent.startpos.X, agent.startpos.Y); |
3449 | if (land != null) | 3480 | if (land != null) |
3450 | { | 3481 | { |
@@ -3453,6 +3484,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3453 | agent.startpos = land.LandData.UserLocation; | 3484 | agent.startpos = land.LandData.UserLocation; |
3454 | } | 3485 | } |
3455 | } | 3486 | } |
3487 | */// This is now handled properly in ScenePresence.MakeRootAgent | ||
3456 | } | 3488 | } |
3457 | 3489 | ||
3458 | m_authenticateHandler.AddNewCircuit(agent.circuitcode, agent); | 3490 | m_authenticateHandler.AddNewCircuit(agent.circuitcode, agent); |
diff --git a/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs b/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs index f49d072..8c808ab 100644 --- a/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs +++ b/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs | |||
@@ -706,17 +706,42 @@ namespace OpenSim.Region.Framework.Scenes | |||
706 | { | 706 | { |
707 | m_log.DebugFormat( | 707 | m_log.DebugFormat( |
708 | "[SCENE COMMUNICATION SERVICE]: RequestTeleportToLocation {0} within {1}", | 708 | "[SCENE COMMUNICATION SERVICE]: RequestTeleportToLocation {0} within {1}", |
709 | position, m_regionInfo.RegionName); | 709 | position, m_regionInfo.RegionName); |
710 | 710 | ||
711 | // Teleport within the same region | 711 | // Teleport within the same region |
712 | if (IsOutsideRegion(avatar.Scene, position) || position.Z < 0) | 712 | if (IsOutsideRegion(avatar.Scene, position) || position.Z < 0) |
713 | { | 713 | { |
714 | Vector3 emergencyPos = new Vector3(128, 128, 128); | 714 | Vector3 emergencyPos = new Vector3(128, 128, 128); |
715 | 715 | ||
716 | m_log.WarnFormat( | 716 | m_log.WarnFormat( |
717 | "[SCENE COMMUNICATION SERVICE]: RequestTeleportToLocation() was given an illegal position of {0} for avatar {1}, {2}. Substituting {3}", | 717 | "[SCENE COMMUNICATION SERVICE]: RequestTeleportToLocation() was given an illegal position of {0} for avatar {1}, {2}. Substituting {3}", |
718 | position, avatar.Name, avatar.UUID, emergencyPos); | 718 | position, avatar.Name, avatar.UUID, emergencyPos); |
719 | position = emergencyPos; | 719 | position = emergencyPos; |
720 | } | ||
721 | |||
722 | Vector3 currentPos = avatar.AbsolutePosition; | ||
723 | ILandObject srcLand = m_scene.LandChannel.GetLandObject(currentPos.X, currentPos.Y); | ||
724 | ILandObject destLand = m_scene.LandChannel.GetLandObject(position.X, position.Y); | ||
725 | if (srcLand != null && destLand != null && (teleportFlags & (uint)TeleportFlags.ViaLure) == 0 && (teleportFlags & (uint)TeleportFlags.ViaGodlikeLure) == 0) | ||
726 | { | ||
727 | if (srcLand.LandData.LocalID == destLand.LandData.LocalID) | ||
728 | { | ||
729 | //TPing within the same parcel. If the landing point is restricted, block the TP. | ||
730 | //Don't restrict gods, estate managers, or land owners to the TP point. This behaviour mimics agni. | ||
731 | if (destLand.LandData.LandingType == (byte)1 && destLand.LandData.UserLocation != Vector3.Zero && avatar.GodLevel < 200 && !m_scene.RegionInfo.EstateSettings.IsEstateManager(avatar.UUID) && destLand.LandData.OwnerID != avatar.UUID) | ||
732 | { | ||
733 | avatar.ControllingClient.SendAgentAlertMessage("Can't TP to the destination; landing point set.", false); | ||
734 | position = currentPos; | ||
735 | } | ||
736 | } | ||
737 | else | ||
738 | { | ||
739 | //Tping to a different parcel. Respect the landing point on the destination parcel. | ||
740 | if (destLand.LandData.LandingType == (byte)1 && destLand.LandData.UserLocation != Vector3.Zero && avatar.GodLevel < 200 && !m_scene.RegionInfo.EstateSettings.IsEstateManager(avatar.UUID) && destLand.LandData.OwnerID != avatar.UUID) | ||
741 | { | ||
742 | position = destLand.LandData.UserLocation; | ||
743 | } | ||
744 | } | ||
720 | } | 745 | } |
721 | 746 | ||
722 | // TODO: Get proper AVG Height | 747 | // TODO: Get proper AVG Height |
diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index f74fd5d..34a92fe 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs | |||
@@ -222,6 +222,30 @@ namespace OpenSim.Region.Framework.Scenes | |||
222 | protected internal bool AddRestoredSceneObject( | 222 | protected internal bool AddRestoredSceneObject( |
223 | SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted) | 223 | SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted) |
224 | { | 224 | { |
225 | // KF: Check for out-of-region, move inside and make static. | ||
226 | Vector3 npos = new Vector3(sceneObject.RootPart.GroupPosition.X, | ||
227 | sceneObject.RootPart.GroupPosition.Y, | ||
228 | sceneObject.RootPart.GroupPosition.Z); | ||
229 | if (!(((sceneObject.RootPart.Shape.PCode == (byte)PCode.Prim) && (sceneObject.RootPart.Shape.State != 0))) && (npos.X < 0.0 || npos.Y < 0.0 || npos.Z < 0.0 || | ||
230 | npos.X > Constants.RegionSize || | ||
231 | npos.Y > Constants.RegionSize)) | ||
232 | { | ||
233 | if (npos.X < 0.0) npos.X = 1.0f; | ||
234 | if (npos.Y < 0.0) npos.Y = 1.0f; | ||
235 | if (npos.Z < 0.0) npos.Z = 0.0f; | ||
236 | if (npos.X > Constants.RegionSize) npos.X = Constants.RegionSize - 1.0f; | ||
237 | if (npos.Y > Constants.RegionSize) npos.Y = Constants.RegionSize - 1.0f; | ||
238 | |||
239 | foreach (SceneObjectPart part in sceneObject.Children.Values) | ||
240 | { | ||
241 | part.GroupPosition = npos; | ||
242 | } | ||
243 | sceneObject.RootPart.Velocity = Vector3.Zero; | ||
244 | sceneObject.RootPart.AngularVelocity = Vector3.Zero; | ||
245 | sceneObject.RootPart.Acceleration = Vector3.Zero; | ||
246 | sceneObject.RootPart.Velocity = Vector3.Zero; | ||
247 | } | ||
248 | |||
225 | if (!alreadyPersisted) | 249 | if (!alreadyPersisted) |
226 | { | 250 | { |
227 | sceneObject.ForceInventoryPersistence(); | 251 | sceneObject.ForceInventoryPersistence(); |
@@ -542,6 +566,18 @@ namespace OpenSim.Region.Framework.Scenes | |||
542 | if (group.GetFromItemID() == itemID) | 566 | if (group.GetFromItemID() == itemID) |
543 | { | 567 | { |
544 | m_parentScene.SendAttachEvent(group.LocalId, itemID, UUID.Zero); | 568 | m_parentScene.SendAttachEvent(group.LocalId, itemID, UUID.Zero); |
569 | bool hasScripts = false; | ||
570 | foreach (SceneObjectPart part in group.Children.Values) | ||
571 | { | ||
572 | if (part.Inventory.ContainsScripts()) | ||
573 | { | ||
574 | hasScripts = true; | ||
575 | break; | ||
576 | } | ||
577 | } | ||
578 | |||
579 | if (hasScripts) // Allow the object to execute the attach(NULL_KEY) event | ||
580 | System.Threading.Thread.Sleep(100); | ||
545 | group.DetachToInventoryPrep(); | 581 | group.DetachToInventoryPrep(); |
546 | m_log.Debug("[DETACH]: Saving attachpoint: " + | 582 | m_log.Debug("[DETACH]: Saving attachpoint: " + |
547 | ((uint)group.GetAttachmentPoint()).ToString()); | 583 | ((uint)group.GetAttachmentPoint()).ToString()); |
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs index 5a06bdb..65ce13a 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs | |||
@@ -46,12 +46,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
46 | /// </summary> | 46 | /// </summary> |
47 | public void ForceInventoryPersistence() | 47 | public void ForceInventoryPersistence() |
48 | { | 48 | { |
49 | lock (m_parts) | 49 | lockPartsForRead(true); |
50 | List<SceneObjectPart> values = new List<SceneObjectPart>(m_parts.Values); | ||
51 | lockPartsForRead(false); | ||
52 | foreach (SceneObjectPart part in values) | ||
50 | { | 53 | { |
51 | foreach (SceneObjectPart part in m_parts.Values) | 54 | part.Inventory.ForceInventoryPersistence(); |
52 | { | ||
53 | part.Inventory.ForceInventoryPersistence(); | ||
54 | } | ||
55 | } | 55 | } |
56 | } | 56 | } |
57 | 57 | ||
@@ -75,14 +75,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
75 | /// Stop the scripts contained in all the prims in this group | 75 | /// Stop the scripts contained in all the prims in this group |
76 | /// </summary> | 76 | /// </summary> |
77 | public void RemoveScriptInstances() | 77 | public void RemoveScriptInstances() |
78 | { | 78 | { |
79 | lock (m_parts) | 79 | lockPartsForRead(true); |
80 | List<SceneObjectPart> values = new List<SceneObjectPart>(m_parts.Values); | ||
81 | lockPartsForRead(false); | ||
82 | |||
83 | foreach (SceneObjectPart part in values) | ||
80 | { | 84 | { |
81 | foreach (SceneObjectPart part in m_parts.Values) | 85 | part.Inventory.RemoveScriptInstances(); |
82 | { | ||
83 | part.Inventory.RemoveScriptInstances(); | ||
84 | } | ||
85 | } | 86 | } |
87 | |||
86 | } | 88 | } |
87 | 89 | ||
88 | /// <summary> | 90 | /// <summary> |
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 34d8b49..e63e8d9 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | |||
@@ -98,6 +98,72 @@ namespace OpenSim.Region.Framework.Scenes | |||
98 | private bool m_hasGroupChanged = false; | 98 | private bool m_hasGroupChanged = false; |
99 | private long timeFirstChanged; | 99 | private long timeFirstChanged; |
100 | private long timeLastChanged; | 100 | private long timeLastChanged; |
101 | private System.Threading.ReaderWriterLockSlim m_partsLock = new System.Threading.ReaderWriterLockSlim(); | ||
102 | |||
103 | public void lockPartsForRead(bool locked) | ||
104 | { | ||
105 | if (locked) | ||
106 | { | ||
107 | if (m_partsLock.RecursiveReadCount > 0) | ||
108 | { | ||
109 | m_log.Error("[SceneObjectGroup.m_parts] Recursive read lock requested. This should not happen and means something needs to be fixed. For now though, it's safe to continue."); | ||
110 | m_partsLock.ExitReadLock(); | ||
111 | } | ||
112 | if (m_partsLock.RecursiveWriteCount > 0) | ||
113 | { | ||
114 | m_log.Error("[SceneObjectGroup.m_parts] Recursive read lock requested. This should not happen and means something needs to be fixed."); | ||
115 | m_partsLock.ExitWriteLock(); | ||
116 | } | ||
117 | |||
118 | while (!m_partsLock.TryEnterReadLock(60000)) | ||
119 | { | ||
120 | m_log.Error("[SceneObjectGroup.m_parts] Thread lock detected while trying to aquire READ lock of m_parts in SceneObjectGroup. I'm going to try to solve the thread lock automatically to preserve region stability, but this needs to be fixed."); | ||
121 | if (m_partsLock.IsWriteLockHeld) | ||
122 | { | ||
123 | m_partsLock = new System.Threading.ReaderWriterLockSlim(); | ||
124 | } | ||
125 | } | ||
126 | } | ||
127 | else | ||
128 | { | ||
129 | if (m_partsLock.RecursiveReadCount > 0) | ||
130 | { | ||
131 | m_partsLock.ExitReadLock(); | ||
132 | } | ||
133 | } | ||
134 | } | ||
135 | public void lockPartsForWrite(bool locked) | ||
136 | { | ||
137 | if (locked) | ||
138 | { | ||
139 | if (m_partsLock.RecursiveReadCount > 0) | ||
140 | { | ||
141 | m_log.Error("[SceneObjectGroup.m_parts] Recursive write lock requested. This should not happen and means something needs to be fixed. For now though, it's safe to continue."); | ||
142 | m_partsLock.ExitReadLock(); | ||
143 | } | ||
144 | if (m_partsLock.RecursiveWriteCount > 0) | ||
145 | { | ||
146 | m_log.Error("[SceneObjectGroup.m_parts] Recursive write lock requested. This should not happen and means something needs to be fixed."); | ||
147 | m_partsLock.ExitWriteLock(); | ||
148 | } | ||
149 | |||
150 | while (!m_partsLock.TryEnterWriteLock(60000)) | ||
151 | { | ||
152 | m_log.Error("[SceneObjectGroup.m_parts] Thread lock detected while trying to aquire WRITE lock of m_scripts in XEngine. I'm going to try to solve the thread lock automatically to preserve region stability, but this needs to be fixed."); | ||
153 | if (m_partsLock.IsWriteLockHeld) | ||
154 | { | ||
155 | m_partsLock = new System.Threading.ReaderWriterLockSlim(); | ||
156 | } | ||
157 | } | ||
158 | } | ||
159 | else | ||
160 | { | ||
161 | if (m_partsLock.RecursiveWriteCount > 0) | ||
162 | { | ||
163 | m_partsLock.ExitWriteLock(); | ||
164 | } | ||
165 | } | ||
166 | } | ||
101 | 167 | ||
102 | public bool HasGroupChanged | 168 | public bool HasGroupChanged |
103 | { | 169 | { |
@@ -243,13 +309,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
243 | set | 309 | set |
244 | { | 310 | { |
245 | m_regionHandle = value; | 311 | m_regionHandle = value; |
246 | lock (m_parts) | 312 | lockPartsForRead(true); |
247 | { | 313 | { |
248 | foreach (SceneObjectPart part in m_parts.Values) | 314 | foreach (SceneObjectPart part in m_parts.Values) |
249 | { | 315 | { |
316 | |||
250 | part.RegionHandle = m_regionHandle; | 317 | part.RegionHandle = m_regionHandle; |
318 | |||
251 | } | 319 | } |
252 | } | 320 | } |
321 | lockPartsForRead(false); | ||
253 | } | 322 | } |
254 | } | 323 | } |
255 | 324 | ||
@@ -275,13 +344,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
275 | m_scene.CrossPrimGroupIntoNewRegion(val, this, true); | 344 | m_scene.CrossPrimGroupIntoNewRegion(val, this, true); |
276 | } | 345 | } |
277 | 346 | ||
278 | lock (m_parts) | 347 | lockPartsForRead(true); |
279 | { | 348 | { |
280 | foreach (SceneObjectPart part in m_parts.Values) | 349 | foreach (SceneObjectPart part in m_parts.Values) |
281 | { | 350 | { |
351 | |||
282 | part.GroupPosition = val; | 352 | part.GroupPosition = val; |
353 | |||
283 | } | 354 | } |
284 | } | 355 | } |
356 | lockPartsForRead(false); | ||
285 | 357 | ||
286 | //if (m_rootPart.PhysActor != null) | 358 | //if (m_rootPart.PhysActor != null) |
287 | //{ | 359 | //{ |
@@ -443,13 +515,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
443 | 515 | ||
444 | public void SetFromItemID(UUID AssetId) | 516 | public void SetFromItemID(UUID AssetId) |
445 | { | 517 | { |
446 | lock (m_parts) | 518 | lockPartsForRead(true); |
447 | { | 519 | { |
448 | foreach (SceneObjectPart part in m_parts.Values) | 520 | foreach (SceneObjectPart part in m_parts.Values) |
449 | { | 521 | { |
522 | |||
450 | part.FromItemID = AssetId; | 523 | part.FromItemID = AssetId; |
524 | |||
451 | } | 525 | } |
452 | } | 526 | } |
527 | lockPartsForRead(false); | ||
453 | } | 528 | } |
454 | 529 | ||
455 | public UUID GetFromItemID() | 530 | public UUID GetFromItemID() |
@@ -516,10 +591,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
516 | Vector3 maxScale = Vector3.Zero; | 591 | Vector3 maxScale = Vector3.Zero; |
517 | Vector3 finalScale = new Vector3(0.5f, 0.5f, 0.5f); | 592 | Vector3 finalScale = new Vector3(0.5f, 0.5f, 0.5f); |
518 | 593 | ||
519 | lock (m_parts) | 594 | lockPartsForRead(true); |
520 | { | 595 | { |
521 | foreach (SceneObjectPart part in m_parts.Values) | 596 | foreach (SceneObjectPart part in m_parts.Values) |
522 | { | 597 | { |
598 | |||
523 | Vector3 partscale = part.Scale; | 599 | Vector3 partscale = part.Scale; |
524 | Vector3 partoffset = part.OffsetPosition; | 600 | Vector3 partoffset = part.OffsetPosition; |
525 | 601 | ||
@@ -530,8 +606,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
530 | maxScale.X = (partscale.X + partoffset.X > maxScale.X) ? partscale.X + partoffset.X : maxScale.X; | 606 | maxScale.X = (partscale.X + partoffset.X > maxScale.X) ? partscale.X + partoffset.X : maxScale.X; |
531 | maxScale.Y = (partscale.Y + partoffset.Y > maxScale.Y) ? partscale.Y + partoffset.Y : maxScale.Y; | 607 | maxScale.Y = (partscale.Y + partoffset.Y > maxScale.Y) ? partscale.Y + partoffset.Y : maxScale.Y; |
532 | maxScale.Z = (partscale.Z + partoffset.Z > maxScale.Z) ? partscale.Z + partoffset.Z : maxScale.Z; | 608 | maxScale.Z = (partscale.Z + partoffset.Z > maxScale.Z) ? partscale.Z + partoffset.Z : maxScale.Z; |
609 | |||
533 | } | 610 | } |
534 | } | 611 | } |
612 | lockPartsForRead(false); | ||
613 | |||
535 | finalScale.X = (minScale.X > maxScale.X) ? minScale.X : maxScale.X; | 614 | finalScale.X = (minScale.X > maxScale.X) ? minScale.X : maxScale.X; |
536 | finalScale.Y = (minScale.Y > maxScale.Y) ? minScale.Y : maxScale.Y; | 615 | finalScale.Y = (minScale.Y > maxScale.Y) ? minScale.Y : maxScale.Y; |
537 | finalScale.Z = (minScale.Z > maxScale.Z) ? minScale.Z : maxScale.Z; | 616 | finalScale.Z = (minScale.Z > maxScale.Z) ? minScale.Z : maxScale.Z; |
@@ -547,10 +626,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
547 | 626 | ||
548 | EntityIntersection result = new EntityIntersection(); | 627 | EntityIntersection result = new EntityIntersection(); |
549 | 628 | ||
550 | lock (m_parts) | 629 | lockPartsForRead(true); |
551 | { | 630 | { |
552 | foreach (SceneObjectPart part in m_parts.Values) | 631 | foreach (SceneObjectPart part in m_parts.Values) |
553 | { | 632 | { |
633 | |||
554 | // Temporary commented to stop compiler warning | 634 | // Temporary commented to stop compiler warning |
555 | //Vector3 partPosition = | 635 | //Vector3 partPosition = |
556 | // new Vector3(part.AbsolutePosition.X, part.AbsolutePosition.Y, part.AbsolutePosition.Z); | 636 | // new Vector3(part.AbsolutePosition.X, part.AbsolutePosition.Y, part.AbsolutePosition.Z); |
@@ -578,8 +658,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
578 | result.distance = inter.distance; | 658 | result.distance = inter.distance; |
579 | } | 659 | } |
580 | } | 660 | } |
661 | |||
581 | } | 662 | } |
582 | } | 663 | } |
664 | lockPartsForRead(false); | ||
583 | return result; | 665 | return result; |
584 | } | 666 | } |
585 | 667 | ||
@@ -592,10 +674,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
592 | public Vector3 GetAxisAlignedBoundingBox(out float offsetHeight) | 674 | public Vector3 GetAxisAlignedBoundingBox(out float offsetHeight) |
593 | { | 675 | { |
594 | float maxX = -256f, maxY = -256f, maxZ = -256f, minX = 256f, minY = 256f, minZ = 256f; | 676 | float maxX = -256f, maxY = -256f, maxZ = -256f, minX = 256f, minY = 256f, minZ = 256f; |
595 | lock (m_parts) | 677 | lockPartsForRead(true); |
596 | { | 678 | { |
597 | foreach (SceneObjectPart part in m_parts.Values) | 679 | foreach (SceneObjectPart part in m_parts.Values) |
598 | { | 680 | { |
681 | |||
599 | Vector3 worldPos = part.GetWorldPosition(); | 682 | Vector3 worldPos = part.GetWorldPosition(); |
600 | Vector3 offset = worldPos - AbsolutePosition; | 683 | Vector3 offset = worldPos - AbsolutePosition; |
601 | Quaternion worldRot; | 684 | Quaternion worldRot; |
@@ -654,6 +737,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
654 | backBottomRight.Y = orig.Y + (part.Scale.Y / 2); | 737 | backBottomRight.Y = orig.Y + (part.Scale.Y / 2); |
655 | backBottomRight.Z = orig.Z - (part.Scale.Z / 2); | 738 | backBottomRight.Z = orig.Z - (part.Scale.Z / 2); |
656 | 739 | ||
740 | |||
741 | |||
657 | //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z); | 742 | //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z); |
658 | //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z); | 743 | //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z); |
659 | //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z); | 744 | //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z); |
@@ -825,6 +910,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
825 | minZ = backBottomLeft.Z; | 910 | minZ = backBottomLeft.Z; |
826 | } | 911 | } |
827 | } | 912 | } |
913 | lockPartsForRead(false); | ||
828 | 914 | ||
829 | Vector3 boundingBox = new Vector3(maxX - minX, maxY - minY, maxZ - minZ); | 915 | Vector3 boundingBox = new Vector3(maxX - minX, maxY - minY, maxZ - minZ); |
830 | 916 | ||
@@ -853,17 +939,20 @@ namespace OpenSim.Region.Framework.Scenes | |||
853 | Dictionary<UUID,string> states = new Dictionary<UUID,string>(); | 939 | Dictionary<UUID,string> states = new Dictionary<UUID,string>(); |
854 | 940 | ||
855 | // Capture script state while holding the lock | 941 | // Capture script state while holding the lock |
856 | lock (m_parts) | 942 | lockPartsForRead(true); |
857 | { | 943 | { |
858 | foreach (SceneObjectPart part in m_parts.Values) | 944 | foreach (SceneObjectPart part in m_parts.Values) |
859 | { | 945 | { |
946 | |||
860 | Dictionary<UUID,string> pstates = part.Inventory.GetScriptStates(); | 947 | Dictionary<UUID,string> pstates = part.Inventory.GetScriptStates(); |
861 | foreach (UUID itemid in pstates.Keys) | 948 | foreach (UUID itemid in pstates.Keys) |
862 | { | 949 | { |
863 | states.Add(itemid, pstates[itemid]); | 950 | states.Add(itemid, pstates[itemid]); |
864 | } | 951 | } |
952 | |||
865 | } | 953 | } |
866 | } | 954 | } |
955 | lockPartsForRead(false); | ||
867 | 956 | ||
868 | if (states.Count > 0) | 957 | if (states.Count > 0) |
869 | { | 958 | { |
@@ -1025,13 +1114,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
1025 | 1114 | ||
1026 | public override void UpdateMovement() | 1115 | public override void UpdateMovement() |
1027 | { | 1116 | { |
1028 | lock (m_parts) | 1117 | lockPartsForRead(true); |
1029 | { | 1118 | { |
1030 | foreach (SceneObjectPart part in m_parts.Values) | 1119 | foreach (SceneObjectPart part in m_parts.Values) |
1031 | { | 1120 | { |
1121 | |||
1032 | part.UpdateMovement(); | 1122 | part.UpdateMovement(); |
1123 | |||
1033 | } | 1124 | } |
1034 | } | 1125 | } |
1126 | lockPartsForRead(false); | ||
1035 | } | 1127 | } |
1036 | 1128 | ||
1037 | public ushort GetTimeDilation() | 1129 | public ushort GetTimeDilation() |
@@ -1075,7 +1167,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1075 | /// <param name="part"></param> | 1167 | /// <param name="part"></param> |
1076 | public void AddPart(SceneObjectPart part) | 1168 | public void AddPart(SceneObjectPart part) |
1077 | { | 1169 | { |
1078 | lock (m_parts) | 1170 | lockPartsForWrite(true); |
1079 | { | 1171 | { |
1080 | part.SetParent(this); | 1172 | part.SetParent(this); |
1081 | m_parts.Add(part.UUID, part); | 1173 | m_parts.Add(part.UUID, part); |
@@ -1085,6 +1177,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1085 | if (part.LinkNum == 2 && RootPart != null) | 1177 | if (part.LinkNum == 2 && RootPart != null) |
1086 | RootPart.LinkNum = 1; | 1178 | RootPart.LinkNum = 1; |
1087 | } | 1179 | } |
1180 | lockPartsForWrite(false); | ||
1088 | } | 1181 | } |
1089 | 1182 | ||
1090 | /// <summary> | 1183 | /// <summary> |
@@ -1092,28 +1185,33 @@ namespace OpenSim.Region.Framework.Scenes | |||
1092 | /// </summary> | 1185 | /// </summary> |
1093 | private void UpdateParentIDs() | 1186 | private void UpdateParentIDs() |
1094 | { | 1187 | { |
1095 | lock (m_parts) | 1188 | lockPartsForRead(true); |
1096 | { | 1189 | { |
1097 | foreach (SceneObjectPart part in m_parts.Values) | 1190 | foreach (SceneObjectPart part in m_parts.Values) |
1098 | { | 1191 | { |
1192 | |||
1099 | if (part.UUID != m_rootPart.UUID) | 1193 | if (part.UUID != m_rootPart.UUID) |
1100 | { | 1194 | { |
1101 | part.ParentID = m_rootPart.LocalId; | 1195 | part.ParentID = m_rootPart.LocalId; |
1102 | } | 1196 | } |
1197 | |||
1103 | } | 1198 | } |
1104 | } | 1199 | } |
1200 | lockPartsForRead(false); | ||
1105 | } | 1201 | } |
1106 | 1202 | ||
1107 | public void RegenerateFullIDs() | 1203 | public void RegenerateFullIDs() |
1108 | { | 1204 | { |
1109 | lock (m_parts) | 1205 | lockPartsForRead(true); |
1110 | { | 1206 | { |
1111 | foreach (SceneObjectPart part in m_parts.Values) | 1207 | foreach (SceneObjectPart part in m_parts.Values) |
1112 | { | 1208 | { |
1209 | |||
1113 | part.UUID = UUID.Random(); | 1210 | part.UUID = UUID.Random(); |
1114 | 1211 | ||
1115 | } | 1212 | } |
1116 | } | 1213 | } |
1214 | lockPartsForRead(false); | ||
1117 | } | 1215 | } |
1118 | 1216 | ||
1119 | // helper provided for parts. | 1217 | // helper provided for parts. |
@@ -1194,29 +1292,33 @@ namespace OpenSim.Region.Framework.Scenes | |||
1194 | 1292 | ||
1195 | DetachFromBackup(); | 1293 | DetachFromBackup(); |
1196 | 1294 | ||
1197 | lock (m_parts) | 1295 | lockPartsForRead(true); |
1296 | List<SceneObjectPart> values = new List<SceneObjectPart>(m_parts.Values); | ||
1297 | lockPartsForRead(false); | ||
1298 | |||
1299 | foreach (SceneObjectPart part in values) | ||
1198 | { | 1300 | { |
1199 | foreach (SceneObjectPart part in m_parts.Values) | ||
1200 | { | ||
1201 | // part.Inventory.RemoveScriptInstances(); | 1301 | // part.Inventory.RemoveScriptInstances(); |
1202 | 1302 | ||
1203 | ScenePresence[] avatars = Scene.GetScenePresences(); | 1303 | ScenePresence[] avatars = Scene.GetScenePresences(); |
1204 | for (int i = 0; i < avatars.Length; i++) | 1304 | for (int i = 0; i < avatars.Length; i++) |
1305 | { | ||
1306 | if (avatars[i].ParentID == LocalId) | ||
1205 | { | 1307 | { |
1206 | if (avatars[i].ParentID == LocalId) | 1308 | avatars[i].StandUp(); |
1207 | { | 1309 | } |
1208 | avatars[i].StandUp(); | ||
1209 | } | ||
1210 | 1310 | ||
1211 | if (!silent) | 1311 | if (!silent) |
1212 | { | 1312 | { |
1213 | part.UpdateFlag = 0; | 1313 | part.UpdateFlag = 0; |
1214 | if (part == m_rootPart) | 1314 | if (part == m_rootPart) |
1215 | avatars[i].ControllingClient.SendKillObject(m_regionHandle, part.LocalId); | 1315 | avatars[i].ControllingClient.SendKillObject(m_regionHandle, part.LocalId); |
1216 | } | ||
1217 | } | 1316 | } |
1218 | } | 1317 | } |
1318 | |||
1219 | } | 1319 | } |
1320 | |||
1321 | |||
1220 | } | 1322 | } |
1221 | 1323 | ||
1222 | public void AddScriptLPS(int count) | 1324 | public void AddScriptLPS(int count) |
@@ -1241,17 +1343,20 @@ namespace OpenSim.Region.Framework.Scenes | |||
1241 | 1343 | ||
1242 | scriptEvents aggregateScriptEvents=0; | 1344 | scriptEvents aggregateScriptEvents=0; |
1243 | 1345 | ||
1244 | lock (m_parts) | 1346 | lockPartsForRead(true); |
1245 | { | 1347 | { |
1246 | foreach (SceneObjectPart part in m_parts.Values) | 1348 | foreach (SceneObjectPart part in m_parts.Values) |
1247 | { | 1349 | { |
1350 | |||
1248 | if (part == null) | 1351 | if (part == null) |
1249 | continue; | 1352 | continue; |
1250 | if (part != RootPart) | 1353 | if (part != RootPart) |
1251 | part.ObjectFlags = objectflagupdate; | 1354 | part.ObjectFlags = objectflagupdate; |
1252 | aggregateScriptEvents |= part.AggregateScriptEvents; | 1355 | aggregateScriptEvents |= part.AggregateScriptEvents; |
1356 | |||
1253 | } | 1357 | } |
1254 | } | 1358 | } |
1359 | lockPartsForRead(false); | ||
1255 | 1360 | ||
1256 | m_scriptListens_atTarget = ((aggregateScriptEvents & scriptEvents.at_target) != 0); | 1361 | m_scriptListens_atTarget = ((aggregateScriptEvents & scriptEvents.at_target) != 0); |
1257 | m_scriptListens_notAtTarget = ((aggregateScriptEvents & scriptEvents.not_at_target) != 0); | 1362 | m_scriptListens_notAtTarget = ((aggregateScriptEvents & scriptEvents.not_at_target) != 0); |
@@ -1284,42 +1389,52 @@ namespace OpenSim.Region.Framework.Scenes | |||
1284 | /// <param name="m_physicalPrim"></param> | 1389 | /// <param name="m_physicalPrim"></param> |
1285 | public void ApplyPhysics(bool m_physicalPrim) | 1390 | public void ApplyPhysics(bool m_physicalPrim) |
1286 | { | 1391 | { |
1287 | lock (m_parts) | 1392 | lockPartsForRead(true); |
1393 | |||
1394 | if (m_parts.Count > 1) | ||
1288 | { | 1395 | { |
1289 | if (m_parts.Count > 1) | 1396 | List<SceneObjectPart> values = new List<SceneObjectPart>(m_parts.Values); |
1397 | lockPartsForRead(false); | ||
1398 | m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, m_physicalPrim); | ||
1399 | foreach (SceneObjectPart part in values) | ||
1290 | { | 1400 | { |
1291 | m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, m_physicalPrim); | 1401 | |
1292 | foreach (SceneObjectPart part in m_parts.Values) | 1402 | if (part.LocalId != m_rootPart.LocalId) |
1293 | { | 1403 | { |
1294 | if (part.LocalId != m_rootPart.LocalId) | 1404 | part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, m_physicalPrim); |
1295 | { | ||
1296 | part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, m_physicalPrim); | ||
1297 | } | ||
1298 | } | 1405 | } |
1299 | 1406 | ||
1300 | // Hack to get the physics scene geometries in the right spot | ||
1301 | ResetChildPrimPhysicsPositions(); | ||
1302 | } | ||
1303 | else | ||
1304 | { | ||
1305 | m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, m_physicalPrim); | ||
1306 | } | 1407 | } |
1408 | // Hack to get the physics scene geometries in the right spot | ||
1409 | ResetChildPrimPhysicsPositions(); | ||
1410 | } | ||
1411 | else | ||
1412 | { | ||
1413 | lockPartsForRead(false); | ||
1414 | m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, m_physicalPrim); | ||
1307 | } | 1415 | } |
1308 | } | 1416 | } |
1309 | 1417 | ||
1310 | public void SetOwnerId(UUID userId) | 1418 | public void SetOwnerId(UUID userId) |
1311 | { | 1419 | { |
1312 | ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); | 1420 | ForEachPart(delegate(SceneObjectPart part) |
1421 | { | ||
1422 | |||
1423 | part.OwnerID = userId; | ||
1424 | |||
1425 | }); | ||
1313 | } | 1426 | } |
1314 | 1427 | ||
1315 | public void ForEachPart(Action<SceneObjectPart> whatToDo) | 1428 | public void ForEachPart(Action<SceneObjectPart> whatToDo) |
1316 | { | 1429 | { |
1317 | lock (m_parts) | 1430 | lockPartsForRead(true); |
1431 | List<SceneObjectPart> values = new List<SceneObjectPart>(m_parts.Values); | ||
1432 | lockPartsForRead(false); | ||
1433 | foreach (SceneObjectPart part in values) | ||
1318 | { | 1434 | { |
1319 | foreach (SceneObjectPart part in m_parts.Values) | 1435 | |
1320 | { | 1436 | whatToDo(part); |
1321 | whatToDo(part); | 1437 | |
1322 | } | ||
1323 | } | 1438 | } |
1324 | } | 1439 | } |
1325 | 1440 | ||
@@ -1418,14 +1533,17 @@ namespace OpenSim.Region.Framework.Scenes | |||
1418 | { | 1533 | { |
1419 | SendPartFullUpdate(remoteClient, RootPart, m_scene.Permissions.GenerateClientFlags(remoteClient.AgentId, RootPart.UUID)); | 1534 | SendPartFullUpdate(remoteClient, RootPart, m_scene.Permissions.GenerateClientFlags(remoteClient.AgentId, RootPart.UUID)); |
1420 | 1535 | ||
1421 | lock (m_parts) | 1536 | lockPartsForRead(true); |
1422 | { | 1537 | { |
1423 | foreach (SceneObjectPart part in m_parts.Values) | 1538 | foreach (SceneObjectPart part in m_parts.Values) |
1424 | { | 1539 | { |
1540 | |||
1425 | if (part != RootPart) | 1541 | if (part != RootPart) |
1426 | SendPartFullUpdate(remoteClient, part, m_scene.Permissions.GenerateClientFlags(remoteClient.AgentId, part.UUID)); | 1542 | SendPartFullUpdate(remoteClient, part, m_scene.Permissions.GenerateClientFlags(remoteClient.AgentId, part.UUID)); |
1543 | |||
1427 | } | 1544 | } |
1428 | } | 1545 | } |
1546 | lockPartsForRead(false); | ||
1429 | } | 1547 | } |
1430 | 1548 | ||
1431 | /// <summary> | 1549 | /// <summary> |
@@ -1520,10 +1638,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
1520 | 1638 | ||
1521 | List<SceneObjectPart> partList; | 1639 | List<SceneObjectPart> partList; |
1522 | 1640 | ||
1523 | lock (m_parts) | 1641 | lockPartsForRead(true); |
1524 | { | 1642 | |
1525 | partList = new List<SceneObjectPart>(m_parts.Values); | 1643 | partList = new List<SceneObjectPart>(m_parts.Values); |
1526 | } | 1644 | |
1645 | lockPartsForRead(false); | ||
1527 | 1646 | ||
1528 | partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) | 1647 | partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) |
1529 | { | 1648 | { |
@@ -1772,6 +1891,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1772 | } | 1891 | } |
1773 | } | 1892 | } |
1774 | } | 1893 | } |
1894 | |||
1775 | public void stopLookAt() | 1895 | public void stopLookAt() |
1776 | { | 1896 | { |
1777 | SceneObjectPart rootpart = m_rootPart; | 1897 | SceneObjectPart rootpart = m_rootPart; |
@@ -1846,10 +1966,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
1846 | SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); | 1966 | SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); |
1847 | newPart.SetParent(this); | 1967 | newPart.SetParent(this); |
1848 | 1968 | ||
1849 | lock (m_parts) | 1969 | lockPartsForWrite(true); |
1850 | { | 1970 | { |
1851 | m_parts.Add(newPart.UUID, newPart); | 1971 | m_parts.Add(newPart.UUID, newPart); |
1852 | } | 1972 | } |
1973 | lockPartsForWrite(false); | ||
1853 | 1974 | ||
1854 | SetPartAsNonRoot(newPart); | 1975 | SetPartAsNonRoot(newPart); |
1855 | 1976 | ||
@@ -1912,7 +2033,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1912 | //if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0) | 2033 | //if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0) |
1913 | // return; | 2034 | // return; |
1914 | 2035 | ||
1915 | lock (m_parts) | 2036 | lockPartsForRead(true); |
1916 | { | 2037 | { |
1917 | bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0); | 2038 | bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0); |
1918 | 2039 | ||
@@ -1930,34 +2051,43 @@ namespace OpenSim.Region.Framework.Scenes | |||
1930 | 2051 | ||
1931 | foreach (SceneObjectPart part in m_parts.Values) | 2052 | foreach (SceneObjectPart part in m_parts.Values) |
1932 | { | 2053 | { |
2054 | |||
1933 | part.SendScheduledUpdates(); | 2055 | part.SendScheduledUpdates(); |
2056 | |||
1934 | } | 2057 | } |
1935 | } | 2058 | } |
2059 | lockPartsForRead(false); | ||
1936 | } | 2060 | } |
1937 | 2061 | ||
1938 | public void ScheduleFullUpdateToAvatar(ScenePresence presence) | 2062 | public void ScheduleFullUpdateToAvatar(ScenePresence presence) |
1939 | { | 2063 | { |
1940 | RootPart.AddFullUpdateToAvatar(presence); | 2064 | RootPart.AddFullUpdateToAvatar(presence); |
1941 | 2065 | ||
1942 | lock (m_parts) | 2066 | lockPartsForRead(true); |
1943 | { | 2067 | { |
1944 | foreach (SceneObjectPart part in m_parts.Values) | 2068 | foreach (SceneObjectPart part in m_parts.Values) |
1945 | { | 2069 | { |
2070 | |||
1946 | if (part != RootPart) | 2071 | if (part != RootPart) |
1947 | part.AddFullUpdateToAvatar(presence); | 2072 | part.AddFullUpdateToAvatar(presence); |
2073 | |||
1948 | } | 2074 | } |
1949 | } | 2075 | } |
2076 | lockPartsForRead(false); | ||
1950 | } | 2077 | } |
1951 | 2078 | ||
1952 | public void ScheduleTerseUpdateToAvatar(ScenePresence presence) | 2079 | public void ScheduleTerseUpdateToAvatar(ScenePresence presence) |
1953 | { | 2080 | { |
1954 | lock (m_parts) | 2081 | lockPartsForRead(true); |
1955 | { | 2082 | { |
1956 | foreach (SceneObjectPart part in m_parts.Values) | 2083 | foreach (SceneObjectPart part in m_parts.Values) |
1957 | { | 2084 | { |
2085 | |||
1958 | part.AddTerseUpdateToAvatar(presence); | 2086 | part.AddTerseUpdateToAvatar(presence); |
2087 | |||
1959 | } | 2088 | } |
1960 | } | 2089 | } |
2090 | lockPartsForRead(false); | ||
1961 | } | 2091 | } |
1962 | 2092 | ||
1963 | /// <summary> | 2093 | /// <summary> |
@@ -1968,14 +2098,17 @@ namespace OpenSim.Region.Framework.Scenes | |||
1968 | checkAtTargets(); | 2098 | checkAtTargets(); |
1969 | RootPart.ScheduleFullUpdate(); | 2099 | RootPart.ScheduleFullUpdate(); |
1970 | 2100 | ||
1971 | lock (m_parts) | 2101 | lockPartsForRead(true); |
1972 | { | 2102 | { |
1973 | foreach (SceneObjectPart part in m_parts.Values) | 2103 | foreach (SceneObjectPart part in m_parts.Values) |
1974 | { | 2104 | { |
2105 | |||
1975 | if (part != RootPart) | 2106 | if (part != RootPart) |
1976 | part.ScheduleFullUpdate(); | 2107 | part.ScheduleFullUpdate(); |
2108 | |||
1977 | } | 2109 | } |
1978 | } | 2110 | } |
2111 | lockPartsForRead(false); | ||
1979 | } | 2112 | } |
1980 | 2113 | ||
1981 | /// <summary> | 2114 | /// <summary> |
@@ -1983,13 +2116,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
1983 | /// </summary> | 2116 | /// </summary> |
1984 | public void ScheduleGroupForTerseUpdate() | 2117 | public void ScheduleGroupForTerseUpdate() |
1985 | { | 2118 | { |
1986 | lock (m_parts) | 2119 | lockPartsForRead(true); |
1987 | { | 2120 | { |
1988 | foreach (SceneObjectPart part in m_parts.Values) | 2121 | foreach (SceneObjectPart part in m_parts.Values) |
1989 | { | 2122 | { |
2123 | |||
1990 | part.ScheduleTerseUpdate(); | 2124 | part.ScheduleTerseUpdate(); |
2125 | |||
1991 | } | 2126 | } |
1992 | } | 2127 | } |
2128 | lockPartsForRead(false); | ||
1993 | } | 2129 | } |
1994 | 2130 | ||
1995 | /// <summary> | 2131 | /// <summary> |
@@ -2002,14 +2138,17 @@ namespace OpenSim.Region.Framework.Scenes | |||
2002 | 2138 | ||
2003 | RootPart.SendFullUpdateToAllClients(); | 2139 | RootPart.SendFullUpdateToAllClients(); |
2004 | 2140 | ||
2005 | lock (m_parts) | 2141 | lockPartsForRead(true); |
2006 | { | 2142 | { |
2007 | foreach (SceneObjectPart part in m_parts.Values) | 2143 | foreach (SceneObjectPart part in m_parts.Values) |
2008 | { | 2144 | { |
2145 | |||
2009 | if (part != RootPart) | 2146 | if (part != RootPart) |
2010 | part.SendFullUpdateToAllClients(); | 2147 | part.SendFullUpdateToAllClients(); |
2148 | |||
2011 | } | 2149 | } |
2012 | } | 2150 | } |
2151 | lockPartsForRead(false); | ||
2013 | } | 2152 | } |
2014 | 2153 | ||
2015 | /// <summary> | 2154 | /// <summary> |
@@ -2040,14 +2179,15 @@ namespace OpenSim.Region.Framework.Scenes | |||
2040 | { | 2179 | { |
2041 | if (IsDeleted) | 2180 | if (IsDeleted) |
2042 | return; | 2181 | return; |
2043 | 2182 | ||
2044 | lock (m_parts) | 2183 | lockPartsForRead(true); |
2045 | { | 2184 | { |
2046 | foreach (SceneObjectPart part in m_parts.Values) | 2185 | foreach (SceneObjectPart part in m_parts.Values) |
2047 | { | 2186 | { |
2048 | part.SendTerseUpdateToAllClients(); | 2187 | part.SendTerseUpdateToAllClients(); |
2049 | } | 2188 | } |
2050 | } | 2189 | } |
2190 | lockPartsForRead(false); | ||
2051 | } | 2191 | } |
2052 | 2192 | ||
2053 | #endregion | 2193 | #endregion |
@@ -2061,16 +2201,18 @@ namespace OpenSim.Region.Framework.Scenes | |||
2061 | /// <returns>null if no child part with that linknum or child part</returns> | 2201 | /// <returns>null if no child part with that linknum or child part</returns> |
2062 | public SceneObjectPart GetLinkNumPart(int linknum) | 2202 | public SceneObjectPart GetLinkNumPart(int linknum) |
2063 | { | 2203 | { |
2064 | lock (m_parts) | 2204 | lockPartsForRead(true); |
2065 | { | 2205 | { |
2066 | foreach (SceneObjectPart part in m_parts.Values) | 2206 | foreach (SceneObjectPart part in m_parts.Values) |
2067 | { | 2207 | { |
2068 | if (part.LinkNum == linknum) | 2208 | if (part.LinkNum == linknum) |
2069 | { | 2209 | { |
2210 | lockPartsForRead(false); | ||
2070 | return part; | 2211 | return part; |
2071 | } | 2212 | } |
2072 | } | 2213 | } |
2073 | } | 2214 | } |
2215 | lockPartsForRead(false); | ||
2074 | 2216 | ||
2075 | return null; | 2217 | return null; |
2076 | } | 2218 | } |
@@ -2098,17 +2240,19 @@ namespace OpenSim.Region.Framework.Scenes | |||
2098 | public SceneObjectPart GetChildPart(uint localID) | 2240 | public SceneObjectPart GetChildPart(uint localID) |
2099 | { | 2241 | { |
2100 | //m_log.DebugFormat("Entered looking for {0}", localID); | 2242 | //m_log.DebugFormat("Entered looking for {0}", localID); |
2101 | lock (m_parts) | 2243 | lockPartsForRead(true); |
2102 | { | 2244 | { |
2103 | foreach (SceneObjectPart part in m_parts.Values) | 2245 | foreach (SceneObjectPart part in m_parts.Values) |
2104 | { | 2246 | { |
2105 | //m_log.DebugFormat("Found {0}", part.LocalId); | 2247 | //m_log.DebugFormat("Found {0}", part.LocalId); |
2106 | if (part.LocalId == localID) | 2248 | if (part.LocalId == localID) |
2107 | { | 2249 | { |
2250 | lockPartsForRead(false); | ||
2108 | return part; | 2251 | return part; |
2109 | } | 2252 | } |
2110 | } | 2253 | } |
2111 | } | 2254 | } |
2255 | lockPartsForRead(false); | ||
2112 | 2256 | ||
2113 | return null; | 2257 | return null; |
2114 | } | 2258 | } |
@@ -2138,17 +2282,19 @@ namespace OpenSim.Region.Framework.Scenes | |||
2138 | public bool HasChildPrim(uint localID) | 2282 | public bool HasChildPrim(uint localID) |
2139 | { | 2283 | { |
2140 | //m_log.DebugFormat("Entered HasChildPrim looking for {0}", localID); | 2284 | //m_log.DebugFormat("Entered HasChildPrim looking for {0}", localID); |
2141 | lock (m_parts) | 2285 | lockPartsForRead(true); |
2142 | { | 2286 | { |
2143 | foreach (SceneObjectPart part in m_parts.Values) | 2287 | foreach (SceneObjectPart part in m_parts.Values) |
2144 | { | 2288 | { |
2145 | //m_log.DebugFormat("Found {0}", part.LocalId); | 2289 | //m_log.DebugFormat("Found {0}", part.LocalId); |
2146 | if (part.LocalId == localID) | 2290 | if (part.LocalId == localID) |
2147 | { | 2291 | { |
2292 | lockPartsForRead(false); | ||
2148 | return true; | 2293 | return true; |
2149 | } | 2294 | } |
2150 | } | 2295 | } |
2151 | } | 2296 | } |
2297 | lockPartsForRead(false); | ||
2152 | 2298 | ||
2153 | return false; | 2299 | return false; |
2154 | } | 2300 | } |
@@ -2198,53 +2344,57 @@ namespace OpenSim.Region.Framework.Scenes | |||
2198 | if (m_rootPart.LinkNum == 0) | 2344 | if (m_rootPart.LinkNum == 0) |
2199 | m_rootPart.LinkNum = 1; | 2345 | m_rootPart.LinkNum = 1; |
2200 | 2346 | ||
2201 | lock (m_parts) | 2347 | lockPartsForWrite(true); |
2202 | { | 2348 | |
2203 | m_parts.Add(linkPart.UUID, linkPart); | 2349 | m_parts.Add(linkPart.UUID, linkPart); |
2204 | 2350 | ||
2205 | // Insert in terms of link numbers, the new links | 2351 | lockPartsForWrite(false); |
2206 | // before the current ones (with the exception of | 2352 | |
2207 | // the root prim. Shuffle the old ones up | 2353 | // Insert in terms of link numbers, the new links |
2208 | foreach (KeyValuePair<UUID, SceneObjectPart> kvp in m_parts) | 2354 | // before the current ones (with the exception of |
2355 | // the root prim. Shuffle the old ones up | ||
2356 | lockPartsForRead(true); | ||
2357 | foreach (KeyValuePair<UUID, SceneObjectPart> kvp in m_parts) | ||
2358 | { | ||
2359 | if (kvp.Value.LinkNum != 1) | ||
2209 | { | 2360 | { |
2210 | if (kvp.Value.LinkNum != 1) | 2361 | // Don't update root prim link number |
2211 | { | 2362 | kvp.Value.LinkNum += objectGroup.PrimCount; |
2212 | // Don't update root prim link number | ||
2213 | kvp.Value.LinkNum += objectGroup.PrimCount; | ||
2214 | } | ||
2215 | } | 2363 | } |
2364 | } | ||
2365 | lockPartsForRead(false); | ||
2216 | 2366 | ||
2217 | linkPart.LinkNum = 2; | 2367 | linkPart.LinkNum = 2; |
2218 | 2368 | ||
2219 | linkPart.SetParent(this); | 2369 | linkPart.SetParent(this); |
2220 | linkPart.AddFlag(PrimFlags.CreateSelected); | 2370 | linkPart.AddFlag(PrimFlags.CreateSelected); |
2221 | 2371 | ||
2222 | //if (linkPart.PhysActor != null) | 2372 | //if (linkPart.PhysActor != null) |
2223 | //{ | 2373 | //{ |
2224 | // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor); | 2374 | // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor); |
2225 | 2375 | ||
2226 | //linkPart.PhysActor = null; | 2376 | //linkPart.PhysActor = null; |
2227 | //} | 2377 | //} |
2228 | 2378 | ||
2229 | //TODO: rest of parts | 2379 | //TODO: rest of parts |
2230 | int linkNum = 3; | 2380 | int linkNum = 3; |
2231 | foreach (SceneObjectPart part in objectGroup.Children.Values) | 2381 | foreach (SceneObjectPart part in objectGroup.Children.Values) |
2382 | { | ||
2383 | if (part.UUID != objectGroup.m_rootPart.UUID) | ||
2232 | { | 2384 | { |
2233 | if (part.UUID != objectGroup.m_rootPart.UUID) | 2385 | LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++); |
2234 | { | ||
2235 | LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++); | ||
2236 | } | ||
2237 | part.ClearUndoState(); | ||
2238 | } | 2386 | } |
2387 | part.ClearUndoState(); | ||
2239 | } | 2388 | } |
2240 | 2389 | ||
2241 | m_scene.UnlinkSceneObject(objectGroup.UUID, true); | 2390 | m_scene.UnlinkSceneObject(objectGroup.UUID, true); |
2242 | objectGroup.m_isDeleted = true; | 2391 | objectGroup.m_isDeleted = true; |
2392 | |||
2393 | objectGroup.lockPartsForWrite(true); | ||
2243 | 2394 | ||
2244 | lock (objectGroup.m_parts) | 2395 | objectGroup.m_parts.Clear(); |
2245 | { | 2396 | |
2246 | objectGroup.m_parts.Clear(); | 2397 | objectGroup.lockPartsForWrite(false); |
2247 | } | ||
2248 | 2398 | ||
2249 | // Can't do this yet since backup still makes use of the root part without any synchronization | 2399 | // Can't do this yet since backup still makes use of the root part without any synchronization |
2250 | // objectGroup.m_rootPart = null; | 2400 | // objectGroup.m_rootPart = null; |
@@ -2303,11 +2453,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
2303 | Quaternion worldRot = linkPart.GetWorldRotation(); | 2453 | Quaternion worldRot = linkPart.GetWorldRotation(); |
2304 | 2454 | ||
2305 | // Remove the part from this object | 2455 | // Remove the part from this object |
2306 | lock (m_parts) | 2456 | lockPartsForWrite(true); |
2307 | { | 2457 | { |
2308 | m_parts.Remove(linkPart.UUID); | 2458 | m_parts.Remove(linkPart.UUID); |
2309 | } | 2459 | } |
2310 | 2460 | lockPartsForWrite(false); | |
2461 | lockPartsForRead(true); | ||
2311 | if (m_parts.Count == 1 && RootPart != null) //Single prim is left | 2462 | if (m_parts.Count == 1 && RootPart != null) //Single prim is left |
2312 | RootPart.LinkNum = 0; | 2463 | RootPart.LinkNum = 0; |
2313 | else | 2464 | else |
@@ -2318,6 +2469,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2318 | p.LinkNum--; | 2469 | p.LinkNum--; |
2319 | } | 2470 | } |
2320 | } | 2471 | } |
2472 | lockPartsForRead(false); | ||
2321 | 2473 | ||
2322 | linkPart.ParentID = 0; | 2474 | linkPart.ParentID = 0; |
2323 | linkPart.LinkNum = 0; | 2475 | linkPart.LinkNum = 0; |
@@ -2635,9 +2787,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
2635 | 2787 | ||
2636 | if (selectionPart != null) | 2788 | if (selectionPart != null) |
2637 | { | 2789 | { |
2638 | lock (m_parts) | 2790 | lockPartsForRead(true); |
2791 | List<SceneObjectPart> parts = new List<SceneObjectPart>(m_parts.Values); | ||
2792 | lockPartsForRead(false); | ||
2793 | foreach (SceneObjectPart part in parts) | ||
2639 | { | 2794 | { |
2640 | foreach (SceneObjectPart part in m_parts.Values) | 2795 | if (part.Scale.X > 10.0 || part.Scale.Y > 10.0 || part.Scale.Z > 10.0) |
2641 | { | 2796 | { |
2642 | if (part.Scale.X > m_scene.RegionInfo.PhysPrimMax || | 2797 | if (part.Scale.X > m_scene.RegionInfo.PhysPrimMax || |
2643 | part.Scale.Y > m_scene.RegionInfo.PhysPrimMax || | 2798 | part.Scale.Y > m_scene.RegionInfo.PhysPrimMax || |
@@ -2647,12 +2802,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
2647 | break; | 2802 | break; |
2648 | } | 2803 | } |
2649 | } | 2804 | } |
2805 | } | ||
2650 | 2806 | ||
2651 | foreach (SceneObjectPart part in m_parts.Values) | 2807 | foreach (SceneObjectPart part in parts) |
2652 | { | 2808 | { |
2653 | part.UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect); | 2809 | part.UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect); |
2654 | } | ||
2655 | } | 2810 | } |
2811 | |||
2656 | } | 2812 | } |
2657 | } | 2813 | } |
2658 | 2814 | ||
@@ -2738,11 +2894,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
2738 | scale.Y = m_scene.m_maxNonphys; | 2894 | scale.Y = m_scene.m_maxNonphys; |
2739 | if (scale.Z > m_scene.m_maxNonphys) | 2895 | if (scale.Z > m_scene.m_maxNonphys) |
2740 | scale.Z = m_scene.m_maxNonphys; | 2896 | scale.Z = m_scene.m_maxNonphys; |
2741 | |||
2742 | SceneObjectPart part = GetChildPart(localID); | 2897 | SceneObjectPart part = GetChildPart(localID); |
2743 | if (part != null) | 2898 | if (part != null) |
2744 | { | 2899 | { |
2745 | part.Resize(scale); | ||
2746 | if (part.PhysActor != null) | 2900 | if (part.PhysActor != null) |
2747 | { | 2901 | { |
2748 | if (part.PhysActor.IsPhysical) | 2902 | if (part.PhysActor.IsPhysical) |
@@ -2757,7 +2911,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2757 | part.PhysActor.Size = scale; | 2911 | part.PhysActor.Size = scale; |
2758 | m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor); | 2912 | m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor); |
2759 | } | 2913 | } |
2760 | //if (part.UUID != m_rootPart.UUID) | 2914 | part.Resize(scale); |
2761 | 2915 | ||
2762 | HasGroupChanged = true; | 2916 | HasGroupChanged = true; |
2763 | ScheduleGroupForFullUpdate(); | 2917 | ScheduleGroupForFullUpdate(); |
@@ -2798,77 +2952,76 @@ namespace OpenSim.Region.Framework.Scenes | |||
2798 | float y = (scale.Y / part.Scale.Y); | 2952 | float y = (scale.Y / part.Scale.Y); |
2799 | float z = (scale.Z / part.Scale.Z); | 2953 | float z = (scale.Z / part.Scale.Z); |
2800 | 2954 | ||
2801 | lock (m_parts) | 2955 | lockPartsForRead(true); |
2956 | if (x > 1.0f || y > 1.0f || z > 1.0f) | ||
2802 | { | 2957 | { |
2803 | if (x > 1.0f || y > 1.0f || z > 1.0f) | 2958 | foreach (SceneObjectPart obPart in m_parts.Values) |
2804 | { | 2959 | { |
2805 | foreach (SceneObjectPart obPart in m_parts.Values) | 2960 | if (obPart.UUID != m_rootPart.UUID) |
2806 | { | 2961 | { |
2807 | if (obPart.UUID != m_rootPart.UUID) | 2962 | Vector3 oldSize = new Vector3(obPart.Scale); |
2808 | { | ||
2809 | Vector3 oldSize = new Vector3(obPart.Scale); | ||
2810 | 2963 | ||
2811 | float f = 1.0f; | 2964 | float f = 1.0f; |
2812 | float a = 1.0f; | 2965 | float a = 1.0f; |
2813 | 2966 | ||
2814 | if (part.PhysActor != null && part.PhysActor.IsPhysical) | 2967 | if (part.PhysActor != null && part.PhysActor.IsPhysical) |
2968 | { | ||
2969 | if (oldSize.X*x > m_scene.m_maxPhys) | ||
2815 | { | 2970 | { |
2816 | if (oldSize.X*x > m_scene.m_maxPhys) | 2971 | f = m_scene.m_maxPhys / oldSize.X; |
2817 | { | 2972 | a = f / x; |
2818 | f = m_scene.m_maxPhys / oldSize.X; | 2973 | x *= a; |
2819 | a = f / x; | 2974 | y *= a; |
2820 | x *= a; | 2975 | z *= a; |
2821 | y *= a; | ||
2822 | z *= a; | ||
2823 | } | ||
2824 | if (oldSize.Y*y > m_scene.m_maxPhys) | ||
2825 | { | ||
2826 | f = m_scene.m_maxPhys / oldSize.Y; | ||
2827 | a = f / y; | ||
2828 | x *= a; | ||
2829 | y *= a; | ||
2830 | z *= a; | ||
2831 | } | ||
2832 | if (oldSize.Z*z > m_scene.m_maxPhys) | ||
2833 | { | ||
2834 | f = m_scene.m_maxPhys / oldSize.Z; | ||
2835 | a = f / z; | ||
2836 | x *= a; | ||
2837 | y *= a; | ||
2838 | z *= a; | ||
2839 | } | ||
2840 | } | 2976 | } |
2841 | else | 2977 | if (oldSize.Y*y > m_scene.m_maxPhys) |
2978 | { | ||
2979 | f = m_scene.m_maxPhys / oldSize.Y; | ||
2980 | a = f / y; | ||
2981 | x *= a; | ||
2982 | y *= a; | ||
2983 | z *= a; | ||
2984 | } | ||
2985 | if (oldSize.Z*z > m_scene.m_maxPhys) | ||
2986 | { | ||
2987 | f = m_scene.m_maxPhys / oldSize.Z; | ||
2988 | a = f / z; | ||
2989 | x *= a; | ||
2990 | y *= a; | ||
2991 | z *= a; | ||
2992 | } | ||
2993 | } | ||
2994 | else | ||
2995 | { | ||
2996 | if (oldSize.X*x > m_scene.m_maxNonphys) | ||
2997 | { | ||
2998 | f = m_scene.m_maxNonphys / oldSize.X; | ||
2999 | a = f / x; | ||
3000 | x *= a; | ||
3001 | y *= a; | ||
3002 | z *= a; | ||
3003 | } | ||
3004 | if (oldSize.Y*y > m_scene.m_maxNonphys) | ||
2842 | { | 3005 | { |
2843 | if (oldSize.X*x > m_scene.m_maxNonphys) | 3006 | f = m_scene.m_maxNonphys / oldSize.Y; |
2844 | { | 3007 | a = f / y; |
2845 | f = m_scene.m_maxNonphys / oldSize.X; | 3008 | x *= a; |
2846 | a = f / x; | 3009 | y *= a; |
2847 | x *= a; | 3010 | z *= a; |
2848 | y *= a; | 3011 | } |
2849 | z *= a; | 3012 | if (oldSize.Z*z > m_scene.m_maxNonphys) |
2850 | } | 3013 | { |
2851 | if (oldSize.Y*y > m_scene.m_maxNonphys) | 3014 | f = m_scene.m_maxNonphys / oldSize.Z; |
2852 | { | 3015 | a = f / z; |
2853 | f = m_scene.m_maxNonphys / oldSize.Y; | 3016 | x *= a; |
2854 | a = f / y; | 3017 | y *= a; |
2855 | x *= a; | 3018 | z *= a; |
2856 | y *= a; | ||
2857 | z *= a; | ||
2858 | } | ||
2859 | if (oldSize.Z*z > m_scene.m_maxNonphys) | ||
2860 | { | ||
2861 | f = m_scene.m_maxNonphys / oldSize.Z; | ||
2862 | a = f / z; | ||
2863 | x *= a; | ||
2864 | y *= a; | ||
2865 | z *= a; | ||
2866 | } | ||
2867 | } | 3019 | } |
2868 | } | 3020 | } |
2869 | } | 3021 | } |
2870 | } | 3022 | } |
2871 | } | 3023 | } |
3024 | lockPartsForRead(false); | ||
2872 | 3025 | ||
2873 | Vector3 prevScale = part.Scale; | 3026 | Vector3 prevScale = part.Scale; |
2874 | prevScale.X *= x; | 3027 | prevScale.X *= x; |
@@ -2876,7 +3029,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2876 | prevScale.Z *= z; | 3029 | prevScale.Z *= z; |
2877 | part.Resize(prevScale); | 3030 | part.Resize(prevScale); |
2878 | 3031 | ||
2879 | lock (m_parts) | 3032 | lockPartsForRead(true); |
2880 | { | 3033 | { |
2881 | foreach (SceneObjectPart obPart in m_parts.Values) | 3034 | foreach (SceneObjectPart obPart in m_parts.Values) |
2882 | { | 3035 | { |
@@ -2895,6 +3048,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2895 | } | 3048 | } |
2896 | } | 3049 | } |
2897 | } | 3050 | } |
3051 | lockPartsForRead(false); | ||
2898 | 3052 | ||
2899 | if (part.PhysActor != null) | 3053 | if (part.PhysActor != null) |
2900 | { | 3054 | { |
@@ -2975,7 +3129,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2975 | axDiff *= Quaternion.Inverse(partRotation); | 3129 | axDiff *= Quaternion.Inverse(partRotation); |
2976 | diff = axDiff; | 3130 | diff = axDiff; |
2977 | 3131 | ||
2978 | lock (m_parts) | 3132 | lockPartsForRead(true); |
2979 | { | 3133 | { |
2980 | foreach (SceneObjectPart obPart in m_parts.Values) | 3134 | foreach (SceneObjectPart obPart in m_parts.Values) |
2981 | { | 3135 | { |
@@ -2985,6 +3139,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2985 | } | 3139 | } |
2986 | } | 3140 | } |
2987 | } | 3141 | } |
3142 | lockPartsForRead(false); | ||
2988 | 3143 | ||
2989 | AbsolutePosition = newPos; | 3144 | AbsolutePosition = newPos; |
2990 | 3145 | ||
@@ -3102,7 +3257,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3102 | m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor); | 3257 | m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor); |
3103 | } | 3258 | } |
3104 | 3259 | ||
3105 | lock (m_parts) | 3260 | lockPartsForRead(true); |
3106 | { | 3261 | { |
3107 | foreach (SceneObjectPart prim in m_parts.Values) | 3262 | foreach (SceneObjectPart prim in m_parts.Values) |
3108 | { | 3263 | { |
@@ -3120,6 +3275,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3120 | } | 3275 | } |
3121 | } | 3276 | } |
3122 | } | 3277 | } |
3278 | lockPartsForRead(false); | ||
3123 | 3279 | ||
3124 | m_rootPart.ScheduleTerseUpdate(); | 3280 | m_rootPart.ScheduleTerseUpdate(); |
3125 | } | 3281 | } |
@@ -3218,7 +3374,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3218 | if (atTargets.Count > 0) | 3374 | if (atTargets.Count > 0) |
3219 | { | 3375 | { |
3220 | uint[] localids = new uint[0]; | 3376 | uint[] localids = new uint[0]; |
3221 | lock (m_parts) | 3377 | lockPartsForRead(true); |
3222 | { | 3378 | { |
3223 | localids = new uint[m_parts.Count]; | 3379 | localids = new uint[m_parts.Count]; |
3224 | int cntr = 0; | 3380 | int cntr = 0; |
@@ -3228,6 +3384,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3228 | cntr++; | 3384 | cntr++; |
3229 | } | 3385 | } |
3230 | } | 3386 | } |
3387 | lockPartsForRead(false); | ||
3231 | 3388 | ||
3232 | for (int ctr = 0; ctr < localids.Length; ctr++) | 3389 | for (int ctr = 0; ctr < localids.Length; ctr++) |
3233 | { | 3390 | { |
@@ -3246,7 +3403,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3246 | { | 3403 | { |
3247 | //trigger not_at_target | 3404 | //trigger not_at_target |
3248 | uint[] localids = new uint[0]; | 3405 | uint[] localids = new uint[0]; |
3249 | lock (m_parts) | 3406 | lockPartsForRead(true); |
3250 | { | 3407 | { |
3251 | localids = new uint[m_parts.Count]; | 3408 | localids = new uint[m_parts.Count]; |
3252 | int cntr = 0; | 3409 | int cntr = 0; |
@@ -3256,7 +3413,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
3256 | cntr++; | 3413 | cntr++; |
3257 | } | 3414 | } |
3258 | } | 3415 | } |
3259 | 3416 | lockPartsForRead(false); | |
3417 | |||
3260 | for (int ctr = 0; ctr < localids.Length; ctr++) | 3418 | for (int ctr = 0; ctr < localids.Length; ctr++) |
3261 | { | 3419 | { |
3262 | m_scene.EventManager.TriggerNotAtTargetEvent(localids[ctr]); | 3420 | m_scene.EventManager.TriggerNotAtTargetEvent(localids[ctr]); |
@@ -3269,19 +3427,20 @@ namespace OpenSim.Region.Framework.Scenes | |||
3269 | public float GetMass() | 3427 | public float GetMass() |
3270 | { | 3428 | { |
3271 | float retmass = 0f; | 3429 | float retmass = 0f; |
3272 | lock (m_parts) | 3430 | lockPartsForRead(true); |
3273 | { | 3431 | { |
3274 | foreach (SceneObjectPart part in m_parts.Values) | 3432 | foreach (SceneObjectPart part in m_parts.Values) |
3275 | { | 3433 | { |
3276 | retmass += part.GetMass(); | 3434 | retmass += part.GetMass(); |
3277 | } | 3435 | } |
3278 | } | 3436 | } |
3437 | lockPartsForRead(false); | ||
3279 | return retmass; | 3438 | return retmass; |
3280 | } | 3439 | } |
3281 | 3440 | ||
3282 | public void CheckSculptAndLoad() | 3441 | public void CheckSculptAndLoad() |
3283 | { | 3442 | { |
3284 | lock (m_parts) | 3443 | lockPartsForRead(true); |
3285 | { | 3444 | { |
3286 | if (!IsDeleted) | 3445 | if (!IsDeleted) |
3287 | { | 3446 | { |
@@ -3306,6 +3465,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3306 | } | 3465 | } |
3307 | } | 3466 | } |
3308 | } | 3467 | } |
3468 | lockPartsForRead(false); | ||
3309 | } | 3469 | } |
3310 | 3470 | ||
3311 | protected void AssetReceived(string id, Object sender, AssetBase asset) | 3471 | protected void AssetReceived(string id, Object sender, AssetBase asset) |
@@ -3326,7 +3486,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3326 | /// <param name="client"></param> | 3486 | /// <param name="client"></param> |
3327 | public void SetGroup(UUID GroupID, IClientAPI client) | 3487 | public void SetGroup(UUID GroupID, IClientAPI client) |
3328 | { | 3488 | { |
3329 | lock (m_parts) | 3489 | lockPartsForRead(true); |
3330 | { | 3490 | { |
3331 | foreach (SceneObjectPart part in m_parts.Values) | 3491 | foreach (SceneObjectPart part in m_parts.Values) |
3332 | { | 3492 | { |
@@ -3336,7 +3496,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3336 | 3496 | ||
3337 | HasGroupChanged = true; | 3497 | HasGroupChanged = true; |
3338 | } | 3498 | } |
3339 | 3499 | lockPartsForRead(false); | |
3340 | ScheduleGroupForFullUpdate(); | 3500 | ScheduleGroupForFullUpdate(); |
3341 | } | 3501 | } |
3342 | 3502 | ||
@@ -3355,11 +3515,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
3355 | 3515 | ||
3356 | public void SetAttachmentPoint(byte point) | 3516 | public void SetAttachmentPoint(byte point) |
3357 | { | 3517 | { |
3358 | lock (m_parts) | 3518 | lockPartsForRead(true); |
3359 | { | 3519 | { |
3360 | foreach (SceneObjectPart part in m_parts.Values) | 3520 | foreach (SceneObjectPart part in m_parts.Values) |
3361 | part.SetAttachmentPoint(point); | 3521 | part.SetAttachmentPoint(point); |
3362 | } | 3522 | } |
3523 | lockPartsForRead(false); | ||
3363 | } | 3524 | } |
3364 | 3525 | ||
3365 | #region ISceneObject | 3526 | #region ISceneObject |
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index d1bc351..e5fc027 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | |||
@@ -224,6 +224,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
224 | private Quaternion m_sitTargetOrientation = Quaternion.Identity; | 224 | private Quaternion m_sitTargetOrientation = Quaternion.Identity; |
225 | private Vector3 m_sitTargetPosition; | 225 | private Vector3 m_sitTargetPosition; |
226 | private string m_sitAnimation = "SIT"; | 226 | private string m_sitAnimation = "SIT"; |
227 | private bool m_occupied; // KF if any av is sitting on this prim | ||
227 | private string m_text = String.Empty; | 228 | private string m_text = String.Empty; |
228 | private string m_touchName = String.Empty; | 229 | private string m_touchName = String.Empty; |
229 | private readonly UndoStack<UndoState> m_undo = new UndoStack<UndoState>(5); | 230 | private readonly UndoStack<UndoState> m_undo = new UndoStack<UndoState>(5); |
@@ -401,12 +402,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
401 | } | 402 | } |
402 | 403 | ||
403 | /// <value> | 404 | /// <value> |
404 | /// Access should be via Inventory directly - this property temporarily remains for xml serialization purposes | 405 | /// Get the inventory list |
405 | /// </value> | 406 | /// </value> |
406 | public TaskInventoryDictionary TaskInventory | 407 | public TaskInventoryDictionary TaskInventory |
407 | { | 408 | { |
408 | get { return m_inventory.Items; } | 409 | get { |
409 | set { m_inventory.Items = value; } | 410 | return m_inventory.Items; |
411 | } | ||
412 | set { | ||
413 | m_inventory.Items = value; | ||
414 | } | ||
410 | } | 415 | } |
411 | 416 | ||
412 | public uint ObjectFlags | 417 | public uint ObjectFlags |
@@ -550,7 +555,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
550 | StoreUndoState(); | 555 | StoreUndoState(); |
551 | 556 | ||
552 | m_groupPosition = value; | 557 | m_groupPosition = value; |
553 | |||
554 | PhysicsActor actor = PhysActor; | 558 | PhysicsActor actor = PhysActor; |
555 | if (actor != null) | 559 | if (actor != null) |
556 | { | 560 | { |
@@ -860,7 +864,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
860 | if (IsAttachment) | 864 | if (IsAttachment) |
861 | return GroupPosition; | 865 | return GroupPosition; |
862 | 866 | ||
863 | return m_offsetPosition + m_groupPosition; } | 867 | // return m_offsetPosition + m_groupPosition; } |
868 | return m_groupPosition + (m_offsetPosition * ParentGroup.RootPart.RotationOffset) ; } //KF: Rotation was ignored! | ||
864 | } | 869 | } |
865 | 870 | ||
866 | public SceneObjectGroup ParentGroup | 871 | public SceneObjectGroup ParentGroup |
@@ -1012,6 +1017,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
1012 | get { return _flags; } | 1017 | get { return _flags; } |
1013 | set { _flags = value; } | 1018 | set { _flags = value; } |
1014 | } | 1019 | } |
1020 | |||
1021 | [XmlIgnore] | ||
1022 | public bool IsOccupied // KF If an av is sittingon this prim | ||
1023 | { | ||
1024 | get { return m_occupied; } | ||
1025 | set { m_occupied = value; } | ||
1026 | } | ||
1015 | 1027 | ||
1016 | [XmlIgnore] | 1028 | [XmlIgnore] |
1017 | public UUID SitTargetAvatar | 1029 | public UUID SitTargetAvatar |
@@ -1087,14 +1099,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
1087 | } | 1099 | } |
1088 | } | 1100 | } |
1089 | 1101 | ||
1090 | /// <summary> | ||
1091 | /// Clear all pending updates of parts to clients | ||
1092 | /// </summary> | ||
1093 | private void ClearUpdateSchedule() | ||
1094 | { | ||
1095 | m_updateFlag = 0; | ||
1096 | } | ||
1097 | |||
1098 | private void SendObjectPropertiesToClient(UUID AgentID) | 1102 | private void SendObjectPropertiesToClient(UUID AgentID) |
1099 | { | 1103 | { |
1100 | ScenePresence[] avatars = m_parentGroup.Scene.GetScenePresences(); | 1104 | ScenePresence[] avatars = m_parentGroup.Scene.GetScenePresences(); |
@@ -1773,12 +1777,17 @@ namespace OpenSim.Region.Framework.Scenes | |||
1773 | public Vector3 GetWorldPosition() | 1777 | public Vector3 GetWorldPosition() |
1774 | { | 1778 | { |
1775 | Quaternion parentRot = ParentGroup.RootPart.RotationOffset; | 1779 | Quaternion parentRot = ParentGroup.RootPart.RotationOffset; |
1776 | |||
1777 | Vector3 axPos = OffsetPosition; | 1780 | Vector3 axPos = OffsetPosition; |
1778 | |||
1779 | axPos *= parentRot; | 1781 | axPos *= parentRot; |
1780 | Vector3 translationOffsetPosition = axPos; | 1782 | Vector3 translationOffsetPosition = axPos; |
1781 | return GroupPosition + translationOffsetPosition; | 1783 | if(_parentID == 0) |
1784 | { | ||
1785 | return GroupPosition; | ||
1786 | } | ||
1787 | else | ||
1788 | { | ||
1789 | return ParentGroup.AbsolutePosition + translationOffsetPosition; //KF: Fix child prim position | ||
1790 | } | ||
1782 | } | 1791 | } |
1783 | 1792 | ||
1784 | /// <summary> | 1793 | /// <summary> |
@@ -1789,7 +1798,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1789 | { | 1798 | { |
1790 | Quaternion newRot; | 1799 | Quaternion newRot; |
1791 | 1800 | ||
1792 | if (this.LinkNum == 0) | 1801 | if (this.LinkNum < 2) //KF Single or root prim |
1793 | { | 1802 | { |
1794 | newRot = RotationOffset; | 1803 | newRot = RotationOffset; |
1795 | } | 1804 | } |
@@ -2334,17 +2343,18 @@ namespace OpenSim.Region.Framework.Scenes | |||
2334 | //Trys to fetch sound id from prim's inventory. | 2343 | //Trys to fetch sound id from prim's inventory. |
2335 | //Prim's inventory doesn't support non script items yet | 2344 | //Prim's inventory doesn't support non script items yet |
2336 | 2345 | ||
2337 | lock (TaskInventory) | 2346 | TaskInventory.LockItemsForRead(true); |
2347 | |||
2348 | foreach (KeyValuePair<UUID, TaskInventoryItem> item in TaskInventory) | ||
2338 | { | 2349 | { |
2339 | foreach (KeyValuePair<UUID, TaskInventoryItem> item in TaskInventory) | 2350 | if (item.Value.Name == sound) |
2340 | { | 2351 | { |
2341 | if (item.Value.Name == sound) | 2352 | soundID = item.Value.ItemID; |
2342 | { | 2353 | break; |
2343 | soundID = item.Value.ItemID; | ||
2344 | break; | ||
2345 | } | ||
2346 | } | 2354 | } |
2347 | } | 2355 | } |
2356 | |||
2357 | TaskInventory.LockItemsForRead(false); | ||
2348 | } | 2358 | } |
2349 | 2359 | ||
2350 | List<ScenePresence> avatarts = m_parentGroup.Scene.GetAvatars(); | 2360 | List<ScenePresence> avatarts = m_parentGroup.Scene.GetAvatars(); |
@@ -2619,8 +2629,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
2619 | { | 2629 | { |
2620 | const float ROTATION_TOLERANCE = 0.01f; | 2630 | const float ROTATION_TOLERANCE = 0.01f; |
2621 | const float VELOCITY_TOLERANCE = 0.001f; | 2631 | const float VELOCITY_TOLERANCE = 0.001f; |
2622 | const float POSITION_TOLERANCE = 0.05f; | 2632 | const float POSITION_TOLERANCE = 0.05f; // I don't like this, but I suppose it's necessary |
2623 | const int TIME_MS_TOLERANCE = 3000; | 2633 | const int TIME_MS_TOLERANCE = 200; //llSetPos has a 200ms delay. This should NOT be 3 seconds. |
2624 | 2634 | ||
2625 | if (m_updateFlag == 1) | 2635 | if (m_updateFlag == 1) |
2626 | { | 2636 | { |
@@ -2634,7 +2644,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2634 | Environment.TickCount - m_lastTerseSent > TIME_MS_TOLERANCE) | 2644 | Environment.TickCount - m_lastTerseSent > TIME_MS_TOLERANCE) |
2635 | { | 2645 | { |
2636 | AddTerseUpdateToAllAvatars(); | 2646 | AddTerseUpdateToAllAvatars(); |
2637 | ClearUpdateSchedule(); | 2647 | |
2638 | 2648 | ||
2639 | // This causes the Scene to 'poll' physical objects every couple of frames | 2649 | // This causes the Scene to 'poll' physical objects every couple of frames |
2640 | // bad, so it's been replaced by an event driven method. | 2650 | // bad, so it's been replaced by an event driven method. |
@@ -2652,16 +2662,18 @@ namespace OpenSim.Region.Framework.Scenes | |||
2652 | m_lastAngularVelocity = AngularVelocity; | 2662 | m_lastAngularVelocity = AngularVelocity; |
2653 | m_lastTerseSent = Environment.TickCount; | 2663 | m_lastTerseSent = Environment.TickCount; |
2654 | } | 2664 | } |
2665 | //Moved this outside of the if clause so updates don't get blocked.. *sigh* | ||
2666 | m_updateFlag = 0; //Why were we calling a function to do this? Inefficient! *screams* | ||
2655 | } | 2667 | } |
2656 | else | 2668 | else |
2657 | { | 2669 | { |
2658 | if (m_updateFlag == 2) // is a new prim, just created/reloaded or has major changes | 2670 | if (m_updateFlag == 2) // is a new prim, just created/reloaded or has major changes |
2659 | { | 2671 | { |
2660 | AddFullUpdateToAllAvatars(); | 2672 | AddFullUpdateToAllAvatars(); |
2661 | ClearUpdateSchedule(); | 2673 | m_updateFlag = 0; //Same here |
2662 | } | 2674 | } |
2663 | } | 2675 | } |
2664 | ClearUpdateSchedule(); | 2676 | m_updateFlag = 0; |
2665 | } | 2677 | } |
2666 | 2678 | ||
2667 | /// <summary> | 2679 | /// <summary> |
@@ -2688,17 +2700,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
2688 | if (!UUID.TryParse(sound, out soundID)) | 2700 | if (!UUID.TryParse(sound, out soundID)) |
2689 | { | 2701 | { |
2690 | // search sound file from inventory | 2702 | // search sound file from inventory |
2691 | lock (TaskInventory) | 2703 | TaskInventory.LockItemsForRead(true); |
2704 | foreach (KeyValuePair<UUID, TaskInventoryItem> item in TaskInventory) | ||
2692 | { | 2705 | { |
2693 | foreach (KeyValuePair<UUID, TaskInventoryItem> item in TaskInventory) | 2706 | if (item.Value.Name == sound && item.Value.Type == (int)AssetType.Sound) |
2694 | { | 2707 | { |
2695 | if (item.Value.Name == sound && item.Value.Type == (int)AssetType.Sound) | 2708 | soundID = item.Value.ItemID; |
2696 | { | 2709 | break; |
2697 | soundID = item.Value.ItemID; | ||
2698 | break; | ||
2699 | } | ||
2700 | } | 2710 | } |
2701 | } | 2711 | } |
2712 | TaskInventory.LockItemsForRead(false); | ||
2702 | } | 2713 | } |
2703 | 2714 | ||
2704 | if (soundID == UUID.Zero) | 2715 | if (soundID == UUID.Zero) |
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs index eb7f5ff..c3c6342 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs | |||
@@ -82,7 +82,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
82 | /// </value> | 82 | /// </value> |
83 | protected internal TaskInventoryDictionary Items | 83 | protected internal TaskInventoryDictionary Items |
84 | { | 84 | { |
85 | get { return m_items; } | 85 | get { |
86 | return m_items; | ||
87 | } | ||
86 | set | 88 | set |
87 | { | 89 | { |
88 | m_items = value; | 90 | m_items = value; |
@@ -118,22 +120,25 @@ namespace OpenSim.Region.Framework.Scenes | |||
118 | /// <param name="linkNum">Link number for the part</param> | 120 | /// <param name="linkNum">Link number for the part</param> |
119 | public void ResetInventoryIDs() | 121 | public void ResetInventoryIDs() |
120 | { | 122 | { |
121 | lock (Items) | 123 | m_items.LockItemsForWrite(true); |
124 | |||
125 | if (0 == Items.Count) | ||
122 | { | 126 | { |
123 | if (0 == Items.Count) | 127 | m_items.LockItemsForWrite(false); |
124 | return; | 128 | return; |
129 | } | ||
125 | 130 | ||
126 | HasInventoryChanged = true; | 131 | HasInventoryChanged = true; |
127 | m_part.ParentGroup.HasGroupChanged = true; | 132 | m_part.ParentGroup.HasGroupChanged = true; |
128 | IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values); | 133 | IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values); |
129 | Items.Clear(); | 134 | Items.Clear(); |
130 | 135 | ||
131 | foreach (TaskInventoryItem item in items) | 136 | foreach (TaskInventoryItem item in items) |
132 | { | 137 | { |
133 | item.ResetIDs(m_part.UUID); | 138 | item.ResetIDs(m_part.UUID); |
134 | Items.Add(item.ItemID, item); | 139 | Items.Add(item.ItemID, item); |
135 | } | ||
136 | } | 140 | } |
141 | m_items.LockItemsForWrite(false); | ||
137 | } | 142 | } |
138 | 143 | ||
139 | /// <summary> | 144 | /// <summary> |
@@ -142,25 +147,25 @@ namespace OpenSim.Region.Framework.Scenes | |||
142 | /// <param name="ownerId"></param> | 147 | /// <param name="ownerId"></param> |
143 | public void ChangeInventoryOwner(UUID ownerId) | 148 | public void ChangeInventoryOwner(UUID ownerId) |
144 | { | 149 | { |
145 | lock (Items) | 150 | m_items.LockItemsForWrite(true); |
151 | if (0 == Items.Count) | ||
146 | { | 152 | { |
147 | if (0 == Items.Count) | 153 | m_items.LockItemsForWrite(false); |
148 | { | 154 | return; |
149 | return; | 155 | } |
150 | } | ||
151 | 156 | ||
152 | HasInventoryChanged = true; | 157 | HasInventoryChanged = true; |
153 | m_part.ParentGroup.HasGroupChanged = true; | 158 | m_part.ParentGroup.HasGroupChanged = true; |
154 | IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values); | 159 | IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values); |
155 | foreach (TaskInventoryItem item in items) | 160 | foreach (TaskInventoryItem item in items) |
161 | { | ||
162 | if (ownerId != item.OwnerID) | ||
156 | { | 163 | { |
157 | if (ownerId != item.OwnerID) | 164 | item.LastOwnerID = item.OwnerID; |
158 | { | 165 | item.OwnerID = ownerId; |
159 | item.LastOwnerID = item.OwnerID; | ||
160 | item.OwnerID = ownerId; | ||
161 | } | ||
162 | } | 166 | } |
163 | } | 167 | } |
168 | m_items.LockItemsForWrite(false); | ||
164 | } | 169 | } |
165 | 170 | ||
166 | /// <summary> | 171 | /// <summary> |
@@ -169,24 +174,24 @@ namespace OpenSim.Region.Framework.Scenes | |||
169 | /// <param name="groupID"></param> | 174 | /// <param name="groupID"></param> |
170 | public void ChangeInventoryGroup(UUID groupID) | 175 | public void ChangeInventoryGroup(UUID groupID) |
171 | { | 176 | { |
172 | lock (Items) | 177 | m_items.LockItemsForWrite(true); |
178 | if (0 == Items.Count) | ||
173 | { | 179 | { |
174 | if (0 == Items.Count) | 180 | m_items.LockItemsForWrite(false); |
175 | { | 181 | return; |
176 | return; | 182 | } |
177 | } | ||
178 | 183 | ||
179 | HasInventoryChanged = true; | 184 | HasInventoryChanged = true; |
180 | m_part.ParentGroup.HasGroupChanged = true; | 185 | m_part.ParentGroup.HasGroupChanged = true; |
181 | IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values); | 186 | IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values); |
182 | foreach (TaskInventoryItem item in items) | 187 | foreach (TaskInventoryItem item in items) |
188 | { | ||
189 | if (groupID != item.GroupID) | ||
183 | { | 190 | { |
184 | if (groupID != item.GroupID) | 191 | item.GroupID = groupID; |
185 | { | ||
186 | item.GroupID = groupID; | ||
187 | } | ||
188 | } | 192 | } |
189 | } | 193 | } |
194 | m_items.LockItemsForWrite(false); | ||
190 | } | 195 | } |
191 | 196 | ||
192 | /// <summary> | 197 | /// <summary> |
@@ -194,14 +199,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
194 | /// </summary> | 199 | /// </summary> |
195 | public void CreateScriptInstances(int startParam, bool postOnRez, string engine, int stateSource) | 200 | public void CreateScriptInstances(int startParam, bool postOnRez, string engine, int stateSource) |
196 | { | 201 | { |
197 | lock (m_items) | 202 | Items.LockItemsForRead(true); |
203 | IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values); | ||
204 | Items.LockItemsForRead(false); | ||
205 | foreach (TaskInventoryItem item in items) | ||
198 | { | 206 | { |
199 | foreach (TaskInventoryItem item in Items.Values) | 207 | if ((int)InventoryType.LSL == item.InvType) |
200 | { | 208 | { |
201 | if ((int)InventoryType.LSL == item.InvType) | 209 | CreateScriptInstance(item, startParam, postOnRez, engine, stateSource); |
202 | { | ||
203 | CreateScriptInstance(item, startParam, postOnRez, engine, stateSource); | ||
204 | } | ||
205 | } | 210 | } |
206 | } | 211 | } |
207 | } | 212 | } |
@@ -232,17 +237,20 @@ namespace OpenSim.Region.Framework.Scenes | |||
232 | /// </summary> | 237 | /// </summary> |
233 | public void RemoveScriptInstances() | 238 | public void RemoveScriptInstances() |
234 | { | 239 | { |
235 | lock (Items) | 240 | Items.LockItemsForRead(true); |
241 | IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values); | ||
242 | Items.LockItemsForRead(false); | ||
243 | |||
244 | foreach (TaskInventoryItem item in items) | ||
236 | { | 245 | { |
237 | foreach (TaskInventoryItem item in Items.Values) | 246 | if ((int)InventoryType.LSL == item.InvType) |
238 | { | 247 | { |
239 | if ((int)InventoryType.LSL == item.InvType) | 248 | RemoveScriptInstance(item.ItemID); |
240 | { | 249 | m_part.RemoveScriptEvents(item.ItemID); |
241 | RemoveScriptInstance(item.ItemID); | ||
242 | m_part.RemoveScriptEvents(item.ItemID); | ||
243 | } | ||
244 | } | 250 | } |
245 | } | 251 | } |
252 | |||
253 | |||
246 | } | 254 | } |
247 | 255 | ||
248 | /// <summary> | 256 | /// <summary> |
@@ -267,8 +275,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
267 | if (stateSource == 1 && // Prim crossing | 275 | if (stateSource == 1 && // Prim crossing |
268 | m_part.ParentGroup.Scene.m_trustBinaries) | 276 | m_part.ParentGroup.Scene.m_trustBinaries) |
269 | { | 277 | { |
278 | m_items.LockItemsForWrite(true); | ||
270 | m_items[item.ItemID].PermsMask = 0; | 279 | m_items[item.ItemID].PermsMask = 0; |
271 | m_items[item.ItemID].PermsGranter = UUID.Zero; | 280 | m_items[item.ItemID].PermsGranter = UUID.Zero; |
281 | m_items.LockItemsForWrite(false); | ||
272 | m_part.ParentGroup.Scene.EventManager.TriggerRezScript( | 282 | m_part.ParentGroup.Scene.EventManager.TriggerRezScript( |
273 | m_part.LocalId, item.ItemID, String.Empty, startParam, postOnRez, engine, stateSource); | 283 | m_part.LocalId, item.ItemID, String.Empty, startParam, postOnRez, engine, stateSource); |
274 | m_part.ParentGroup.AddActiveScriptCount(1); | 284 | m_part.ParentGroup.AddActiveScriptCount(1); |
@@ -290,8 +300,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
290 | { | 300 | { |
291 | if (m_part.ParentGroup.m_savedScriptState != null) | 301 | if (m_part.ParentGroup.m_savedScriptState != null) |
292 | RestoreSavedScriptState(item.OldItemID, item.ItemID); | 302 | RestoreSavedScriptState(item.OldItemID, item.ItemID); |
303 | m_items.LockItemsForWrite(true); | ||
293 | m_items[item.ItemID].PermsMask = 0; | 304 | m_items[item.ItemID].PermsMask = 0; |
294 | m_items[item.ItemID].PermsGranter = UUID.Zero; | 305 | m_items[item.ItemID].PermsGranter = UUID.Zero; |
306 | m_items.LockItemsForWrite(false); | ||
295 | string script = Utils.BytesToString(asset.Data); | 307 | string script = Utils.BytesToString(asset.Data); |
296 | m_part.ParentGroup.Scene.EventManager.TriggerRezScript( | 308 | m_part.ParentGroup.Scene.EventManager.TriggerRezScript( |
297 | m_part.LocalId, item.ItemID, script, startParam, postOnRez, engine, stateSource); | 309 | m_part.LocalId, item.ItemID, script, startParam, postOnRez, engine, stateSource); |
@@ -367,14 +379,17 @@ namespace OpenSim.Region.Framework.Scenes | |||
367 | /// </param> | 379 | /// </param> |
368 | public void CreateScriptInstance(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource) | 380 | public void CreateScriptInstance(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource) |
369 | { | 381 | { |
370 | lock (m_items) | 382 | m_items.LockItemsForRead(true); |
383 | if (m_items.ContainsKey(itemId)) | ||
371 | { | 384 | { |
372 | if (m_items.ContainsKey(itemId)) | 385 | if (m_items.ContainsKey(itemId)) |
373 | { | 386 | { |
387 | m_items.LockItemsForRead(false); | ||
374 | CreateScriptInstance(m_items[itemId], startParam, postOnRez, engine, stateSource); | 388 | CreateScriptInstance(m_items[itemId], startParam, postOnRez, engine, stateSource); |
375 | } | 389 | } |
376 | else | 390 | else |
377 | { | 391 | { |
392 | m_items.LockItemsForRead(false); | ||
378 | m_log.ErrorFormat( | 393 | m_log.ErrorFormat( |
379 | "[PRIM INVENTORY]: " + | 394 | "[PRIM INVENTORY]: " + |
380 | "Couldn't start script with ID {0} since it couldn't be found for prim {1}, {2} at {3} in {4}", | 395 | "Couldn't start script with ID {0} since it couldn't be found for prim {1}, {2} at {3} in {4}", |
@@ -382,6 +397,15 @@ namespace OpenSim.Region.Framework.Scenes | |||
382 | m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName); | 397 | m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName); |
383 | } | 398 | } |
384 | } | 399 | } |
400 | else | ||
401 | { | ||
402 | m_items.LockItemsForRead(false); | ||
403 | m_log.ErrorFormat( | ||
404 | "[PRIM INVENTORY]: " + | ||
405 | "Couldn't start script with ID {0} since it couldn't be found for prim {1}, {2}", | ||
406 | itemId, m_part.Name, m_part.UUID); | ||
407 | } | ||
408 | |||
385 | } | 409 | } |
386 | 410 | ||
387 | /// <summary> | 411 | /// <summary> |
@@ -413,11 +437,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
413 | /// <returns></returns> | 437 | /// <returns></returns> |
414 | private bool InventoryContainsName(string name) | 438 | private bool InventoryContainsName(string name) |
415 | { | 439 | { |
416 | foreach (TaskInventoryItem item in Items.Values) | 440 | m_items.LockItemsForRead(true); |
441 | foreach (TaskInventoryItem item in m_items.Values) | ||
417 | { | 442 | { |
418 | if (item.Name == name) | 443 | if (item.Name == name) |
444 | { | ||
445 | m_items.LockItemsForRead(false); | ||
419 | return true; | 446 | return true; |
447 | } | ||
420 | } | 448 | } |
449 | m_items.LockItemsForRead(false); | ||
421 | return false; | 450 | return false; |
422 | } | 451 | } |
423 | 452 | ||
@@ -459,7 +488,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
459 | /// <param name="item"></param> | 488 | /// <param name="item"></param> |
460 | public void AddInventoryItemExclusive(TaskInventoryItem item, bool allowedDrop) | 489 | public void AddInventoryItemExclusive(TaskInventoryItem item, bool allowedDrop) |
461 | { | 490 | { |
491 | m_items.LockItemsForRead(true); | ||
462 | List<TaskInventoryItem> il = new List<TaskInventoryItem>(m_items.Values); | 492 | List<TaskInventoryItem> il = new List<TaskInventoryItem>(m_items.Values); |
493 | m_items.LockItemsForRead(false); | ||
463 | foreach (TaskInventoryItem i in il) | 494 | foreach (TaskInventoryItem i in il) |
464 | { | 495 | { |
465 | if (i.Name == item.Name) | 496 | if (i.Name == item.Name) |
@@ -496,15 +527,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
496 | item.ParentPartID = m_part.UUID; | 527 | item.ParentPartID = m_part.UUID; |
497 | item.Name = name; | 528 | item.Name = name; |
498 | 529 | ||
499 | lock (m_items) | 530 | m_items.LockItemsForWrite(true); |
500 | { | 531 | m_items.Add(item.ItemID, item); |
501 | m_items.Add(item.ItemID, item); | 532 | m_items.LockItemsForWrite(false); |
502 | |||
503 | if (allowedDrop) | 533 | if (allowedDrop) |
504 | m_part.TriggerScriptChangedEvent(Changed.ALLOWED_DROP); | 534 | m_part.TriggerScriptChangedEvent(Changed.ALLOWED_DROP); |
505 | else | 535 | else |
506 | m_part.TriggerScriptChangedEvent(Changed.INVENTORY); | 536 | m_part.TriggerScriptChangedEvent(Changed.INVENTORY); |
507 | } | 537 | |
508 | 538 | ||
509 | m_inventorySerial++; | 539 | m_inventorySerial++; |
510 | //m_inventorySerial += 2; | 540 | //m_inventorySerial += 2; |
@@ -521,14 +551,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
521 | /// <param name="items"></param> | 551 | /// <param name="items"></param> |
522 | public void RestoreInventoryItems(ICollection<TaskInventoryItem> items) | 552 | public void RestoreInventoryItems(ICollection<TaskInventoryItem> items) |
523 | { | 553 | { |
524 | lock (m_items) | 554 | m_items.LockItemsForWrite(true); |
555 | foreach (TaskInventoryItem item in items) | ||
525 | { | 556 | { |
526 | foreach (TaskInventoryItem item in items) | 557 | m_items.Add(item.ItemID, item); |
527 | { | 558 | m_part.TriggerScriptChangedEvent(Changed.INVENTORY); |
528 | m_items.Add(item.ItemID, item); | ||
529 | m_part.TriggerScriptChangedEvent(Changed.INVENTORY); | ||
530 | } | ||
531 | } | 559 | } |
560 | m_items.LockItemsForWrite(false); | ||
532 | 561 | ||
533 | m_inventorySerial++; | 562 | m_inventorySerial++; |
534 | } | 563 | } |
@@ -541,8 +570,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
541 | public TaskInventoryItem GetInventoryItem(UUID itemId) | 570 | public TaskInventoryItem GetInventoryItem(UUID itemId) |
542 | { | 571 | { |
543 | TaskInventoryItem item; | 572 | TaskInventoryItem item; |
573 | m_items.LockItemsForRead(true); | ||
544 | m_items.TryGetValue(itemId, out item); | 574 | m_items.TryGetValue(itemId, out item); |
545 | 575 | m_items.LockItemsForRead(false); | |
546 | return item; | 576 | return item; |
547 | } | 577 | } |
548 | 578 | ||
@@ -554,46 +584,46 @@ namespace OpenSim.Region.Framework.Scenes | |||
554 | /// <returns>false if the item did not exist, true if the update occurred successfully</returns> | 584 | /// <returns>false if the item did not exist, true if the update occurred successfully</returns> |
555 | public bool UpdateInventoryItem(TaskInventoryItem item) | 585 | public bool UpdateInventoryItem(TaskInventoryItem item) |
556 | { | 586 | { |
557 | lock (m_items) | 587 | m_items.LockItemsForWrite(true); |
588 | |||
589 | if (m_items.ContainsKey(item.ItemID)) | ||
558 | { | 590 | { |
559 | if (m_items.ContainsKey(item.ItemID)) | 591 | item.ParentID = m_part.UUID; |
592 | item.ParentPartID = m_part.UUID; | ||
593 | item.Flags = m_items[item.ItemID].Flags; | ||
594 | if (item.AssetID == UUID.Zero) | ||
560 | { | 595 | { |
561 | item.ParentID = m_part.UUID; | 596 | item.AssetID = m_items[item.ItemID].AssetID; |
562 | item.ParentPartID = m_part.UUID; | 597 | } |
563 | item.Flags = m_items[item.ItemID].Flags; | 598 | else if ((InventoryType)item.Type == InventoryType.Notecard) |
564 | if (item.AssetID == UUID.Zero) | 599 | { |
565 | { | 600 | ScenePresence presence = m_part.ParentGroup.Scene.GetScenePresence(item.OwnerID); |
566 | item.AssetID = m_items[item.ItemID].AssetID; | ||
567 | } | ||
568 | else if ((InventoryType)item.Type == InventoryType.Notecard) | ||
569 | { | ||
570 | ScenePresence presence = m_part.ParentGroup.Scene.GetScenePresence(item.OwnerID); | ||
571 | 601 | ||
572 | if (presence != null) | 602 | if (presence != null) |
573 | { | 603 | { |
574 | presence.ControllingClient.SendAgentAlertMessage( | 604 | presence.ControllingClient.SendAgentAlertMessage( |
575 | "Notecard saved", false); | 605 | "Notecard saved", false); |
576 | } | ||
577 | } | 606 | } |
607 | } | ||
578 | 608 | ||
579 | m_items[item.ItemID] = item; | 609 | m_items[item.ItemID] = item; |
580 | m_inventorySerial++; | 610 | m_inventorySerial++; |
581 | m_part.TriggerScriptChangedEvent(Changed.INVENTORY); | 611 | m_part.TriggerScriptChangedEvent(Changed.INVENTORY); |
582 | |||
583 | HasInventoryChanged = true; | ||
584 | m_part.ParentGroup.HasGroupChanged = true; | ||
585 | 612 | ||
586 | return true; | 613 | HasInventoryChanged = true; |
587 | } | 614 | m_part.ParentGroup.HasGroupChanged = true; |
588 | else | 615 | m_items.LockItemsForWrite(false); |
589 | { | 616 | return true; |
590 | m_log.ErrorFormat( | 617 | } |
591 | "[PRIM INVENTORY]: " + | 618 | else |
592 | "Tried to retrieve item ID {0} from prim {1}, {2} at {3} in {4} but the item does not exist in this inventory", | 619 | { |
593 | item.ItemID, m_part.Name, m_part.UUID, | 620 | m_log.ErrorFormat( |
594 | m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName); | 621 | "[PRIM INVENTORY]: " + |
595 | } | 622 | "Tried to retrieve item ID {0} from prim {1}, {2} at {3} in {4} but the item does not exist in this inventory", |
623 | item.ItemID, m_part.Name, m_part.UUID, | ||
624 | m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName); | ||
596 | } | 625 | } |
626 | m_items.LockItemsForWrite(false); | ||
597 | 627 | ||
598 | return false; | 628 | return false; |
599 | } | 629 | } |
@@ -606,52 +636,54 @@ namespace OpenSim.Region.Framework.Scenes | |||
606 | /// in this prim's inventory.</returns> | 636 | /// in this prim's inventory.</returns> |
607 | public int RemoveInventoryItem(UUID itemID) | 637 | public int RemoveInventoryItem(UUID itemID) |
608 | { | 638 | { |
609 | lock (m_items) | 639 | m_items.LockItemsForRead(true); |
640 | |||
641 | if (m_items.ContainsKey(itemID)) | ||
610 | { | 642 | { |
611 | if (m_items.ContainsKey(itemID)) | 643 | int type = m_items[itemID].InvType; |
644 | m_items.LockItemsForRead(false); | ||
645 | if (type == 10) // Script | ||
612 | { | 646 | { |
613 | int type = m_items[itemID].InvType; | 647 | m_part.ParentGroup.Scene.EventManager.TriggerRemoveScript(m_part.LocalId, itemID); |
614 | if (type == 10) // Script | 648 | } |
615 | { | 649 | m_items.LockItemsForWrite(true); |
616 | m_part.ParentGroup.Scene.EventManager.TriggerRemoveScript(m_part.LocalId, itemID); | 650 | m_items.Remove(itemID); |
617 | } | 651 | m_items.LockItemsForWrite(false); |
618 | m_items.Remove(itemID); | 652 | m_inventorySerial++; |
619 | m_inventorySerial++; | 653 | m_part.TriggerScriptChangedEvent(Changed.INVENTORY); |
620 | m_part.TriggerScriptChangedEvent(Changed.INVENTORY); | ||
621 | |||
622 | HasInventoryChanged = true; | ||
623 | m_part.ParentGroup.HasGroupChanged = true; | ||
624 | 654 | ||
625 | int scriptcount = 0; | 655 | HasInventoryChanged = true; |
626 | lock (m_items) | 656 | m_part.ParentGroup.HasGroupChanged = true; |
627 | { | ||
628 | foreach (TaskInventoryItem item in m_items.Values) | ||
629 | { | ||
630 | if (item.Type == 10) | ||
631 | { | ||
632 | scriptcount++; | ||
633 | } | ||
634 | } | ||
635 | } | ||
636 | 657 | ||
637 | if (scriptcount <= 0) | 658 | int scriptcount = 0; |
659 | m_items.LockItemsForRead(true); | ||
660 | foreach (TaskInventoryItem item in m_items.Values) | ||
661 | { | ||
662 | if (item.Type == 10) | ||
638 | { | 663 | { |
639 | m_part.RemFlag(PrimFlags.Scripted); | 664 | scriptcount++; |
640 | } | 665 | } |
641 | |||
642 | m_part.ScheduleFullUpdate(); | ||
643 | |||
644 | return type; | ||
645 | } | 666 | } |
646 | else | 667 | m_items.LockItemsForRead(false); |
668 | |||
669 | |||
670 | if (scriptcount <= 0) | ||
647 | { | 671 | { |
648 | m_log.ErrorFormat( | 672 | m_part.RemFlag(PrimFlags.Scripted); |
649 | "[PRIM INVENTORY]: " + | ||
650 | "Tried to remove item ID {0} from prim {1}, {2} at {3} in {4} but the item does not exist in this inventory", | ||
651 | itemID, m_part.Name, m_part.UUID, | ||
652 | m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName); | ||
653 | } | 673 | } |
674 | |||
675 | m_part.ScheduleFullUpdate(); | ||
676 | |||
677 | return type; | ||
678 | } | ||
679 | else | ||
680 | { | ||
681 | m_log.ErrorFormat( | ||
682 | "[PRIM INVENTORY]: " + | ||
683 | "Tried to remove item ID {0} from prim {1}, {2} but the item does not exist in this inventory", | ||
684 | itemID, m_part.Name, m_part.UUID); | ||
654 | } | 685 | } |
686 | m_items.LockItemsForWrite(false); | ||
655 | 687 | ||
656 | return -1; | 688 | return -1; |
657 | } | 689 | } |
@@ -704,52 +736,53 @@ namespace OpenSim.Region.Framework.Scenes | |||
704 | // isn't available (such as drag from prim inventory to agent inventory) | 736 | // isn't available (such as drag from prim inventory to agent inventory) |
705 | InventoryStringBuilder invString = new InventoryStringBuilder(m_part.UUID, UUID.Zero); | 737 | InventoryStringBuilder invString = new InventoryStringBuilder(m_part.UUID, UUID.Zero); |
706 | 738 | ||
707 | lock (m_items) | 739 | m_items.LockItemsForRead(true); |
740 | |||
741 | foreach (TaskInventoryItem item in m_items.Values) | ||
708 | { | 742 | { |
709 | foreach (TaskInventoryItem item in m_items.Values) | 743 | UUID ownerID = item.OwnerID; |
710 | { | 744 | uint everyoneMask = 0; |
711 | UUID ownerID = item.OwnerID; | 745 | uint baseMask = item.BasePermissions; |
712 | uint everyoneMask = 0; | 746 | uint ownerMask = item.CurrentPermissions; |
713 | uint baseMask = item.BasePermissions; | ||
714 | uint ownerMask = item.CurrentPermissions; | ||
715 | 747 | ||
716 | invString.AddItemStart(); | 748 | invString.AddItemStart(); |
717 | invString.AddNameValueLine("item_id", item.ItemID.ToString()); | 749 | invString.AddNameValueLine("item_id", item.ItemID.ToString()); |
718 | invString.AddNameValueLine("parent_id", m_part.UUID.ToString()); | 750 | invString.AddNameValueLine("parent_id", m_part.UUID.ToString()); |
719 | 751 | ||
720 | invString.AddPermissionsStart(); | 752 | invString.AddPermissionsStart(); |
721 | 753 | ||
722 | invString.AddNameValueLine("base_mask", Utils.UIntToHexString(baseMask)); | 754 | invString.AddNameValueLine("base_mask", Utils.UIntToHexString(baseMask)); |
723 | invString.AddNameValueLine("owner_mask", Utils.UIntToHexString(ownerMask)); | 755 | invString.AddNameValueLine("owner_mask", Utils.UIntToHexString(ownerMask)); |
724 | invString.AddNameValueLine("group_mask", Utils.UIntToHexString(0)); | 756 | invString.AddNameValueLine("group_mask", Utils.UIntToHexString(0)); |
725 | invString.AddNameValueLine("everyone_mask", Utils.UIntToHexString(everyoneMask)); | 757 | invString.AddNameValueLine("everyone_mask", Utils.UIntToHexString(everyoneMask)); |
726 | invString.AddNameValueLine("next_owner_mask", Utils.UIntToHexString(item.NextPermissions)); | 758 | invString.AddNameValueLine("next_owner_mask", Utils.UIntToHexString(item.NextPermissions)); |
727 | 759 | ||
728 | invString.AddNameValueLine("creator_id", item.CreatorID.ToString()); | 760 | invString.AddNameValueLine("creator_id", item.CreatorID.ToString()); |
729 | invString.AddNameValueLine("owner_id", ownerID.ToString()); | 761 | invString.AddNameValueLine("owner_id", ownerID.ToString()); |
730 | 762 | ||
731 | invString.AddNameValueLine("last_owner_id", item.LastOwnerID.ToString()); | 763 | invString.AddNameValueLine("last_owner_id", item.LastOwnerID.ToString()); |
732 | 764 | ||
733 | invString.AddNameValueLine("group_id", item.GroupID.ToString()); | 765 | invString.AddNameValueLine("group_id", item.GroupID.ToString()); |
734 | invString.AddSectionEnd(); | 766 | invString.AddSectionEnd(); |
735 | 767 | ||
736 | invString.AddNameValueLine("asset_id", item.AssetID.ToString()); | 768 | invString.AddNameValueLine("asset_id", item.AssetID.ToString()); |
737 | invString.AddNameValueLine("type", TaskInventoryItem.Types[item.Type]); | 769 | invString.AddNameValueLine("type", TaskInventoryItem.Types[item.Type]); |
738 | invString.AddNameValueLine("inv_type", TaskInventoryItem.InvTypes[item.InvType]); | 770 | invString.AddNameValueLine("inv_type", TaskInventoryItem.InvTypes[item.InvType]); |
739 | invString.AddNameValueLine("flags", Utils.UIntToHexString(item.Flags)); | 771 | invString.AddNameValueLine("flags", Utils.UIntToHexString(item.Flags)); |
740 | 772 | ||
741 | invString.AddSaleStart(); | 773 | invString.AddSaleStart(); |
742 | invString.AddNameValueLine("sale_type", "not"); | 774 | invString.AddNameValueLine("sale_type", "not"); |
743 | invString.AddNameValueLine("sale_price", "0"); | 775 | invString.AddNameValueLine("sale_price", "0"); |
744 | invString.AddSectionEnd(); | 776 | invString.AddSectionEnd(); |
745 | 777 | ||
746 | invString.AddNameValueLine("name", item.Name + "|"); | 778 | invString.AddNameValueLine("name", item.Name + "|"); |
747 | invString.AddNameValueLine("desc", item.Description + "|"); | 779 | invString.AddNameValueLine("desc", item.Description + "|"); |
748 | 780 | ||
749 | invString.AddNameValueLine("creation_date", item.CreationDate.ToString()); | 781 | invString.AddNameValueLine("creation_date", item.CreationDate.ToString()); |
750 | invString.AddSectionEnd(); | 782 | invString.AddSectionEnd(); |
751 | } | ||
752 | } | 783 | } |
784 | int count = m_items.Count; | ||
785 | m_items.LockItemsForRead(false); | ||
753 | 786 | ||
754 | fileData = Utils.StringToBytes(invString.BuildString); | 787 | fileData = Utils.StringToBytes(invString.BuildString); |
755 | 788 | ||
@@ -770,10 +803,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
770 | { | 803 | { |
771 | if (HasInventoryChanged) | 804 | if (HasInventoryChanged) |
772 | { | 805 | { |
773 | lock (Items) | 806 | Items.LockItemsForRead(true); |
774 | { | 807 | datastore.StorePrimInventory(m_part.UUID, Items.Values); |
775 | datastore.StorePrimInventory(m_part.UUID, Items.Values); | 808 | Items.LockItemsForRead(false); |
776 | } | ||
777 | 809 | ||
778 | HasInventoryChanged = false; | 810 | HasInventoryChanged = false; |
779 | } | 811 | } |
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 8545425..f36c1a9 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs | |||
@@ -73,7 +73,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
73 | // { | 73 | // { |
74 | // m_log.Debug("[ScenePresence] Destructor called"); | 74 | // m_log.Debug("[ScenePresence] Destructor called"); |
75 | // } | 75 | // } |
76 | 76 | ||
77 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 77 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
78 | 78 | ||
79 | private static readonly byte[] BAKE_INDICES = new byte[] { 8, 9, 10, 11, 19, 20 }; | 79 | private static readonly byte[] BAKE_INDICES = new byte[] { 8, 9, 10, 11, 19, 20 }; |
@@ -89,7 +89,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
89 | /// rotation, prim cut, prim twist, prim taper, and prim shear. See mantis | 89 | /// rotation, prim cut, prim twist, prim taper, and prim shear. See mantis |
90 | /// issue #1716 | 90 | /// issue #1716 |
91 | /// </summary> | 91 | /// </summary> |
92 | private static readonly Vector3 SIT_TARGET_ADJUSTMENT = new Vector3(0.1f, 0.0f, 0.3f); | 92 | // private static readonly Vector3 SIT_TARGET_ADJUSTMENT = new Vector3(0.1f, 0.0f, 0.3f); |
93 | // Value revised by KF 091121 by comparison with SL. | ||
94 | private static readonly Vector3 SIT_TARGET_ADJUSTMENT = new Vector3(0.0f, 0.0f, 0.418f); | ||
93 | 95 | ||
94 | public UUID currentParcelUUID = UUID.Zero; | 96 | public UUID currentParcelUUID = UUID.Zero; |
95 | 97 | ||
@@ -113,8 +115,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
113 | public Vector3 lastKnownAllowedPosition; | 115 | public Vector3 lastKnownAllowedPosition; |
114 | public bool sentMessageAboutRestrictedParcelFlyingDown; | 116 | public bool sentMessageAboutRestrictedParcelFlyingDown; |
115 | public Vector4 CollisionPlane = Vector4.UnitW; | 117 | public Vector4 CollisionPlane = Vector4.UnitW; |
116 | 118 | ||
117 | private Vector3 m_lastPosition; | 119 | private Vector3 m_avInitialPos; // used to calculate unscripted sit rotation |
120 | private Vector3 m_avUnscriptedSitPos; // for non-scripted prims | ||
121 | private Vector3 m_lastPosition; | ||
122 | private Vector3 m_lastWorldPosition; | ||
118 | private Quaternion m_lastRotation; | 123 | private Quaternion m_lastRotation; |
119 | private Vector3 m_lastVelocity; | 124 | private Vector3 m_lastVelocity; |
120 | //private int m_lastTerseSent; | 125 | //private int m_lastTerseSent; |
@@ -124,7 +129,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
124 | private Vector3? m_forceToApply; | 129 | private Vector3? m_forceToApply; |
125 | private uint m_requestedSitTargetID; | 130 | private uint m_requestedSitTargetID; |
126 | private UUID m_requestedSitTargetUUID; | 131 | private UUID m_requestedSitTargetUUID; |
127 | public bool SitGround = false; | ||
128 | 132 | ||
129 | private SendCourseLocationsMethod m_sendCourseLocationsMethod; | 133 | private SendCourseLocationsMethod m_sendCourseLocationsMethod; |
130 | 134 | ||
@@ -146,7 +150,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
146 | private int m_perfMonMS; | 150 | private int m_perfMonMS; |
147 | 151 | ||
148 | private bool m_setAlwaysRun; | 152 | private bool m_setAlwaysRun; |
149 | |||
150 | private bool m_forceFly; | 153 | private bool m_forceFly; |
151 | private bool m_flyDisabled; | 154 | private bool m_flyDisabled; |
152 | 155 | ||
@@ -170,7 +173,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
170 | protected RegionInfo m_regionInfo; | 173 | protected RegionInfo m_regionInfo; |
171 | protected ulong crossingFromRegion; | 174 | protected ulong crossingFromRegion; |
172 | 175 | ||
173 | private readonly Vector3[] Dir_Vectors = new Vector3[9]; | 176 | private readonly Vector3[] Dir_Vectors = new Vector3[11]; |
177 | private bool m_isNudging = false; | ||
174 | 178 | ||
175 | // Position of agent's camera in world (region cordinates) | 179 | // Position of agent's camera in world (region cordinates) |
176 | protected Vector3 m_CameraCenter; | 180 | protected Vector3 m_CameraCenter; |
@@ -195,6 +199,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
195 | private bool m_autopilotMoving; | 199 | private bool m_autopilotMoving; |
196 | private Vector3 m_autoPilotTarget; | 200 | private Vector3 m_autoPilotTarget; |
197 | private bool m_sitAtAutoTarget; | 201 | private bool m_sitAtAutoTarget; |
202 | private Vector3 m_initialSitTarget; //KF: First estimate of where to sit | ||
198 | 203 | ||
199 | private string m_nextSitAnimation = String.Empty; | 204 | private string m_nextSitAnimation = String.Empty; |
200 | 205 | ||
@@ -205,6 +210,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
205 | private bool m_followCamAuto; | 210 | private bool m_followCamAuto; |
206 | 211 | ||
207 | private int m_movementUpdateCount; | 212 | private int m_movementUpdateCount; |
213 | private int m_lastColCount = -1; //KF: Look for Collision chnages | ||
214 | private int m_updateCount = 0; //KF: Update Anims for a while | ||
215 | private static readonly int UPDATE_COUNT = 10; // how many frames to update for | ||
208 | 216 | ||
209 | private const int NumMovementsBetweenRayCast = 5; | 217 | private const int NumMovementsBetweenRayCast = 5; |
210 | 218 | ||
@@ -235,7 +243,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
235 | DIR_CONTROL_FLAG_UP = AgentManager.ControlFlags.AGENT_CONTROL_UP_POS, | 243 | DIR_CONTROL_FLAG_UP = AgentManager.ControlFlags.AGENT_CONTROL_UP_POS, |
236 | DIR_CONTROL_FLAG_DOWN = AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG, | 244 | DIR_CONTROL_FLAG_DOWN = AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG, |
237 | DIR_CONTROL_FLAG_FORWARD_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_POS, | 245 | DIR_CONTROL_FLAG_FORWARD_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_POS, |
238 | DIR_CONTROL_FLAG_BACKWARD_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_NEG, | 246 | DIR_CONTROL_FLAG_BACK_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_NEG, |
247 | DIR_CONTROL_FLAG_LEFT_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_POS, | ||
248 | DIR_CONTROL_FLAG_RIGHT_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_NEG, | ||
239 | DIR_CONTROL_FLAG_DOWN_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG | 249 | DIR_CONTROL_FLAG_DOWN_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG |
240 | } | 250 | } |
241 | 251 | ||
@@ -661,10 +671,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
661 | 671 | ||
662 | 672 | ||
663 | AdjustKnownSeeds(); | 673 | AdjustKnownSeeds(); |
664 | |||
665 | // TODO: I think, this won't send anything, as we are still a child here... | ||
666 | Animator.TrySetMovementAnimation("STAND"); | 674 | Animator.TrySetMovementAnimation("STAND"); |
667 | |||
668 | // we created a new ScenePresence (a new child agent) in a fresh region. | 675 | // we created a new ScenePresence (a new child agent) in a fresh region. |
669 | // Request info about all the (root) agents in this region | 676 | // Request info about all the (root) agents in this region |
670 | // Note: This won't send data *to* other clients in that region (children don't send) | 677 | // Note: This won't send data *to* other clients in that region (children don't send) |
@@ -720,25 +727,47 @@ namespace OpenSim.Region.Framework.Scenes | |||
720 | Dir_Vectors[3] = -Vector3.UnitY; //RIGHT | 727 | Dir_Vectors[3] = -Vector3.UnitY; //RIGHT |
721 | Dir_Vectors[4] = Vector3.UnitZ; //UP | 728 | Dir_Vectors[4] = Vector3.UnitZ; //UP |
722 | Dir_Vectors[5] = -Vector3.UnitZ; //DOWN | 729 | Dir_Vectors[5] = -Vector3.UnitZ; //DOWN |
723 | Dir_Vectors[8] = new Vector3(0f, 0f, -0.5f); //DOWN_Nudge | 730 | Dir_Vectors[6] = new Vector3(0.5f, 0f, 0f); //FORWARD_NUDGE |
724 | Dir_Vectors[6] = Vector3.UnitX*2; //FORWARD | 731 | Dir_Vectors[7] = new Vector3(-0.5f, 0f, 0f); //BACK_NUDGE |
725 | Dir_Vectors[7] = -Vector3.UnitX; //BACK | 732 | Dir_Vectors[8] = new Vector3(0f, 0.5f, 0f); //LEFT_NUDGE |
733 | Dir_Vectors[9] = new Vector3(0f, -0.5f, 0f); //RIGHT_NUDGE | ||
734 | Dir_Vectors[10] = new Vector3(0f, 0f, -0.5f); //DOWN_Nudge | ||
726 | } | 735 | } |
727 | 736 | ||
728 | private Vector3[] GetWalkDirectionVectors() | 737 | private Vector3[] GetWalkDirectionVectors() |
729 | { | 738 | { |
730 | Vector3[] vector = new Vector3[9]; | 739 | Vector3[] vector = new Vector3[11]; |
731 | vector[0] = new Vector3(m_CameraUpAxis.Z, 0f, -m_CameraAtAxis.Z); //FORWARD | 740 | vector[0] = new Vector3(m_CameraUpAxis.Z, 0f, -m_CameraAtAxis.Z); //FORWARD |
732 | vector[1] = new Vector3(-m_CameraUpAxis.Z, 0f, m_CameraAtAxis.Z); //BACK | 741 | vector[1] = new Vector3(-m_CameraUpAxis.Z, 0f, m_CameraAtAxis.Z); //BACK |
733 | vector[2] = Vector3.UnitY; //LEFT | 742 | vector[2] = Vector3.UnitY; //LEFT |
734 | vector[3] = -Vector3.UnitY; //RIGHT | 743 | vector[3] = -Vector3.UnitY; //RIGHT |
735 | vector[4] = new Vector3(m_CameraAtAxis.Z, 0f, m_CameraUpAxis.Z); //UP | 744 | vector[4] = new Vector3(m_CameraAtAxis.Z, 0f, m_CameraUpAxis.Z); //UP |
736 | vector[5] = new Vector3(-m_CameraAtAxis.Z, 0f, -m_CameraUpAxis.Z); //DOWN | 745 | vector[5] = new Vector3(-m_CameraAtAxis.Z, 0f, -m_CameraUpAxis.Z); //DOWN |
737 | vector[8] = new Vector3(-m_CameraAtAxis.Z, 0f, -m_CameraUpAxis.Z); //DOWN_Nudge | 746 | vector[6] = new Vector3(m_CameraUpAxis.Z, 0f, -m_CameraAtAxis.Z); //FORWARD_NUDGE |
738 | vector[6] = (new Vector3(m_CameraUpAxis.Z, 0f, -m_CameraAtAxis.Z) * 2); //FORWARD Nudge | 747 | vector[7] = new Vector3(-m_CameraUpAxis.Z, 0f, m_CameraAtAxis.Z); //BACK_NUDGE |
739 | vector[7] = new Vector3(-m_CameraUpAxis.Z, 0f, m_CameraAtAxis.Z); //BACK Nudge | 748 | vector[8] = Vector3.UnitY; //LEFT_NUDGE |
749 | vector[9] = -Vector3.UnitY; //RIGHT_NUDGE | ||
750 | vector[10] = new Vector3(-m_CameraAtAxis.Z, 0f, -m_CameraUpAxis.Z); //DOWN_NUDGE | ||
740 | return vector; | 751 | return vector; |
741 | } | 752 | } |
753 | |||
754 | private bool[] GetDirectionIsNudge() | ||
755 | { | ||
756 | bool[] isNudge = new bool[11]; | ||
757 | isNudge[0] = false; //FORWARD | ||
758 | isNudge[1] = false; //BACK | ||
759 | isNudge[2] = false; //LEFT | ||
760 | isNudge[3] = false; //RIGHT | ||
761 | isNudge[4] = false; //UP | ||
762 | isNudge[5] = false; //DOWN | ||
763 | isNudge[6] = true; //FORWARD_NUDGE | ||
764 | isNudge[7] = true; //BACK_NUDGE | ||
765 | isNudge[8] = true; //LEFT_NUDGE | ||
766 | isNudge[9] = true; //RIGHT_NUDGE | ||
767 | isNudge[10] = true; //DOWN_Nudge | ||
768 | return isNudge; | ||
769 | } | ||
770 | |||
742 | 771 | ||
743 | #endregion | 772 | #endregion |
744 | 773 | ||
@@ -807,9 +836,24 @@ namespace OpenSim.Region.Framework.Scenes | |||
807 | { | 836 | { |
808 | Border crossedBorder = m_scene.GetCrossedBorder(pos, Cardinals.N); | 837 | Border crossedBorder = m_scene.GetCrossedBorder(pos, Cardinals.N); |
809 | pos.Y = crossedBorder.BorderLine.Z - 1; | 838 | pos.Y = crossedBorder.BorderLine.Z - 1; |
839 | } | ||
840 | |||
841 | //If they're TP'ing in or logging in, we haven't had time to add any known child regions yet. | ||
842 | //This has the unfortunate consequence that if somebody is TP'ing who is already a child agent, | ||
843 | //they'll bypass the landing point. But I can't think of any decent way of fixing this. | ||
844 | if (KnownChildRegionHandles.Count == 0) | ||
845 | { | ||
846 | ILandObject land = m_scene.LandChannel.GetLandObject(pos.X, pos.Y); | ||
847 | if (land != null) | ||
848 | { | ||
849 | //Don't restrict gods, estate managers, or land owners to the TP point. This behaviour mimics agni. | ||
850 | if (land.LandData.LandingType == (byte)1 && land.LandData.UserLocation != Vector3.Zero && m_godlevel < 200 && !m_scene.RegionInfo.EstateSettings.IsEstateManager(m_uuid) && land.LandData.OwnerID != m_uuid) | ||
851 | { | ||
852 | pos = land.LandData.UserLocation; | ||
853 | } | ||
854 | } | ||
810 | } | 855 | } |
811 | 856 | ||
812 | |||
813 | if (pos.X < 0 || pos.Y < 0 || pos.Z < 0) | 857 | if (pos.X < 0 || pos.Y < 0 || pos.Z < 0) |
814 | { | 858 | { |
815 | Vector3 emergencyPos = new Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 128); | 859 | Vector3 emergencyPos = new Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 128); |
@@ -944,9 +988,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
944 | public void Teleport(Vector3 pos) | 988 | public void Teleport(Vector3 pos) |
945 | { | 989 | { |
946 | bool isFlying = false; | 990 | bool isFlying = false; |
947 | if (m_physicsActor != null) | ||
948 | isFlying = m_physicsActor.Flying; | ||
949 | 991 | ||
992 | if (m_physicsActor != null) | ||
993 | isFlying = m_physicsActor.Flying; | ||
994 | |||
950 | RemoveFromPhysicalScene(); | 995 | RemoveFromPhysicalScene(); |
951 | Velocity = Vector3.Zero; | 996 | Velocity = Vector3.Zero; |
952 | AbsolutePosition = pos; | 997 | AbsolutePosition = pos; |
@@ -957,7 +1002,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
957 | SetHeight(m_appearance.AvatarHeight); | 1002 | SetHeight(m_appearance.AvatarHeight); |
958 | } | 1003 | } |
959 | 1004 | ||
960 | SendTerseUpdateToAllClients(); | 1005 | SendTerseUpdateToAllClients(); |
1006 | |||
961 | } | 1007 | } |
962 | 1008 | ||
963 | public void TeleportWithMomentum(Vector3 pos) | 1009 | public void TeleportWithMomentum(Vector3 pos) |
@@ -1002,7 +1048,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
1002 | { | 1048 | { |
1003 | AbsolutePosition = AbsolutePosition + new Vector3(0f, 0f, (1.56f / 6f)); | 1049 | AbsolutePosition = AbsolutePosition + new Vector3(0f, 0f, (1.56f / 6f)); |
1004 | } | 1050 | } |
1005 | 1051 | ||
1052 | m_updateCount = UPDATE_COUNT; //KF: Trigger Anim updates to catch falling anim. | ||
1053 | |||
1006 | ControllingClient.SendAvatarTerseUpdate(new SendAvatarTerseData(m_rootRegionHandle, (ushort)(m_scene.TimeDilation * ushort.MaxValue), LocalId, | 1054 | ControllingClient.SendAvatarTerseUpdate(new SendAvatarTerseData(m_rootRegionHandle, (ushort)(m_scene.TimeDilation * ushort.MaxValue), LocalId, |
1007 | AbsolutePosition, Velocity, Vector3.Zero, m_bodyRot, new Vector4(0,0,1,AbsolutePosition.Z - 0.5f), m_uuid, null, GetUpdatePriority(ControllingClient))); | 1055 | AbsolutePosition, Velocity, Vector3.Zero, m_bodyRot, new Vector4(0,0,1,AbsolutePosition.Z - 0.5f), m_uuid, null, GetUpdatePriority(ControllingClient))); |
1008 | } | 1056 | } |
@@ -1237,7 +1285,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
1237 | m_scene.PhysicsScene.RaycastWorld(m_pos, Vector3.Normalize(m_CameraCenter - posAdjusted), Vector3.Distance(m_CameraCenter, posAdjusted) + 0.3f, RayCastCameraCallback); | 1285 | m_scene.PhysicsScene.RaycastWorld(m_pos, Vector3.Normalize(m_CameraCenter - posAdjusted), Vector3.Distance(m_CameraCenter, posAdjusted) + 0.3f, RayCastCameraCallback); |
1238 | } | 1286 | } |
1239 | } | 1287 | } |
1240 | |||
1241 | lock (scriptedcontrols) | 1288 | lock (scriptedcontrols) |
1242 | { | 1289 | { |
1243 | if (scriptedcontrols.Count > 0) | 1290 | if (scriptedcontrols.Count > 0) |
@@ -1252,12 +1299,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
1252 | 1299 | ||
1253 | if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_SIT_ON_GROUND) != 0) | 1300 | if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_SIT_ON_GROUND) != 0) |
1254 | { | 1301 | { |
1255 | // TODO: This doesn't prevent the user from walking yet. | 1302 | m_updateCount = 0; // Kill animation update burst so that the SIT_G.. will stick. |
1256 | // Setting parent ID would fix this, if we knew what value | 1303 | Animator.TrySetMovementAnimation("SIT_GROUND_CONSTRAINED"); |
1257 | // to use. Or we could add a m_isSitting variable. | ||
1258 | //Animator.TrySetMovementAnimation("SIT_GROUND_CONSTRAINED"); | ||
1259 | SitGround = true; | ||
1260 | |||
1261 | } | 1304 | } |
1262 | 1305 | ||
1263 | // In the future, these values might need to go global. | 1306 | // In the future, these values might need to go global. |
@@ -1301,6 +1344,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
1301 | update_rotation = true; | 1344 | update_rotation = true; |
1302 | } | 1345 | } |
1303 | 1346 | ||
1347 | //guilty until proven innocent.. | ||
1348 | bool Nudging = true; | ||
1349 | //Basically, if there is at least one non-nudge control then we don't need | ||
1350 | //to worry about stopping the avatar | ||
1351 | |||
1304 | if (m_parentID == 0) | 1352 | if (m_parentID == 0) |
1305 | { | 1353 | { |
1306 | bool bAllowUpdateMoveToPosition = false; | 1354 | bool bAllowUpdateMoveToPosition = false; |
@@ -1315,9 +1363,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
1315 | else | 1363 | else |
1316 | dirVectors = Dir_Vectors; | 1364 | dirVectors = Dir_Vectors; |
1317 | 1365 | ||
1318 | // The fact that m_movementflag is a byte needs to be fixed | 1366 | bool[] isNudge = GetDirectionIsNudge(); |
1319 | // it really should be a uint | 1367 | |
1320 | uint nudgehack = 250; | 1368 | |
1369 | |||
1370 | |||
1371 | |||
1321 | foreach (Dir_ControlFlags DCF in DIR_CONTROL_FLAGS) | 1372 | foreach (Dir_ControlFlags DCF in DIR_CONTROL_FLAGS) |
1322 | { | 1373 | { |
1323 | if (((uint)flags & (uint)DCF) != 0) | 1374 | if (((uint)flags & (uint)DCF) != 0) |
@@ -1327,40 +1378,28 @@ namespace OpenSim.Region.Framework.Scenes | |||
1327 | try | 1378 | try |
1328 | { | 1379 | { |
1329 | agent_control_v3 += dirVectors[i]; | 1380 | agent_control_v3 += dirVectors[i]; |
1330 | //m_log.DebugFormat("[Motion]: {0}, {1}",i, dirVectors[i]); | 1381 | if (isNudge[i] == false) |
1382 | { | ||
1383 | Nudging = false; | ||
1384 | } | ||
1331 | } | 1385 | } |
1332 | catch (IndexOutOfRangeException) | 1386 | catch (IndexOutOfRangeException) |
1333 | { | 1387 | { |
1334 | // Why did I get this? | 1388 | // Why did I get this? |
1335 | } | 1389 | } |
1336 | 1390 | ||
1337 | if ((m_movementflag & (byte)(uint)DCF) == 0) | 1391 | if ((m_movementflag & (uint)DCF) == 0) |
1338 | { | 1392 | { |
1339 | if (DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_BACKWARD_NUDGE) | ||
1340 | { | ||
1341 | m_movementflag |= (byte)nudgehack; | ||
1342 | } | ||
1343 | m_movementflag += (byte)(uint)DCF; | 1393 | m_movementflag += (byte)(uint)DCF; |
1344 | update_movementflag = true; | 1394 | update_movementflag = true; |
1345 | } | 1395 | } |
1346 | } | 1396 | } |
1347 | else | 1397 | else |
1348 | { | 1398 | { |
1349 | if ((m_movementflag & (byte)(uint)DCF) != 0 || | 1399 | if ((m_movementflag & (uint)DCF) != 0) |
1350 | ((DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_BACKWARD_NUDGE) | ||
1351 | && ((m_movementflag & (byte)nudgehack) == nudgehack)) | ||
1352 | ) // This or is for Nudge forward | ||
1353 | { | 1400 | { |
1354 | m_movementflag -= ((byte)(uint)DCF); | 1401 | m_movementflag -= (byte)(uint)DCF; |
1355 | |||
1356 | update_movementflag = true; | 1402 | update_movementflag = true; |
1357 | /* | ||
1358 | if ((DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_BACKWARD_NUDGE) | ||
1359 | && ((m_movementflag & (byte)nudgehack) == nudgehack)) | ||
1360 | { | ||
1361 | m_log.Debug("Removed Hack flag"); | ||
1362 | } | ||
1363 | */ | ||
1364 | } | 1403 | } |
1365 | else | 1404 | else |
1366 | { | 1405 | { |
@@ -1404,6 +1443,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
1404 | // Ignore z component of vector | 1443 | // Ignore z component of vector |
1405 | Vector3 LocalVectorToTarget2D = new Vector3((float)(LocalVectorToTarget3D.X), (float)(LocalVectorToTarget3D.Y), 0f); | 1444 | Vector3 LocalVectorToTarget2D = new Vector3((float)(LocalVectorToTarget3D.X), (float)(LocalVectorToTarget3D.Y), 0f); |
1406 | LocalVectorToTarget2D.Normalize(); | 1445 | LocalVectorToTarget2D.Normalize(); |
1446 | |||
1447 | //We're not nudging | ||
1448 | Nudging = false; | ||
1407 | agent_control_v3 += LocalVectorToTarget2D; | 1449 | agent_control_v3 += LocalVectorToTarget2D; |
1408 | 1450 | ||
1409 | // update avatar movement flags. the avatar coordinate system is as follows: | 1451 | // update avatar movement flags. the avatar coordinate system is as follows: |
@@ -1492,13 +1534,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
1492 | // m_log.DebugFormat( | 1534 | // m_log.DebugFormat( |
1493 | // "In {0} adding velocity to {1} of {2}", m_scene.RegionInfo.RegionName, Name, agent_control_v3); | 1535 | // "In {0} adding velocity to {1} of {2}", m_scene.RegionInfo.RegionName, Name, agent_control_v3); |
1494 | 1536 | ||
1495 | AddNewMovement(agent_control_v3, q); | 1537 | AddNewMovement(agent_control_v3, q, Nudging); |
1496 | 1538 | ||
1497 | 1539 | ||
1498 | } | 1540 | } |
1499 | } | 1541 | } |
1500 | 1542 | ||
1501 | if (update_movementflag && ((flags & AgentManager.ControlFlags.AGENT_CONTROL_SIT_ON_GROUND) == 0) && (m_parentID == 0) && !SitGround) | 1543 | if (update_movementflag) |
1502 | Animator.UpdateMovementAnimations(); | 1544 | Animator.UpdateMovementAnimations(); |
1503 | 1545 | ||
1504 | m_scene.EventManager.TriggerOnClientMovement(this); | 1546 | m_scene.EventManager.TriggerOnClientMovement(this); |
@@ -1513,7 +1555,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
1513 | m_sitAtAutoTarget = false; | 1555 | m_sitAtAutoTarget = false; |
1514 | PrimitiveBaseShape proxy = PrimitiveBaseShape.Default; | 1556 | PrimitiveBaseShape proxy = PrimitiveBaseShape.Default; |
1515 | //proxy.PCode = (byte)PCode.ParticleSystem; | 1557 | //proxy.PCode = (byte)PCode.ParticleSystem; |
1516 | |||
1517 | proxyObjectGroup = new SceneObjectGroup(UUID, Pos, Rotation, proxy); | 1558 | proxyObjectGroup = new SceneObjectGroup(UUID, Pos, Rotation, proxy); |
1518 | proxyObjectGroup.AttachToScene(m_scene); | 1559 | proxyObjectGroup.AttachToScene(m_scene); |
1519 | 1560 | ||
@@ -1555,7 +1596,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1555 | } | 1596 | } |
1556 | m_moveToPositionInProgress = true; | 1597 | m_moveToPositionInProgress = true; |
1557 | m_moveToPositionTarget = new Vector3(locx, locy, locz); | 1598 | m_moveToPositionTarget = new Vector3(locx, locy, locz); |
1558 | } | 1599 | } |
1559 | catch (Exception ex) | 1600 | catch (Exception ex) |
1560 | { | 1601 | { |
1561 | //Why did I get this error? | 1602 | //Why did I get this error? |
@@ -1577,7 +1618,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1577 | Velocity = Vector3.Zero; | 1618 | Velocity = Vector3.Zero; |
1578 | SendFullUpdateToAllClients(); | 1619 | SendFullUpdateToAllClients(); |
1579 | 1620 | ||
1580 | //HandleAgentSit(ControllingClient, m_requestedSitTargetUUID); | 1621 | HandleAgentSit(ControllingClient, m_requestedSitTargetUUID); //KF ?? |
1581 | } | 1622 | } |
1582 | //ControllingClient.SendSitResponse(m_requestedSitTargetID, m_requestedSitOffset, Quaternion.Identity, false, Vector3.Zero, Vector3.Zero, false); | 1623 | //ControllingClient.SendSitResponse(m_requestedSitTargetID, m_requestedSitOffset, Quaternion.Identity, false, Vector3.Zero, Vector3.Zero, false); |
1583 | m_requestedSitTargetUUID = UUID.Zero; | 1624 | m_requestedSitTargetUUID = UUID.Zero; |
@@ -1610,55 +1651,84 @@ namespace OpenSim.Region.Framework.Scenes | |||
1610 | /// </summary> | 1651 | /// </summary> |
1611 | public void StandUp() | 1652 | public void StandUp() |
1612 | { | 1653 | { |
1613 | if (SitGround) | ||
1614 | SitGround = false; | ||
1615 | |||
1616 | if (m_parentID != 0) | 1654 | if (m_parentID != 0) |
1617 | { | 1655 | { |
1618 | m_log.Debug("StandupCode Executed"); | ||
1619 | SceneObjectPart part = m_scene.GetSceneObjectPart(m_parentID); | 1656 | SceneObjectPart part = m_scene.GetSceneObjectPart(m_parentID); |
1620 | if (part != null) | 1657 | if (part != null) |
1621 | { | 1658 | { |
1659 | part.TaskInventory.LockItemsForRead(true); | ||
1622 | TaskInventoryDictionary taskIDict = part.TaskInventory; | 1660 | TaskInventoryDictionary taskIDict = part.TaskInventory; |
1623 | if (taskIDict != null) | 1661 | if (taskIDict != null) |
1624 | { | 1662 | { |
1625 | lock (taskIDict) | 1663 | foreach (UUID taskID in taskIDict.Keys) |
1626 | { | 1664 | { |
1627 | foreach (UUID taskID in taskIDict.Keys) | 1665 | UnRegisterControlEventsToScript(LocalId, taskID); |
1628 | { | 1666 | taskIDict[taskID].PermsMask &= ~( |
1629 | UnRegisterControlEventsToScript(LocalId, taskID); | 1667 | 2048 | //PERMISSION_CONTROL_CAMERA |
1630 | taskIDict[taskID].PermsMask &= ~( | 1668 | 4); // PERMISSION_TAKE_CONTROLS |
1631 | 2048 | //PERMISSION_CONTROL_CAMERA | ||
1632 | 4); // PERMISSION_TAKE_CONTROLS | ||
1633 | } | ||
1634 | } | 1669 | } |
1635 | |||
1636 | } | 1670 | } |
1671 | part.TaskInventory.LockItemsForRead(false); | ||
1637 | // Reset sit target. | 1672 | // Reset sit target. |
1638 | if (part.GetAvatarOnSitTarget() == UUID) | 1673 | if (part.GetAvatarOnSitTarget() == UUID) |
1639 | part.SetAvatarOnSitTarget(UUID.Zero); | 1674 | part.SetAvatarOnSitTarget(UUID.Zero); |
1640 | |||
1641 | m_parentPosition = part.GetWorldPosition(); | 1675 | m_parentPosition = part.GetWorldPosition(); |
1642 | ControllingClient.SendClearFollowCamProperties(part.ParentUUID); | 1676 | ControllingClient.SendClearFollowCamProperties(part.ParentUUID); |
1643 | } | 1677 | } |
1644 | 1678 | // part.GetWorldRotation() is the rotation of the object being sat on | |
1645 | if (m_physicsActor == null) | 1679 | // Rotation is the sittiing Av's rotation |
1646 | { | 1680 | |
1647 | AddToPhysicalScene(false); | 1681 | Quaternion partRot; |
1682 | // if (part.LinkNum == 1) | ||
1683 | // { // Root prim of linkset | ||
1684 | // partRot = part.ParentGroup.RootPart.RotationOffset; | ||
1685 | // } | ||
1686 | // else | ||
1687 | // { // single or child prim | ||
1688 | |||
1689 | // } | ||
1690 | if (part == null) //CW: Part may be gone. llDie() for example. | ||
1691 | { | ||
1692 | partRot = new Quaternion(0.0f, 0.0f, 0.0f, 1.0f); | ||
1693 | } | ||
1694 | else | ||
1695 | { | ||
1696 | partRot = part.GetWorldRotation(); | ||
1697 | } | ||
1698 | |||
1699 | Quaternion partIRot = Quaternion.Inverse(partRot); | ||
1700 | |||
1701 | Quaternion avatarRot = Quaternion.Inverse(Quaternion.Inverse(Rotation) * partIRot); // world or. of the av | ||
1702 | Vector3 avStandUp = new Vector3(1.0f, 0f, 0f) * avatarRot; // 1M infront of av | ||
1703 | |||
1704 | |||
1705 | if (m_physicsActor == null) | ||
1706 | { | ||
1707 | AddToPhysicalScene(false); | ||
1708 | } | ||
1709 | //CW: If the part isn't null then we can set the current position | ||
1710 | if (part != null) | ||
1711 | { | ||
1712 | Vector3 avWorldStandUp = avStandUp + part.GetWorldPosition() + (m_pos * partRot); // + av sit offset! | ||
1713 | AbsolutePosition = avWorldStandUp; //KF: Fix stand up. | ||
1714 | part.IsOccupied = false; | ||
1715 | } | ||
1716 | else | ||
1717 | { | ||
1718 | //CW: Since the part doesn't exist, a coarse standup position isn't an issue | ||
1719 | AbsolutePosition = m_lastWorldPosition; | ||
1648 | } | 1720 | } |
1649 | 1721 | ||
1650 | m_pos += m_parentPosition + new Vector3(0.0f, 0.0f, 2.0f*m_sitAvatarHeight); | 1722 | m_parentPosition = Vector3.Zero; |
1651 | m_parentPosition = Vector3.Zero; | 1723 | m_parentID = 0; |
1652 | |||
1653 | m_parentID = 0; | ||
1654 | SendFullUpdateToAllClients(); | 1724 | SendFullUpdateToAllClients(); |
1655 | m_requestedSitTargetID = 0; | 1725 | m_requestedSitTargetID = 0; |
1726 | |||
1656 | if ((m_physicsActor != null) && (m_avHeight > 0)) | 1727 | if ((m_physicsActor != null) && (m_avHeight > 0)) |
1657 | { | 1728 | { |
1658 | SetHeight(m_avHeight); | 1729 | SetHeight(m_avHeight); |
1659 | } | 1730 | } |
1660 | } | 1731 | } |
1661 | |||
1662 | Animator.TrySetMovementAnimation("STAND"); | 1732 | Animator.TrySetMovementAnimation("STAND"); |
1663 | } | 1733 | } |
1664 | 1734 | ||
@@ -1689,13 +1759,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
1689 | Vector3 avSitOffSet = part.SitTargetPosition; | 1759 | Vector3 avSitOffSet = part.SitTargetPosition; |
1690 | Quaternion avSitOrientation = part.SitTargetOrientation; | 1760 | Quaternion avSitOrientation = part.SitTargetOrientation; |
1691 | UUID avOnTargetAlready = part.GetAvatarOnSitTarget(); | 1761 | UUID avOnTargetAlready = part.GetAvatarOnSitTarget(); |
1692 | 1762 | bool SitTargetOccupied = (avOnTargetAlready != UUID.Zero); | |
1693 | bool SitTargetUnOccupied = (!(avOnTargetAlready != UUID.Zero)); | 1763 | bool SitTargetisSet = (Vector3.Zero != avSitOffSet); //NB Latest SL Spec shows Sit Rotation setting is ignored. |
1694 | bool SitTargetisSet = | 1764 | if (SitTargetisSet && !SitTargetOccupied) |
1695 | (!(avSitOffSet.X == 0f && avSitOffSet.Y == 0f && avSitOffSet.Z == 0f && avSitOrientation.W == 1f && | ||
1696 | avSitOrientation.X == 0f && avSitOrientation.Y == 0f && avSitOrientation.Z == 0f)); | ||
1697 | |||
1698 | if (SitTargetisSet && SitTargetUnOccupied) | ||
1699 | { | 1765 | { |
1700 | //switch the target to this prim | 1766 | //switch the target to this prim |
1701 | return part; | 1767 | return part; |
@@ -1709,84 +1775,152 @@ namespace OpenSim.Region.Framework.Scenes | |||
1709 | private void SendSitResponse(IClientAPI remoteClient, UUID targetID, Vector3 offset, Quaternion pSitOrientation) | 1775 | private void SendSitResponse(IClientAPI remoteClient, UUID targetID, Vector3 offset, Quaternion pSitOrientation) |
1710 | { | 1776 | { |
1711 | bool autopilot = true; | 1777 | bool autopilot = true; |
1778 | Vector3 autopilotTarget = new Vector3(); | ||
1779 | Quaternion sitOrientation = Quaternion.Identity; | ||
1712 | Vector3 pos = new Vector3(); | 1780 | Vector3 pos = new Vector3(); |
1713 | Quaternion sitOrientation = pSitOrientation; | ||
1714 | Vector3 cameraEyeOffset = Vector3.Zero; | 1781 | Vector3 cameraEyeOffset = Vector3.Zero; |
1715 | Vector3 cameraAtOffset = Vector3.Zero; | 1782 | Vector3 cameraAtOffset = Vector3.Zero; |
1716 | bool forceMouselook = false; | 1783 | bool forceMouselook = false; |
1717 | 1784 | ||
1718 | //SceneObjectPart part = m_scene.GetSceneObjectPart(targetID); | 1785 | //SceneObjectPart part = m_scene.GetSceneObjectPart(targetID); |
1719 | SceneObjectPart part = FindNextAvailableSitTarget(targetID); | 1786 | SceneObjectPart part = FindNextAvailableSitTarget(targetID); |
1720 | if (part != null) | 1787 | if (part == null) return; |
1721 | { | 1788 | |
1722 | // TODO: determine position to sit at based on scene geometry; don't trust offset from client | 1789 | // TODO: determine position to sit at based on scene geometry; don't trust offset from client |
1723 | // see http://wiki.secondlife.com/wiki/User:Andrew_Linden/Office_Hours/2007_11_06 for details on how LL does it | 1790 | // see http://wiki.secondlife.com/wiki/User:Andrew_Linden/Office_Hours/2007_11_06 for details on how LL does it |
1724 | 1791 | ||
1725 | // Is a sit target available? | 1792 | // part is the prim to sit on |
1726 | Vector3 avSitOffSet = part.SitTargetPosition; | 1793 | // offset is the world-ref vector distance from that prim center to the click-spot |
1727 | Quaternion avSitOrientation = part.SitTargetOrientation; | 1794 | // UUID is the UUID of the Avatar doing the clicking |
1728 | UUID avOnTargetAlready = part.GetAvatarOnSitTarget(); | 1795 | |
1729 | 1796 | m_avInitialPos = AbsolutePosition; // saved to calculate unscripted sit rotation | |
1730 | bool SitTargetUnOccupied = (!(avOnTargetAlready != UUID.Zero)); | 1797 | |
1731 | bool SitTargetisSet = | 1798 | // Is a sit target available? |
1732 | (!(avSitOffSet.X == 0f && avSitOffSet.Y == 0f && avSitOffSet.Z == 0f && | 1799 | Vector3 avSitOffSet = part.SitTargetPosition; |
1733 | ( | 1800 | Quaternion avSitOrientation = part.SitTargetOrientation; |
1734 | avSitOrientation.X == 0f && avSitOrientation.Y == 0f && avSitOrientation.Z == 0f && avSitOrientation.W == 1f // Valid Zero Rotation quaternion | 1801 | |
1735 | || avSitOrientation.X == 0f && avSitOrientation.Y == 0f && avSitOrientation.Z == 1f && avSitOrientation.W == 0f // W-Z Mapping was invalid at one point | 1802 | bool SitTargetisSet = (Vector3.Zero != avSitOffSet); //NB Latest SL Spec shows Sit Rotation setting is ignored. |
1736 | || avSitOrientation.X == 0f && avSitOrientation.Y == 0f && avSitOrientation.Z == 0f && avSitOrientation.W == 0f // Invalid Quaternion | 1803 | // Quaternion partIRot = Quaternion.Inverse(part.GetWorldRotation()); |
1737 | ) | 1804 | Quaternion partRot; |
1738 | )); | 1805 | // if (part.LinkNum == 1) |
1739 | 1806 | // { // Root prim of linkset | |
1740 | if (SitTargetisSet && SitTargetUnOccupied) | 1807 | // partRot = part.ParentGroup.RootPart.RotationOffset; |
1741 | { | 1808 | // } |
1742 | part.SetAvatarOnSitTarget(UUID); | 1809 | // else |
1743 | offset = new Vector3(avSitOffSet.X, avSitOffSet.Y, avSitOffSet.Z); | 1810 | // { // single or child prim |
1744 | sitOrientation = avSitOrientation; | 1811 | partRot = part.GetWorldRotation(); |
1745 | autopilot = false; | 1812 | // } |
1746 | } | 1813 | Quaternion partIRot = Quaternion.Inverse(partRot); |
1747 | 1814 | //Console.WriteLine("SendSitResponse offset=" + offset + " Occup=" + part.IsOccupied + " TargSet=" + SitTargetisSet); | |
1748 | pos = part.AbsolutePosition + offset; | 1815 | // Sit analysis rewritten by KF 091125 |
1749 | //if (Math.Abs(part.AbsolutePosition.Z - AbsolutePosition.Z) > 1) | 1816 | if (SitTargetisSet) // scipted sit |
1750 | //{ | 1817 | { |
1751 | // offset = pos; | 1818 | if (!part.IsOccupied) |
1752 | //autopilot = false; | 1819 | { |
1753 | //} | 1820 | //Console.WriteLine("Scripted, unoccupied"); |
1754 | if (m_physicsActor != null) | 1821 | part.SetAvatarOnSitTarget(UUID); // set that Av will be on it |
1755 | { | 1822 | offset = new Vector3(avSitOffSet.X, avSitOffSet.Y, avSitOffSet.Z); // change ofset to the scripted one |
1756 | // If we're not using the client autopilot, we're immediately warping the avatar to the location | 1823 | sitOrientation = avSitOrientation; // Change rotatione to the scripted one |
1757 | // We can remove the physicsActor until they stand up. | 1824 | autopilot = false; // Jump direct to scripted llSitPos() |
1758 | m_sitAvatarHeight = m_physicsActor.Size.Z; | 1825 | } |
1759 | 1826 | else | |
1760 | if (autopilot) | 1827 | { |
1761 | { | 1828 | //Console.WriteLine("Scripted, occupied"); |
1762 | if (Util.GetDistanceTo(AbsolutePosition, pos) < 4.5) | 1829 | return; |
1763 | { | 1830 | } |
1764 | autopilot = false; | 1831 | } |
1832 | else // Not Scripted | ||
1833 | { | ||
1834 | if ( (Math.Abs(offset.X) > 0.5f) || (Math.Abs(offset.Y) > 0.5f) ) | ||
1835 | { | ||
1836 | // large prim & offset, ignore if other Avs sitting | ||
1837 | // offset.Z -= 0.05f; | ||
1838 | m_avUnscriptedSitPos = offset * partIRot; // (non-zero) sit where clicked | ||
1839 | autopilotTarget = part.AbsolutePosition + offset; // World location of clicked point | ||
1840 | |||
1841 | //Console.WriteLine(" offset ={0}", offset); | ||
1842 | //Console.WriteLine(" UnscriptedSitPos={0}", m_avUnscriptedSitPos); | ||
1843 | //Console.WriteLine(" autopilotTarget={0}", autopilotTarget); | ||
1844 | |||
1845 | } | ||
1846 | else // small offset | ||
1847 | { | ||
1848 | //Console.WriteLine("Small offset"); | ||
1849 | if (!part.IsOccupied) | ||
1850 | { | ||
1851 | m_avUnscriptedSitPos = Vector3.Zero; // Zero = Sit on prim center | ||
1852 | autopilotTarget = part.AbsolutePosition; | ||
1853 | } | ||
1854 | else return; // occupied small | ||
1855 | } // end large/small | ||
1856 | } // end Scripted/not | ||
1857 | cameraAtOffset = part.GetCameraAtOffset(); | ||
1858 | cameraEyeOffset = part.GetCameraEyeOffset(); | ||
1859 | forceMouselook = part.GetForceMouselook(); | ||
1860 | if(cameraAtOffset == Vector3.Zero) cameraAtOffset = new Vector3(0f, 0f, 0.1f); // | ||
1861 | if(cameraEyeOffset == Vector3.Zero) cameraEyeOffset = new Vector3(0f, 0f, 0.1f); // | ||
1765 | 1862 | ||
1766 | RemoveFromPhysicalScene(); | 1863 | if (m_physicsActor != null) |
1767 | AbsolutePosition = pos + new Vector3(0.0f, 0.0f, m_sitAvatarHeight); | 1864 | { |
1768 | } | 1865 | // If we're not using the client autopilot, we're immediately warping the avatar to the location |
1769 | } | 1866 | // We can remove the physicsActor until they stand up. |
1770 | else | 1867 | m_sitAvatarHeight = m_physicsActor.Size.Z; |
1868 | if (autopilot) | ||
1869 | { // its not a scripted sit | ||
1870 | // if (Util.GetDistanceTo(AbsolutePosition, autopilotTarget) < 4.5) | ||
1871 | if( (Math.Abs(AbsolutePosition.X - autopilotTarget.X) < 2.0f) && (Math.Abs(AbsolutePosition.Y - autopilotTarget.Y) < 2.0f) ) | ||
1771 | { | 1872 | { |
1873 | autopilot = false; // close enough | ||
1874 | m_lastWorldPosition = m_pos; /* CW - This give us a position to return the avatar to if the part is killed before standup. | ||
1875 | Not using the part's position because returning the AV to the last known standing | ||
1876 | position is likely to be more friendly, isn't it? */ | ||
1772 | RemoveFromPhysicalScene(); | 1877 | RemoveFromPhysicalScene(); |
1773 | } | 1878 | AbsolutePosition = autopilotTarget + new Vector3(0.0f, 0.0f, (m_sitAvatarHeight / 2.0f)); // Warp av to over sit target |
1879 | } // else the autopilot will get us close | ||
1880 | } | ||
1881 | else | ||
1882 | { // its a scripted sit | ||
1883 | m_lastWorldPosition = part.AbsolutePosition; /* CW - This give us a position to return the avatar to if the part is killed before standup. | ||
1884 | I *am* using the part's position this time because we have no real idea how far away | ||
1885 | the avatar is from the sit target. */ | ||
1886 | RemoveFromPhysicalScene(); | ||
1774 | } | 1887 | } |
1775 | |||
1776 | cameraAtOffset = part.GetCameraAtOffset(); | ||
1777 | cameraEyeOffset = part.GetCameraEyeOffset(); | ||
1778 | forceMouselook = part.GetForceMouselook(); | ||
1779 | } | 1888 | } |
1780 | 1889 | else return; // physactor is null! | |
1781 | ControllingClient.SendSitResponse(targetID, offset, sitOrientation, autopilot, cameraAtOffset, cameraEyeOffset, forceMouselook); | 1890 | |
1782 | m_requestedSitTargetUUID = targetID; | 1891 | Vector3 offsetr; // = offset * partIRot; |
1892 | // KF: In a linkset, offsetr needs to be relative to the group root! 091208 | ||
1893 | // offsetr = (part.OffsetPosition * Quaternion.Inverse(part.ParentGroup.RootPart.RotationOffset)) + (offset * partIRot); | ||
1894 | // if (part.LinkNum < 2) 091216 All this was necessary because of the GetWorldRotation error. | ||
1895 | // { // Single, or Root prim of linkset, target is ClickOffset * RootRot | ||
1896 | offsetr = offset * partIRot; | ||
1897 | // | ||
1898 | // else | ||
1899 | // { // Child prim, offset is (ChildOffset * RootRot) + (ClickOffset * ChildRot) | ||
1900 | // offsetr = //(part.OffsetPosition * Quaternion.Inverse(part.ParentGroup.RootPart.RotationOffset)) + | ||
1901 | // (offset * partRot); | ||
1902 | // } | ||
1903 | |||
1904 | //Console.WriteLine(" "); | ||
1905 | //Console.WriteLine("link number ={0}", part.LinkNum); | ||
1906 | //Console.WriteLine("Prim offset ={0}", part.OffsetPosition ); | ||
1907 | //Console.WriteLine("Root Rotate ={0}", part.ParentGroup.RootPart.RotationOffset); | ||
1908 | //Console.WriteLine("Click offst ={0}", offset); | ||
1909 | //Console.WriteLine("Prim Rotate ={0}", part.GetWorldRotation()); | ||
1910 | //Console.WriteLine("offsetr ={0}", offsetr); | ||
1911 | //Console.WriteLine("Camera At ={0}", cameraAtOffset); | ||
1912 | //Console.WriteLine("Camera Eye ={0}", cameraEyeOffset); | ||
1913 | |||
1914 | ControllingClient.SendSitResponse(part.UUID, offsetr, sitOrientation, autopilot, cameraAtOffset, cameraEyeOffset, forceMouselook); | ||
1915 | m_requestedSitTargetUUID = part.UUID; //KF: Correct autopilot target | ||
1783 | // This calls HandleAgentSit twice, once from here, and the client calls | 1916 | // This calls HandleAgentSit twice, once from here, and the client calls |
1784 | // HandleAgentSit itself after it gets to the location | 1917 | // HandleAgentSit itself after it gets to the location |
1785 | // It doesn't get to the location until we've moved them there though | 1918 | // It doesn't get to the location until we've moved them there though |
1786 | // which happens in HandleAgentSit :P | 1919 | // which happens in HandleAgentSit :P |
1787 | m_autopilotMoving = autopilot; | 1920 | m_autopilotMoving = autopilot; |
1788 | m_autoPilotTarget = pos; | 1921 | m_autoPilotTarget = autopilotTarget; |
1789 | m_sitAtAutoTarget = autopilot; | 1922 | m_sitAtAutoTarget = autopilot; |
1923 | m_initialSitTarget = autopilotTarget; | ||
1790 | if (!autopilot) | 1924 | if (!autopilot) |
1791 | HandleAgentSit(remoteClient, UUID); | 1925 | HandleAgentSit(remoteClient, UUID); |
1792 | } | 1926 | } |
@@ -2081,31 +2215,65 @@ namespace OpenSim.Region.Framework.Scenes | |||
2081 | { | 2215 | { |
2082 | if (part != null) | 2216 | if (part != null) |
2083 | { | 2217 | { |
2218 | //Console.WriteLine("Link #{0}, Rot {1}", part.LinkNum, part.GetWorldRotation()); | ||
2084 | if (part.GetAvatarOnSitTarget() == UUID) | 2219 | if (part.GetAvatarOnSitTarget() == UUID) |
2085 | { | 2220 | { |
2221 | //Console.WriteLine("Scripted Sit"); | ||
2222 | // Scripted sit | ||
2086 | Vector3 sitTargetPos = part.SitTargetPosition; | 2223 | Vector3 sitTargetPos = part.SitTargetPosition; |
2087 | Quaternion sitTargetOrient = part.SitTargetOrientation; | 2224 | Quaternion sitTargetOrient = part.SitTargetOrientation; |
2088 | |||
2089 | //Quaternion vq = new Quaternion(sitTargetPos.X, sitTargetPos.Y+0.2f, sitTargetPos.Z+0.2f, 0); | ||
2090 | //Quaternion nq = new Quaternion(-sitTargetOrient.X, -sitTargetOrient.Y, -sitTargetOrient.Z, sitTargetOrient.w); | ||
2091 | |||
2092 | //Quaternion result = (sitTargetOrient * vq) * nq; | ||
2093 | |||
2094 | m_pos = new Vector3(sitTargetPos.X, sitTargetPos.Y, sitTargetPos.Z); | 2225 | m_pos = new Vector3(sitTargetPos.X, sitTargetPos.Y, sitTargetPos.Z); |
2095 | m_pos += SIT_TARGET_ADJUSTMENT; | 2226 | m_pos += SIT_TARGET_ADJUSTMENT; |
2096 | m_bodyRot = sitTargetOrient; | 2227 | m_bodyRot = sitTargetOrient; |
2097 | //Rotation = sitTargetOrient; | ||
2098 | m_parentPosition = part.AbsolutePosition; | 2228 | m_parentPosition = part.AbsolutePosition; |
2099 | 2229 | part.IsOccupied = true; | |
2100 | //SendTerseUpdateToAllClients(); | ||
2101 | } | 2230 | } |
2102 | else | 2231 | else |
2103 | { | 2232 | { |
2104 | m_pos -= part.AbsolutePosition; | 2233 | // if m_avUnscriptedSitPos is zero then Av sits above center |
2234 | // Else Av sits at m_avUnscriptedSitPos | ||
2235 | |||
2236 | // Non-scripted sit by Kitto Flora 21Nov09 | ||
2237 | // Calculate angle of line from prim to Av | ||
2238 | Quaternion partIRot; | ||
2239 | // if (part.LinkNum == 1) | ||
2240 | // { // Root prim of linkset | ||
2241 | // partIRot = Quaternion.Inverse(part.ParentGroup.RootPart.RotationOffset); | ||
2242 | // } | ||
2243 | // else | ||
2244 | // { // single or child prim | ||
2245 | partIRot = Quaternion.Inverse(part.GetWorldRotation()); | ||
2246 | // } | ||
2247 | Vector3 sitTargetPos= part.AbsolutePosition + m_avUnscriptedSitPos; | ||
2248 | float y_diff = (m_avInitialPos.Y - sitTargetPos.Y); | ||
2249 | float x_diff = ( m_avInitialPos.X - sitTargetPos.X); | ||
2250 | if(Math.Abs(x_diff) < 0.001f) x_diff = 0.001f; // avoid div by 0 | ||
2251 | if(Math.Abs(y_diff) < 0.001f) y_diff = 0.001f; // avoid pol flip at 0 | ||
2252 | float sit_angle = (float)Math.Atan2( (double)y_diff, (double)x_diff); | ||
2253 | // NOTE: when sitting m_ pos and m_bodyRot are *relative* to the prim location/rotation, not 'World'. | ||
2254 | // Av sits at world euler <0,0, z>, translated by part rotation | ||
2255 | m_bodyRot = partIRot * Quaternion.CreateFromEulers(0f, 0f, sit_angle); // sit at 0,0,inv-click | ||
2256 | |||
2105 | m_parentPosition = part.AbsolutePosition; | 2257 | m_parentPosition = part.AbsolutePosition; |
2106 | } | 2258 | part.IsOccupied = true; |
2107 | } | 2259 | m_pos = new Vector3(0f, 0f, 0.05f) + // corrections to get Sit Animation |
2108 | else | 2260 | (new Vector3(0.0f, 0f, 0.61f) * partIRot) + // located on center |
2261 | (new Vector3(0.34f, 0f, 0.0f) * m_bodyRot) + | ||
2262 | m_avUnscriptedSitPos; // adds click offset, if any | ||
2263 | //Set up raytrace to find top surface of prim | ||
2264 | Vector3 size = part.Scale; | ||
2265 | float mag = 2.0f; // 0.1f + (float)Math.Sqrt((size.X * size.X) + (size.Y * size.Y) + (size.Z * size.Z)); | ||
2266 | Vector3 start = part.AbsolutePosition + new Vector3(0f, 0f, mag); | ||
2267 | Vector3 down = new Vector3(0f, 0f, -1f); | ||
2268 | //Console.WriteLine("st={0} do={1} ma={2}", start, down, mag); | ||
2269 | m_scene.PhysicsScene.RaycastWorld( | ||
2270 | start, // Vector3 position, | ||
2271 | down, // Vector3 direction, | ||
2272 | mag, // float length, | ||
2273 | SitAltitudeCallback); // retMethod | ||
2274 | } // end scripted/not | ||
2275 | } | ||
2276 | else // no Av | ||
2109 | { | 2277 | { |
2110 | return; | 2278 | return; |
2111 | } | 2279 | } |
@@ -2117,11 +2285,36 @@ namespace OpenSim.Region.Framework.Scenes | |||
2117 | 2285 | ||
2118 | Animator.TrySetMovementAnimation(sitAnimation); | 2286 | Animator.TrySetMovementAnimation(sitAnimation); |
2119 | SendFullUpdateToAllClients(); | 2287 | SendFullUpdateToAllClients(); |
2120 | // This may seem stupid, but Our Full updates don't send avatar rotation :P | ||
2121 | // So we're also sending a terse update (which has avatar rotation) | ||
2122 | // [Update] We do now. | ||
2123 | //SendTerseUpdateToAllClients(); | ||
2124 | } | 2288 | } |
2289 | |||
2290 | public void SitAltitudeCallback(bool hitYN, Vector3 collisionPoint, uint localid, float distance, Vector3 normal) | ||
2291 | { | ||
2292 | // KF: 091202 There appears to be a bug in Prim Edit Size - the process sometimes make a prim that RayTrace no longer | ||
2293 | // sees. Take/re-rez, or sim restart corrects the condition. Result of bug is incorrect sit height. | ||
2294 | if(hitYN) | ||
2295 | { | ||
2296 | // m_pos = Av offset from prim center to make look like on center | ||
2297 | // m_parentPosition = Actual center pos of prim | ||
2298 | // collisionPoint = spot on prim where we want to sit | ||
2299 | // collisionPoint.Z = global sit surface height | ||
2300 | SceneObjectPart part = m_scene.GetSceneObjectPart(localid); | ||
2301 | Quaternion partIRot; | ||
2302 | // if (part.LinkNum == 1) | ||
2303 | /// { // Root prim of linkset | ||
2304 | // partIRot = Quaternion.Inverse(part.ParentGroup.RootPart.RotationOffset); | ||
2305 | // } | ||
2306 | // else | ||
2307 | // { // single or child prim | ||
2308 | partIRot = Quaternion.Inverse(part.GetWorldRotation()); | ||
2309 | // } | ||
2310 | float offZ = collisionPoint.Z - m_initialSitTarget.Z; | ||
2311 | Vector3 offset = new Vector3(0.0f, 0.0f, offZ) * partIRot; // Altitude correction | ||
2312 | //Console.WriteLine("sitPoint={0}, offset={1}", sitPoint, offset); | ||
2313 | m_pos += offset; | ||
2314 | // ControllingClient.SendClearFollowCamProperties(part.UUID); | ||
2315 | |||
2316 | } | ||
2317 | } // End SitAltitudeCallback KF. | ||
2125 | 2318 | ||
2126 | /// <summary> | 2319 | /// <summary> |
2127 | /// Event handler for the 'Always run' setting on the client | 2320 | /// Event handler for the 'Always run' setting on the client |
@@ -2151,7 +2344,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2151 | /// </summary> | 2344 | /// </summary> |
2152 | /// <param name="vec">The vector in which to move. This is relative to the rotation argument</param> | 2345 | /// <param name="vec">The vector in which to move. This is relative to the rotation argument</param> |
2153 | /// <param name="rotation">The direction in which this avatar should now face. | 2346 | /// <param name="rotation">The direction in which this avatar should now face. |
2154 | public void AddNewMovement(Vector3 vec, Quaternion rotation) | 2347 | public void AddNewMovement(Vector3 vec, Quaternion rotation, bool Nudging) |
2155 | { | 2348 | { |
2156 | if (m_isChildAgent) | 2349 | if (m_isChildAgent) |
2157 | { | 2350 | { |
@@ -2225,7 +2418,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2225 | 2418 | ||
2226 | // TODO: Add the force instead of only setting it to support multiple forces per frame? | 2419 | // TODO: Add the force instead of only setting it to support multiple forces per frame? |
2227 | m_forceToApply = direc; | 2420 | m_forceToApply = direc; |
2228 | 2421 | m_isNudging = Nudging; | |
2229 | m_scene.StatsReporter.AddAgentTime(Util.EnvironmentTickCountSubtract(m_perfMonMS)); | 2422 | m_scene.StatsReporter.AddAgentTime(Util.EnvironmentTickCountSubtract(m_perfMonMS)); |
2230 | } | 2423 | } |
2231 | 2424 | ||
@@ -2240,7 +2433,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2240 | const float POSITION_TOLERANCE = 0.05f; | 2433 | const float POSITION_TOLERANCE = 0.05f; |
2241 | //const int TIME_MS_TOLERANCE = 3000; | 2434 | //const int TIME_MS_TOLERANCE = 3000; |
2242 | 2435 | ||
2243 | SendPrimUpdates(); | 2436 | |
2244 | 2437 | ||
2245 | if (m_newCoarseLocations) | 2438 | if (m_newCoarseLocations) |
2246 | { | 2439 | { |
@@ -2276,6 +2469,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
2276 | CheckForBorderCrossing(); | 2469 | CheckForBorderCrossing(); |
2277 | CheckForSignificantMovement(); // sends update to the modules. | 2470 | CheckForSignificantMovement(); // sends update to the modules. |
2278 | } | 2471 | } |
2472 | |||
2473 | //Sending prim updates AFTER the avatar terse updates are sent | ||
2474 | SendPrimUpdates(); | ||
2279 | } | 2475 | } |
2280 | 2476 | ||
2281 | #endregion | 2477 | #endregion |
@@ -3129,14 +3325,25 @@ namespace OpenSim.Region.Framework.Scenes | |||
3129 | { | 3325 | { |
3130 | if (m_forceToApply.HasValue) | 3326 | if (m_forceToApply.HasValue) |
3131 | { | 3327 | { |
3132 | Vector3 force = m_forceToApply.Value; | ||
3133 | 3328 | ||
3329 | Vector3 force = m_forceToApply.Value; | ||
3134 | m_updateflag = true; | 3330 | m_updateflag = true; |
3135 | // movementvector = force; | ||
3136 | Velocity = force; | 3331 | Velocity = force; |
3137 | 3332 | ||
3138 | m_forceToApply = null; | 3333 | m_forceToApply = null; |
3139 | } | 3334 | } |
3335 | else | ||
3336 | { | ||
3337 | if (m_isNudging) | ||
3338 | { | ||
3339 | Vector3 force = Vector3.Zero; | ||
3340 | |||
3341 | m_updateflag = true; | ||
3342 | Velocity = force; | ||
3343 | m_isNudging = false; | ||
3344 | m_updateCount = UPDATE_COUNT; //KF: Update anims to pickup "STAND" | ||
3345 | } | ||
3346 | } | ||
3140 | } | 3347 | } |
3141 | 3348 | ||
3142 | public override void SetText(string text, Vector3 color, double alpha) | 3349 | public override void SetText(string text, Vector3 color, double alpha) |
@@ -3188,18 +3395,29 @@ namespace OpenSim.Region.Framework.Scenes | |||
3188 | { | 3395 | { |
3189 | if (e == null) | 3396 | if (e == null) |
3190 | return; | 3397 | return; |
3191 | 3398 | ||
3192 | //if ((Math.Abs(Velocity.X) > 0.1e-9f) || (Math.Abs(Velocity.Y) > 0.1e-9f)) | 3399 | // The Physics Scene will send (spam!) updates every 500 ms grep: m_physicsActor.SubscribeEvents( |
3193 | // The Physics Scene will send updates every 500 ms grep: m_physicsActor.SubscribeEvents( | ||
3194 | // as of this comment the interval is set in AddToPhysicalScene | 3400 | // as of this comment the interval is set in AddToPhysicalScene |
3195 | if (Animator!=null) | 3401 | if (Animator!=null) |
3196 | Animator.UpdateMovementAnimations(); | 3402 | { |
3403 | if (m_updateCount > 0) //KF: DO NOT call UpdateMovementAnimations outside of the m_updateCount wrapper, | ||
3404 | { // else its will lock out other animation changes, like ground sit. | ||
3405 | Animator.UpdateMovementAnimations(); | ||
3406 | m_updateCount--; | ||
3407 | } | ||
3408 | } | ||
3197 | 3409 | ||
3198 | CollisionEventUpdate collisionData = (CollisionEventUpdate)e; | 3410 | CollisionEventUpdate collisionData = (CollisionEventUpdate)e; |
3199 | Dictionary<uint, ContactPoint> coldata = collisionData.m_objCollisionList; | 3411 | Dictionary<uint, ContactPoint> coldata = collisionData.m_objCollisionList; |
3200 | 3412 | ||
3201 | CollisionPlane = Vector4.UnitW; | 3413 | CollisionPlane = Vector4.UnitW; |
3202 | 3414 | ||
3415 | if (m_lastColCount != coldata.Count) | ||
3416 | { | ||
3417 | m_updateCount = UPDATE_COUNT; | ||
3418 | m_lastColCount = coldata.Count; | ||
3419 | } | ||
3420 | |||
3203 | if (coldata.Count != 0 && Animator != null) | 3421 | if (coldata.Count != 0 && Animator != null) |
3204 | { | 3422 | { |
3205 | switch (Animator.CurrentMovementAnimation) | 3423 | switch (Animator.CurrentMovementAnimation) |
@@ -3847,5 +4065,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
3847 | m_reprioritization_called = false; | 4065 | m_reprioritization_called = false; |
3848 | } | 4066 | } |
3849 | } | 4067 | } |
4068 | |||
4069 | private Vector3 Quat2Euler(Quaternion rot){ | ||
4070 | float x = Utils.RAD_TO_DEG * (float)Math.Atan2((double)((2.0f * rot.X * rot.W) - (2.0f * rot.Y * rot.Z)) , | ||
4071 | (double)(1 - (2.0f * rot.X * rot.X) - (2.0f * rot.Z * rot.Z))); | ||
4072 | float y = Utils.RAD_TO_DEG * (float)Math.Asin ((double)((2.0f * rot.X * rot.Y) + (2.0f * rot.Z * rot.W))); | ||
4073 | float z = Utils.RAD_TO_DEG * (float)Math.Atan2(((double)(2.0f * rot.Y * rot.W) - (2.0f * rot.X * rot.Z)) , | ||
4074 | (double)(1 - (2.0f * rot.Y * rot.Y) - (2.0f * rot.Z * rot.Z))); | ||
4075 | return(new Vector3(x,y,z)); | ||
4076 | } | ||
4077 | |||
4078 | |||
3850 | } | 4079 | } |
3851 | } \ No newline at end of file | 4080 | } |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs index 8a27b7b..5abbb82 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs | |||
@@ -101,7 +101,16 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
101 | { | 101 | { |
102 | throw new NotImplementedException(); | 102 | throw new NotImplementedException(); |
103 | } | 103 | } |
104 | 104 | public RegionMeta7WindlightData LoadRegionWindlightSettings(UUID regionUUID) | |
105 | { | ||
106 | //This connector doesn't support the windlight module yet | ||
107 | //Return default LL windlight settings | ||
108 | return new RegionMeta7WindlightData(); | ||
109 | } | ||
110 | public void StoreRegionWindlightSettings(RegionMeta7WindlightData wl) | ||
111 | { | ||
112 | //This connector doesn't support the windlight module yet | ||
113 | } | ||
105 | public RegionSettings LoadRegionSettings(UUID regionUUID) | 114 | public RegionSettings LoadRegionSettings(UUID regionUUID) |
106 | { | 115 | { |
107 | return null; | 116 | return null; |
diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs index 6785c08..f966376 100644 --- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs +++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs | |||
@@ -955,7 +955,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server | |||
955 | // TODO | 955 | // TODO |
956 | } | 956 | } |
957 | 957 | ||
958 | public void SendGenericMessage(string method, List<string> message) | 958 | public void SendGenericMessage(string method, List<byte[]> message) |
959 | { | 959 | { |
960 | 960 | ||
961 | } | 961 | } |
diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs index 4a4c515..23398f7 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs | |||
@@ -542,7 +542,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC | |||
542 | 542 | ||
543 | } | 543 | } |
544 | 544 | ||
545 | public void SendGenericMessage(string method, List<string> message) | 545 | public void SendGenericMessage(string method, List<byte[]> message) |
546 | { | 546 | { |
547 | 547 | ||
548 | } | 548 | } |
diff --git a/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETCharacter.cs b/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETCharacter.cs index 97eb6a2..a3344dd 100644 --- a/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETCharacter.cs +++ b/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETCharacter.cs | |||
@@ -619,8 +619,7 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin | |||
619 | { | 619 | { |
620 | set { return; } | 620 | set { return; } |
621 | } | 621 | } |
622 | 622 | ||
623 | |||
624 | public override Quaternion APIDTarget | 623 | public override Quaternion APIDTarget |
625 | { | 624 | { |
626 | set { return; } | 625 | set { return; } |
diff --git a/OpenSim/Region/Physics/ChOdePlugin/AssemblyInfo.cs b/OpenSim/Region/Physics/ChOdePlugin/AssemblyInfo.cs new file mode 100644 index 0000000..d65929a --- /dev/null +++ b/OpenSim/Region/Physics/ChOdePlugin/AssemblyInfo.cs | |||
@@ -0,0 +1,58 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System.Reflection; | ||
29 | using System.Runtime.InteropServices; | ||
30 | |||
31 | // Information about this assembly is defined by the following | ||
32 | // attributes. | ||
33 | // | ||
34 | // change them to the information which is associated with the assembly | ||
35 | // you compile. | ||
36 | |||
37 | [assembly : AssemblyTitle("OdePlugin")] | ||
38 | [assembly : AssemblyDescription("")] | ||
39 | [assembly : AssemblyConfiguration("")] | ||
40 | [assembly : AssemblyCompany("http://opensimulator.org")] | ||
41 | [assembly : AssemblyProduct("OdePlugin")] | ||
42 | [assembly : AssemblyCopyright("Copyright (c) OpenSimulator.org Developers 2007-2009")] | ||
43 | [assembly : AssemblyTrademark("")] | ||
44 | [assembly : AssemblyCulture("")] | ||
45 | |||
46 | // This sets the default COM visibility of types in the assembly to invisible. | ||
47 | // If you need to expose a type to COM, use [ComVisible(true)] on that type. | ||
48 | |||
49 | [assembly : ComVisible(false)] | ||
50 | |||
51 | // The assembly version has following format : | ||
52 | // | ||
53 | // Major.Minor.Build.Revision | ||
54 | // | ||
55 | // You can specify all values by your own or you can build default build and revision | ||
56 | // numbers with the '*' character (the default): | ||
57 | |||
58 | [assembly : AssemblyVersion("0.6.5.*")] | ||
diff --git a/OpenSim/Region/Physics/ChOdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/ChOdePlugin/ODECharacter.cs new file mode 100644 index 0000000..aa0acb7 --- /dev/null +++ b/OpenSim/Region/Physics/ChOdePlugin/ODECharacter.cs | |||
@@ -0,0 +1,1353 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Reflection; | ||
31 | using OpenMetaverse; | ||
32 | using Ode.NET; | ||
33 | using OpenSim.Framework; | ||
34 | using OpenSim.Region.Physics.Manager; | ||
35 | using log4net; | ||
36 | |||
37 | namespace OpenSim.Region.Physics.OdePlugin | ||
38 | { | ||
39 | /// <summary> | ||
40 | /// Various properties that ODE uses for AMotors but isn't exposed in ODE.NET so we must define them ourselves. | ||
41 | /// </summary> | ||
42 | |||
43 | public enum dParam : int | ||
44 | { | ||
45 | LowStop = 0, | ||
46 | HiStop = 1, | ||
47 | Vel = 2, | ||
48 | FMax = 3, | ||
49 | FudgeFactor = 4, | ||
50 | Bounce = 5, | ||
51 | CFM = 6, | ||
52 | StopERP = 7, | ||
53 | StopCFM = 8, | ||
54 | LoStop2 = 256, | ||
55 | HiStop2 = 257, | ||
56 | Vel2 = 258, | ||
57 | FMax2 = 259, | ||
58 | StopERP2 = 7 + 256, | ||
59 | StopCFM2 = 8 + 256, | ||
60 | LoStop3 = 512, | ||
61 | HiStop3 = 513, | ||
62 | Vel3 = 514, | ||
63 | FMax3 = 515, | ||
64 | StopERP3 = 7 + 512, | ||
65 | StopCFM3 = 8 + 512 | ||
66 | } | ||
67 | public class OdeCharacter : PhysicsActor | ||
68 | { | ||
69 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
70 | |||
71 | private Vector3 _position; | ||
72 | private d.Vector3 _zeroPosition; | ||
73 | // private d.Matrix3 m_StandUpRotation; | ||
74 | private bool _zeroFlag = false; | ||
75 | private bool m_lastUpdateSent = false; | ||
76 | private Vector3 _velocity; | ||
77 | private Vector3 _target_velocity; | ||
78 | private Vector3 _acceleration; | ||
79 | private Vector3 m_rotationalVelocity; | ||
80 | private float m_mass = 80f; | ||
81 | public float m_density = 60f; | ||
82 | private bool m_pidControllerActive = true; | ||
83 | public float PID_D = 800.0f; | ||
84 | public float PID_P = 900.0f; | ||
85 | //private static float POSTURE_SERVO = 10000.0f; | ||
86 | public float CAPSULE_RADIUS = 0.37f; | ||
87 | public float CAPSULE_LENGTH = 2.140599f; | ||
88 | public float m_tensor = 3800000f; | ||
89 | public float heightFudgeFactor = 0.52f; | ||
90 | public float walkDivisor = 1.3f; | ||
91 | public float runDivisor = 0.8f; | ||
92 | private bool flying = false; | ||
93 | private bool m_iscolliding = false; | ||
94 | private bool m_iscollidingGround = false; | ||
95 | private bool m_wascolliding = false; | ||
96 | private bool m_wascollidingGround = false; | ||
97 | private bool m_iscollidingObj = false; | ||
98 | private bool m_alwaysRun = false; | ||
99 | private bool m_hackSentFall = false; | ||
100 | private bool m_hackSentFly = false; | ||
101 | private int m_requestedUpdateFrequency = 0; | ||
102 | private Vector3 m_taintPosition = Vector3.Zero; | ||
103 | public uint m_localID = 0; | ||
104 | public bool m_returnCollisions = false; | ||
105 | // taints and their non-tainted counterparts | ||
106 | public bool m_isPhysical = false; // the current physical status | ||
107 | public bool m_tainted_isPhysical = false; // set when the physical status is tainted (false=not existing in physics engine, true=existing) | ||
108 | public float MinimumGroundFlightOffset = 3f; | ||
109 | |||
110 | private float m_tainted_CAPSULE_LENGTH; // set when the capsule length changes. | ||
111 | private float m_tiltMagnitudeWhenProjectedOnXYPlane = 0.1131371f; // used to introduce a fixed tilt because a straight-up capsule falls through terrain, probably a bug in terrain collider | ||
112 | |||
113 | |||
114 | private float m_buoyancy = 0f; | ||
115 | |||
116 | // private CollisionLocker ode; | ||
117 | |||
118 | private string m_name = String.Empty; | ||
119 | |||
120 | private bool[] m_colliderarr = new bool[11]; | ||
121 | private bool[] m_colliderGroundarr = new bool[11]; | ||
122 | |||
123 | // Default we're a Character | ||
124 | private CollisionCategories m_collisionCategories = (CollisionCategories.Character); | ||
125 | |||
126 | // Default, Collide with Other Geometries, spaces, bodies and characters. | ||
127 | private CollisionCategories m_collisionFlags = (CollisionCategories.Geom | ||
128 | | CollisionCategories.Space | ||
129 | | CollisionCategories.Body | ||
130 | | CollisionCategories.Character | ||
131 | | CollisionCategories.Land); | ||
132 | public IntPtr Body = IntPtr.Zero; | ||
133 | private OdeScene _parent_scene; | ||
134 | public IntPtr Shell = IntPtr.Zero; | ||
135 | public IntPtr Amotor = IntPtr.Zero; | ||
136 | public d.Mass ShellMass; | ||
137 | public bool collidelock = false; | ||
138 | |||
139 | public int m_eventsubscription = 0; | ||
140 | private CollisionEventUpdate CollisionEventsThisFrame = new CollisionEventUpdate(); | ||
141 | |||
142 | // unique UUID of this character object | ||
143 | public UUID m_uuid; | ||
144 | public bool bad = false; | ||
145 | |||
146 | public OdeCharacter(String avName, OdeScene parent_scene, Vector3 pos, CollisionLocker dode, Vector3 size, float pid_d, float pid_p, float capsule_radius, float tensor, float density, float height_fudge_factor, float walk_divisor, float rundivisor) | ||
147 | { | ||
148 | m_uuid = UUID.Random(); | ||
149 | |||
150 | if (pos.IsFinite()) | ||
151 | { | ||
152 | if (pos.Z > 9999999f) | ||
153 | { | ||
154 | pos.Z = parent_scene.GetTerrainHeightAtXY(127, 127) + 5; | ||
155 | } | ||
156 | if (pos.Z < -90000f) | ||
157 | { | ||
158 | pos.Z = parent_scene.GetTerrainHeightAtXY(127, 127) + 5; | ||
159 | } | ||
160 | _position = pos; | ||
161 | m_taintPosition.X = pos.X; | ||
162 | m_taintPosition.Y = pos.Y; | ||
163 | m_taintPosition.Z = pos.Z; | ||
164 | } | ||
165 | else | ||
166 | { | ||
167 | _position = new Vector3(((float)_parent_scene.WorldExtents.X * 0.5f), ((float)_parent_scene.WorldExtents.Y * 0.5f), parent_scene.GetTerrainHeightAtXY(128f, 128f) + 10f); | ||
168 | m_taintPosition.X = _position.X; | ||
169 | m_taintPosition.Y = _position.Y; | ||
170 | m_taintPosition.Z = _position.Z; | ||
171 | m_log.Warn("[PHYSICS]: Got NaN Position on Character Create"); | ||
172 | } | ||
173 | |||
174 | _parent_scene = parent_scene; | ||
175 | |||
176 | PID_D = pid_d; | ||
177 | PID_P = pid_p; | ||
178 | CAPSULE_RADIUS = capsule_radius; | ||
179 | m_tensor = tensor; | ||
180 | m_density = density; | ||
181 | heightFudgeFactor = height_fudge_factor; | ||
182 | walkDivisor = walk_divisor; | ||
183 | runDivisor = rundivisor; | ||
184 | |||
185 | // m_StandUpRotation = | ||
186 | // new d.Matrix3(0.5f, 0.7071068f, 0.5f, -0.7071068f, 0f, 0.7071068f, 0.5f, -0.7071068f, | ||
187 | // 0.5f); | ||
188 | |||
189 | for (int i = 0; i < 11; i++) | ||
190 | { | ||
191 | m_colliderarr[i] = false; | ||
192 | } | ||
193 | CAPSULE_LENGTH = (size.Z * 1.15f) - CAPSULE_RADIUS * 2.0f; | ||
194 | //m_log.Info("[SIZE]: " + CAPSULE_LENGTH.ToString()); | ||
195 | m_tainted_CAPSULE_LENGTH = CAPSULE_LENGTH; | ||
196 | |||
197 | m_isPhysical = false; // current status: no ODE information exists | ||
198 | m_tainted_isPhysical = true; // new tainted status: need to create ODE information | ||
199 | |||
200 | _parent_scene.AddPhysicsActorTaint(this); | ||
201 | |||
202 | m_name = avName; | ||
203 | } | ||
204 | |||
205 | public override int PhysicsActorType | ||
206 | { | ||
207 | get { return (int) ActorTypes.Agent; } | ||
208 | set { return; } | ||
209 | } | ||
210 | |||
211 | /// <summary> | ||
212 | /// If this is set, the avatar will move faster | ||
213 | /// </summary> | ||
214 | public override bool SetAlwaysRun | ||
215 | { | ||
216 | get { return m_alwaysRun; } | ||
217 | set { m_alwaysRun = value; } | ||
218 | } | ||
219 | |||
220 | public override uint LocalID | ||
221 | { | ||
222 | set { m_localID = value; } | ||
223 | } | ||
224 | |||
225 | public override bool Grabbed | ||
226 | { | ||
227 | set { return; } | ||
228 | } | ||
229 | |||
230 | public override bool Selected | ||
231 | { | ||
232 | set { return; } | ||
233 | } | ||
234 | |||
235 | public override float Buoyancy | ||
236 | { | ||
237 | get { return m_buoyancy; } | ||
238 | set { m_buoyancy = value; } | ||
239 | } | ||
240 | |||
241 | public override bool FloatOnWater | ||
242 | { | ||
243 | set { return; } | ||
244 | } | ||
245 | |||
246 | public override bool IsPhysical | ||
247 | { | ||
248 | get { return false; } | ||
249 | set { return; } | ||
250 | } | ||
251 | |||
252 | public override bool ThrottleUpdates | ||
253 | { | ||
254 | get { return false; } | ||
255 | set { return; } | ||
256 | } | ||
257 | |||
258 | public override bool Flying | ||
259 | { | ||
260 | get { return flying; } | ||
261 | set { flying = value; } | ||
262 | } | ||
263 | |||
264 | /// <summary> | ||
265 | /// Returns if the avatar is colliding in general. | ||
266 | /// This includes the ground and objects and avatar. | ||
267 | /// </summary> | ||
268 | public override bool IsColliding | ||
269 | { | ||
270 | get { return m_iscolliding; } | ||
271 | set | ||
272 | { | ||
273 | int i; | ||
274 | int truecount = 0; | ||
275 | int falsecount = 0; | ||
276 | |||
277 | if (m_colliderarr.Length >= 10) | ||
278 | { | ||
279 | for (i = 0; i < 10; i++) | ||
280 | { | ||
281 | m_colliderarr[i] = m_colliderarr[i + 1]; | ||
282 | } | ||
283 | } | ||
284 | m_colliderarr[10] = value; | ||
285 | |||
286 | for (i = 0; i < 11; i++) | ||
287 | { | ||
288 | if (m_colliderarr[i]) | ||
289 | { | ||
290 | truecount++; | ||
291 | } | ||
292 | else | ||
293 | { | ||
294 | falsecount++; | ||
295 | } | ||
296 | } | ||
297 | |||
298 | // Equal truecounts and false counts means we're colliding with something. | ||
299 | |||
300 | if (falsecount > 1.2*truecount) | ||
301 | { | ||
302 | m_iscolliding = false; | ||
303 | } | ||
304 | else | ||
305 | { | ||
306 | m_iscolliding = true; | ||
307 | } | ||
308 | if (m_wascolliding != m_iscolliding) | ||
309 | { | ||
310 | //base.SendCollisionUpdate(new CollisionEventUpdate()); | ||
311 | } | ||
312 | m_wascolliding = m_iscolliding; | ||
313 | } | ||
314 | } | ||
315 | |||
316 | /// <summary> | ||
317 | /// Returns if an avatar is colliding with the ground | ||
318 | /// </summary> | ||
319 | public override bool CollidingGround | ||
320 | { | ||
321 | get { return m_iscollidingGround; } | ||
322 | set | ||
323 | { | ||
324 | // Collisions against the ground are not really reliable | ||
325 | // So, to get a consistant value we have to average the current result over time | ||
326 | // Currently we use 1 second = 10 calls to this. | ||
327 | int i; | ||
328 | int truecount = 0; | ||
329 | int falsecount = 0; | ||
330 | |||
331 | if (m_colliderGroundarr.Length >= 10) | ||
332 | { | ||
333 | for (i = 0; i < 10; i++) | ||
334 | { | ||
335 | m_colliderGroundarr[i] = m_colliderGroundarr[i + 1]; | ||
336 | } | ||
337 | } | ||
338 | m_colliderGroundarr[10] = value; | ||
339 | |||
340 | for (i = 0; i < 11; i++) | ||
341 | { | ||
342 | if (m_colliderGroundarr[i]) | ||
343 | { | ||
344 | truecount++; | ||
345 | } | ||
346 | else | ||
347 | { | ||
348 | falsecount++; | ||
349 | } | ||
350 | } | ||
351 | |||
352 | // Equal truecounts and false counts means we're colliding with something. | ||
353 | |||
354 | if (falsecount > 1.2*truecount) | ||
355 | { | ||
356 | m_iscollidingGround = false; | ||
357 | } | ||
358 | else | ||
359 | { | ||
360 | m_iscollidingGround = true; | ||
361 | } | ||
362 | if (m_wascollidingGround != m_iscollidingGround) | ||
363 | { | ||
364 | //base.SendCollisionUpdate(new CollisionEventUpdate()); | ||
365 | } | ||
366 | m_wascollidingGround = m_iscollidingGround; | ||
367 | } | ||
368 | } | ||
369 | |||
370 | /// <summary> | ||
371 | /// Returns if the avatar is colliding with an object | ||
372 | /// </summary> | ||
373 | public override bool CollidingObj | ||
374 | { | ||
375 | get { return m_iscollidingObj; } | ||
376 | set | ||
377 | { | ||
378 | m_iscollidingObj = value; | ||
379 | if (value) | ||
380 | m_pidControllerActive = false; | ||
381 | else | ||
382 | m_pidControllerActive = true; | ||
383 | } | ||
384 | } | ||
385 | |||
386 | /// <summary> | ||
387 | /// turn the PID controller on or off. | ||
388 | /// The PID Controller will turn on all by itself in many situations | ||
389 | /// </summary> | ||
390 | /// <param name="status"></param> | ||
391 | public void SetPidStatus(bool status) | ||
392 | { | ||
393 | m_pidControllerActive = status; | ||
394 | } | ||
395 | |||
396 | public override bool Stopped | ||
397 | { | ||
398 | get { return _zeroFlag; } | ||
399 | } | ||
400 | |||
401 | /// <summary> | ||
402 | /// This 'puts' an avatar somewhere in the physics space. | ||
403 | /// Not really a good choice unless you 'know' it's a good | ||
404 | /// spot otherwise you're likely to orbit the avatar. | ||
405 | /// </summary> | ||
406 | public override Vector3 Position | ||
407 | { | ||
408 | get { return _position; } | ||
409 | set | ||
410 | { | ||
411 | if (Body == IntPtr.Zero || Shell == IntPtr.Zero) | ||
412 | { | ||
413 | if (value.IsFinite()) | ||
414 | { | ||
415 | if (value.Z > 9999999f) | ||
416 | { | ||
417 | value.Z = _parent_scene.GetTerrainHeightAtXY(127, 127) + 5; | ||
418 | } | ||
419 | if (value.Z < -90000f) | ||
420 | { | ||
421 | value.Z = _parent_scene.GetTerrainHeightAtXY(127, 127) + 5; | ||
422 | } | ||
423 | |||
424 | _position.X = value.X; | ||
425 | _position.Y = value.Y; | ||
426 | _position.Z = value.Z; | ||
427 | |||
428 | m_taintPosition.X = value.X; | ||
429 | m_taintPosition.Y = value.Y; | ||
430 | m_taintPosition.Z = value.Z; | ||
431 | _parent_scene.AddPhysicsActorTaint(this); | ||
432 | } | ||
433 | else | ||
434 | { | ||
435 | m_log.Warn("[PHYSICS]: Got a NaN Position from Scene on a Character"); | ||
436 | } | ||
437 | } | ||
438 | } | ||
439 | } | ||
440 | |||
441 | public override Vector3 RotationalVelocity | ||
442 | { | ||
443 | get { return m_rotationalVelocity; } | ||
444 | set { m_rotationalVelocity = value; } | ||
445 | } | ||
446 | |||
447 | /// <summary> | ||
448 | /// This property sets the height of the avatar only. We use the height to make sure the avatar stands up straight | ||
449 | /// and use it to offset landings properly | ||
450 | /// </summary> | ||
451 | public override Vector3 Size | ||
452 | { | ||
453 | get { return new Vector3(CAPSULE_RADIUS * 2, CAPSULE_RADIUS * 2, CAPSULE_LENGTH); } | ||
454 | set | ||
455 | { | ||
456 | if (value.IsFinite()) | ||
457 | { | ||
458 | m_pidControllerActive = true; | ||
459 | |||
460 | Vector3 SetSize = value; | ||
461 | m_tainted_CAPSULE_LENGTH = (SetSize.Z*1.15f) - CAPSULE_RADIUS*2.0f; | ||
462 | //m_log.Info("[SIZE]: " + CAPSULE_LENGTH.ToString()); | ||
463 | |||
464 | Velocity = Vector3.Zero; | ||
465 | |||
466 | _parent_scene.AddPhysicsActorTaint(this); | ||
467 | } | ||
468 | else | ||
469 | { | ||
470 | m_log.Warn("[PHYSICS]: Got a NaN Size from Scene on a Character"); | ||
471 | } | ||
472 | } | ||
473 | } | ||
474 | |||
475 | private void AlignAvatarTiltWithCurrentDirectionOfMovement(Vector3 movementVector) | ||
476 | { | ||
477 | movementVector.Z = 0f; | ||
478 | float magnitude = (float)Math.Sqrt((double)(movementVector.X * movementVector.X + movementVector.Y * movementVector.Y)); | ||
479 | if (magnitude < 0.1f) return; | ||
480 | |||
481 | // normalize the velocity vector | ||
482 | float invMagnitude = 1.0f / magnitude; | ||
483 | movementVector.X *= invMagnitude; | ||
484 | movementVector.Y *= invMagnitude; | ||
485 | |||
486 | // if we change the capsule heading too often, the capsule can fall down | ||
487 | // therefore we snap movement vector to just 1 of 4 predefined directions (ne, nw, se, sw), | ||
488 | // meaning only 4 possible capsule tilt orientations | ||
489 | if (movementVector.X > 0) | ||
490 | { | ||
491 | // east | ||
492 | if (movementVector.Y > 0) | ||
493 | { | ||
494 | // northeast | ||
495 | movementVector.X = (float)Math.Sqrt(2.0); | ||
496 | movementVector.Y = (float)Math.Sqrt(2.0); | ||
497 | } | ||
498 | else | ||
499 | { | ||
500 | // southeast | ||
501 | movementVector.X = (float)Math.Sqrt(2.0); | ||
502 | movementVector.Y = -(float)Math.Sqrt(2.0); | ||
503 | } | ||
504 | } | ||
505 | else | ||
506 | { | ||
507 | // west | ||
508 | if (movementVector.Y > 0) | ||
509 | { | ||
510 | // northwest | ||
511 | movementVector.X = -(float)Math.Sqrt(2.0); | ||
512 | movementVector.Y = (float)Math.Sqrt(2.0); | ||
513 | } | ||
514 | else | ||
515 | { | ||
516 | // southwest | ||
517 | movementVector.X = -(float)Math.Sqrt(2.0); | ||
518 | movementVector.Y = -(float)Math.Sqrt(2.0); | ||
519 | } | ||
520 | } | ||
521 | |||
522 | |||
523 | // movementVector.Z is zero | ||
524 | |||
525 | // calculate tilt components based on desired amount of tilt and current (snapped) heading. | ||
526 | // the "-" sign is to force the tilt to be OPPOSITE the direction of movement. | ||
527 | float xTiltComponent = -movementVector.X * m_tiltMagnitudeWhenProjectedOnXYPlane; | ||
528 | float yTiltComponent = -movementVector.Y * m_tiltMagnitudeWhenProjectedOnXYPlane; | ||
529 | |||
530 | //m_log.Debug("[PHYSICS] changing avatar tilt"); | ||
531 | d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, xTiltComponent); | ||
532 | d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, xTiltComponent); // must be same as lowstop, else a different, spurious tilt is introduced | ||
533 | d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, yTiltComponent); | ||
534 | d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, yTiltComponent); // same as lowstop | ||
535 | d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, 0f); | ||
536 | d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0f); // same as lowstop | ||
537 | } | ||
538 | |||
539 | /// <summary> | ||
540 | /// This creates the Avatar's physical Surrogate at the position supplied | ||
541 | /// </summary> | ||
542 | /// <param name="npositionX"></param> | ||
543 | /// <param name="npositionY"></param> | ||
544 | /// <param name="npositionZ"></param> | ||
545 | |||
546 | // WARNING: This MUST NOT be called outside of ProcessTaints, else we can have unsynchronized access | ||
547 | // to ODE internals. ProcessTaints is called from within thread-locked Simulate(), so it is the only | ||
548 | // place that is safe to call this routine AvatarGeomAndBodyCreation. | ||
549 | private void AvatarGeomAndBodyCreation(float npositionX, float npositionY, float npositionZ, float tensor) | ||
550 | { | ||
551 | //CAPSULE_LENGTH = -5; | ||
552 | //CAPSULE_RADIUS = -5; | ||
553 | int dAMotorEuler = 1; | ||
554 | _parent_scene.waitForSpaceUnlock(_parent_scene.space); | ||
555 | if (CAPSULE_LENGTH <= 0) | ||
556 | { | ||
557 | m_log.Warn("[PHYSICS]: The capsule size you specified in opensim.ini is invalid! Setting it to the smallest possible size!"); | ||
558 | CAPSULE_LENGTH = 0.01f; | ||
559 | |||
560 | } | ||
561 | |||
562 | if (CAPSULE_RADIUS <= 0) | ||
563 | { | ||
564 | m_log.Warn("[PHYSICS]: The capsule size you specified in opensim.ini is invalid! Setting it to the smallest possible size!"); | ||
565 | CAPSULE_RADIUS = 0.01f; | ||
566 | |||
567 | } | ||
568 | Shell = d.CreateCapsule(_parent_scene.space, CAPSULE_RADIUS, CAPSULE_LENGTH); | ||
569 | |||
570 | d.GeomSetCategoryBits(Shell, (int)m_collisionCategories); | ||
571 | d.GeomSetCollideBits(Shell, (int)m_collisionFlags); | ||
572 | |||
573 | d.MassSetCapsuleTotal(out ShellMass, m_mass, 2, CAPSULE_RADIUS, CAPSULE_LENGTH); | ||
574 | Body = d.BodyCreate(_parent_scene.world); | ||
575 | d.BodySetPosition(Body, npositionX, npositionY, npositionZ); | ||
576 | |||
577 | _position.X = npositionX; | ||
578 | _position.Y = npositionY; | ||
579 | _position.Z = npositionZ; | ||
580 | |||
581 | |||
582 | m_taintPosition.X = npositionX; | ||
583 | m_taintPosition.Y = npositionY; | ||
584 | m_taintPosition.Z = npositionZ; | ||
585 | |||
586 | d.BodySetMass(Body, ref ShellMass); | ||
587 | d.Matrix3 m_caprot; | ||
588 | // 90 Stand up on the cap of the capped cyllinder | ||
589 | if (_parent_scene.IsAvCapsuleTilted) | ||
590 | { | ||
591 | d.RFromAxisAndAngle(out m_caprot, 1, 0, 1, (float)(Math.PI / 2)); | ||
592 | } | ||
593 | else | ||
594 | { | ||
595 | d.RFromAxisAndAngle(out m_caprot, 0, 0, 1, (float)(Math.PI / 2)); | ||
596 | } | ||
597 | |||
598 | |||
599 | d.GeomSetRotation(Shell, ref m_caprot); | ||
600 | d.BodySetRotation(Body, ref m_caprot); | ||
601 | |||
602 | d.GeomSetBody(Shell, Body); | ||
603 | |||
604 | |||
605 | // The purpose of the AMotor here is to keep the avatar's physical | ||
606 | // surrogate from rotating while moving | ||
607 | Amotor = d.JointCreateAMotor(_parent_scene.world, IntPtr.Zero); | ||
608 | d.JointAttach(Amotor, Body, IntPtr.Zero); | ||
609 | d.JointSetAMotorMode(Amotor, dAMotorEuler); | ||
610 | d.JointSetAMotorNumAxes(Amotor, 3); | ||
611 | d.JointSetAMotorAxis(Amotor, 0, 0, 1, 0, 0); | ||
612 | d.JointSetAMotorAxis(Amotor, 1, 0, 0, 1, 0); | ||
613 | d.JointSetAMotorAxis(Amotor, 2, 0, 0, 0, 1); | ||
614 | d.JointSetAMotorAngle(Amotor, 0, 0); | ||
615 | d.JointSetAMotorAngle(Amotor, 1, 0); | ||
616 | d.JointSetAMotorAngle(Amotor, 2, 0); | ||
617 | |||
618 | // These lowstops and high stops are effectively (no wiggle room) | ||
619 | if (_parent_scene.IsAvCapsuleTilted) | ||
620 | { | ||
621 | d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, -0.000000000001f); | ||
622 | d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, -0.000000000001f); | ||
623 | d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, -0.000000000001f); | ||
624 | d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, 0.000000000001f); | ||
625 | d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0.000000000001f); | ||
626 | d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, 0.000000000001f); | ||
627 | } | ||
628 | else | ||
629 | { | ||
630 | #region Documentation of capsule motor LowStop and HighStop parameters | ||
631 | // Intentionally introduce some tilt into the capsule by setting | ||
632 | // the motor stops to small epsilon values. This small tilt prevents | ||
633 | // the capsule from falling into the terrain; a straight-up capsule | ||
634 | // (with -0..0 motor stops) falls into the terrain for reasons yet | ||
635 | // to be comprehended in their entirety. | ||
636 | #endregion | ||
637 | AlignAvatarTiltWithCurrentDirectionOfMovement(Vector3.Zero); | ||
638 | d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, 0.08f); | ||
639 | d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, -0f); | ||
640 | d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, 0.08f); | ||
641 | d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, 0.08f); // must be same as lowstop, else a different, spurious tilt is introduced | ||
642 | d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0f); // same as lowstop | ||
643 | d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, 0.08f); // same as lowstop | ||
644 | } | ||
645 | |||
646 | // Fudge factor is 1f by default, we're setting it to 0. We don't want it to Fudge or the | ||
647 | // capped cyllinder will fall over | ||
648 | d.JointSetAMotorParam(Amotor, (int)dParam.FudgeFactor, 0f); | ||
649 | d.JointSetAMotorParam(Amotor, (int)dParam.FMax, tensor); | ||
650 | |||
651 | //d.Matrix3 bodyrotation = d.BodyGetRotation(Body); | ||
652 | //d.QfromR( | ||
653 | //d.Matrix3 checkrotation = new d.Matrix3(0.7071068,0.5, -0.7071068, | ||
654 | // | ||
655 | //m_log.Info("[PHYSICSAV]: Rotation: " + bodyrotation.M00 + " : " + bodyrotation.M01 + " : " + bodyrotation.M02 + " : " + bodyrotation.M10 + " : " + bodyrotation.M11 + " : " + bodyrotation.M12 + " : " + bodyrotation.M20 + " : " + bodyrotation.M21 + " : " + bodyrotation.M22); | ||
656 | //standupStraight(); | ||
657 | } | ||
658 | |||
659 | // | ||
660 | /// <summary> | ||
661 | /// Uses the capped cyllinder volume formula to calculate the avatar's mass. | ||
662 | /// This may be used in calculations in the scene/scenepresence | ||
663 | /// </summary> | ||
664 | public override float Mass | ||
665 | { | ||
666 | get | ||
667 | { | ||
668 | float AVvolume = (float) (Math.PI*Math.Pow(CAPSULE_RADIUS, 2)*CAPSULE_LENGTH); | ||
669 | return m_density*AVvolume; | ||
670 | } | ||
671 | } | ||
672 | public override void link(PhysicsActor obj) | ||
673 | { | ||
674 | |||
675 | } | ||
676 | |||
677 | public override void delink() | ||
678 | { | ||
679 | |||
680 | } | ||
681 | |||
682 | public override void LockAngularMotion(Vector3 axis) | ||
683 | { | ||
684 | |||
685 | } | ||
686 | |||
687 | // This code is very useful. Written by DanX0r. We're just not using it right now. | ||
688 | // Commented out to prevent a warning. | ||
689 | // | ||
690 | // private void standupStraight() | ||
691 | // { | ||
692 | // // The purpose of this routine here is to quickly stabilize the Body while it's popped up in the air. | ||
693 | // // The amotor needs a few seconds to stabilize so without it, the avatar shoots up sky high when you | ||
694 | // // change appearance and when you enter the simulator | ||
695 | // // After this routine is done, the amotor stabilizes much quicker | ||
696 | // d.Vector3 feet; | ||
697 | // d.Vector3 head; | ||
698 | // d.BodyGetRelPointPos(Body, 0.0f, 0.0f, -1.0f, out feet); | ||
699 | // d.BodyGetRelPointPos(Body, 0.0f, 0.0f, 1.0f, out head); | ||
700 | // float posture = head.Z - feet.Z; | ||
701 | |||
702 | // // restoring force proportional to lack of posture: | ||
703 | // float servo = (2.5f - posture) * POSTURE_SERVO; | ||
704 | // d.BodyAddForceAtRelPos(Body, 0.0f, 0.0f, servo, 0.0f, 0.0f, 1.0f); | ||
705 | // d.BodyAddForceAtRelPos(Body, 0.0f, 0.0f, -servo, 0.0f, 0.0f, -1.0f); | ||
706 | // //d.Matrix3 bodyrotation = d.BodyGetRotation(Body); | ||
707 | // //m_log.Info("[PHYSICSAV]: Rotation: " + bodyrotation.M00 + " : " + bodyrotation.M01 + " : " + bodyrotation.M02 + " : " + bodyrotation.M10 + " : " + bodyrotation.M11 + " : " + bodyrotation.M12 + " : " + bodyrotation.M20 + " : " + bodyrotation.M21 + " : " + bodyrotation.M22); | ||
708 | // } | ||
709 | |||
710 | public override Vector3 Force | ||
711 | { | ||
712 | get { return _target_velocity; } | ||
713 | set { return; } | ||
714 | } | ||
715 | |||
716 | public override int VehicleType | ||
717 | { | ||
718 | get { return 0; } | ||
719 | set { return; } | ||
720 | } | ||
721 | |||
722 | public override void VehicleFloatParam(int param, float value) | ||
723 | { | ||
724 | |||
725 | } | ||
726 | |||
727 | public override void VehicleVectorParam(int param, Vector3 value) | ||
728 | { | ||
729 | |||
730 | } | ||
731 | |||
732 | public override void VehicleRotationParam(int param, Quaternion rotation) | ||
733 | { | ||
734 | |||
735 | } | ||
736 | |||
737 | public override void SetVolumeDetect(int param) | ||
738 | { | ||
739 | |||
740 | } | ||
741 | |||
742 | public override Vector3 CenterOfMass | ||
743 | { | ||
744 | get { return Vector3.Zero; } | ||
745 | } | ||
746 | |||
747 | public override Vector3 GeometricCenter | ||
748 | { | ||
749 | get { return Vector3.Zero; } | ||
750 | } | ||
751 | |||
752 | public override PrimitiveBaseShape Shape | ||
753 | { | ||
754 | set { return; } | ||
755 | } | ||
756 | |||
757 | public override Vector3 Velocity | ||
758 | { | ||
759 | get { | ||
760 | // There's a problem with Vector3.Zero! Don't Use it Here! | ||
761 | if (_zeroFlag) | ||
762 | return Vector3.Zero; | ||
763 | m_lastUpdateSent = false; | ||
764 | return _velocity; | ||
765 | } | ||
766 | set | ||
767 | { | ||
768 | if (value.IsFinite()) | ||
769 | { | ||
770 | m_pidControllerActive = true; | ||
771 | _target_velocity = value; | ||
772 | } | ||
773 | else | ||
774 | { | ||
775 | m_log.Warn("[PHYSICS]: Got a NaN velocity from Scene in a Character"); | ||
776 | } | ||
777 | } | ||
778 | } | ||
779 | |||
780 | public override Vector3 Torque | ||
781 | { | ||
782 | get { return Vector3.Zero; } | ||
783 | set { return; } | ||
784 | } | ||
785 | |||
786 | public override float CollisionScore | ||
787 | { | ||
788 | get { return 0f; } | ||
789 | set { } | ||
790 | } | ||
791 | |||
792 | public override bool Kinematic | ||
793 | { | ||
794 | get { return false; } | ||
795 | set { } | ||
796 | } | ||
797 | |||
798 | public override Quaternion Orientation | ||
799 | { | ||
800 | get { return Quaternion.Identity; } | ||
801 | set { | ||
802 | //Matrix3 or = Orientation.ToRotationMatrix(); | ||
803 | //d.Matrix3 ord = new d.Matrix3(or.m00, or.m10, or.m20, or.m01, or.m11, or.m21, or.m02, or.m12, or.m22); | ||
804 | //d.BodySetRotation(Body, ref ord); | ||
805 | } | ||
806 | } | ||
807 | |||
808 | public override Vector3 Acceleration | ||
809 | { | ||
810 | get { return _acceleration; } | ||
811 | } | ||
812 | |||
813 | public void SetAcceleration(Vector3 accel) | ||
814 | { | ||
815 | m_pidControllerActive = true; | ||
816 | _acceleration = accel; | ||
817 | } | ||
818 | |||
819 | /// <summary> | ||
820 | /// Adds the force supplied to the Target Velocity | ||
821 | /// The PID controller takes this target velocity and tries to make it a reality | ||
822 | /// </summary> | ||
823 | /// <param name="force"></param> | ||
824 | public override void AddForce(Vector3 force, bool pushforce) | ||
825 | { | ||
826 | if (force.IsFinite()) | ||
827 | { | ||
828 | if (pushforce) | ||
829 | { | ||
830 | m_pidControllerActive = false; | ||
831 | force *= 100f; | ||
832 | doForce(force); | ||
833 | // If uncommented, things get pushed off world | ||
834 | // | ||
835 | // m_log.Debug("Push!"); | ||
836 | // _target_velocity.X += force.X; | ||
837 | // _target_velocity.Y += force.Y; | ||
838 | // _target_velocity.Z += force.Z; | ||
839 | } | ||
840 | else | ||
841 | { | ||
842 | m_pidControllerActive = true; | ||
843 | _target_velocity.X += force.X; | ||
844 | _target_velocity.Y += force.Y; | ||
845 | _target_velocity.Z += force.Z; | ||
846 | } | ||
847 | } | ||
848 | else | ||
849 | { | ||
850 | m_log.Warn("[PHYSICS]: Got a NaN force applied to a Character"); | ||
851 | } | ||
852 | //m_lastUpdateSent = false; | ||
853 | } | ||
854 | |||
855 | public override void AddAngularForce(Vector3 force, bool pushforce) | ||
856 | { | ||
857 | |||
858 | } | ||
859 | |||
860 | /// <summary> | ||
861 | /// After all of the forces add up with 'add force' we apply them with doForce | ||
862 | /// </summary> | ||
863 | /// <param name="force"></param> | ||
864 | public void doForce(Vector3 force) | ||
865 | { | ||
866 | if (!collidelock) | ||
867 | { | ||
868 | d.BodyAddForce(Body, force.X, force.Y, force.Z); | ||
869 | //d.BodySetRotation(Body, ref m_StandUpRotation); | ||
870 | //standupStraight(); | ||
871 | |||
872 | } | ||
873 | } | ||
874 | |||
875 | public override void SetMomentum(Vector3 momentum) | ||
876 | { | ||
877 | } | ||
878 | |||
879 | |||
880 | /// <summary> | ||
881 | /// Called from Simulate | ||
882 | /// This is the avatar's movement control + PID Controller | ||
883 | /// </summary> | ||
884 | /// <param name="timeStep"></param> | ||
885 | public void Move(float timeStep, List<OdeCharacter> defects) | ||
886 | { | ||
887 | // no lock; for now it's only called from within Simulate() | ||
888 | |||
889 | // If the PID Controller isn't active then we set our force | ||
890 | // calculating base velocity to the current position | ||
891 | |||
892 | if (Body == IntPtr.Zero) | ||
893 | return; | ||
894 | |||
895 | if (m_pidControllerActive == false) | ||
896 | { | ||
897 | _zeroPosition = d.BodyGetPosition(Body); | ||
898 | } | ||
899 | //PidStatus = true; | ||
900 | |||
901 | d.Vector3 localpos = d.BodyGetPosition(Body); | ||
902 | Vector3 localPos = new Vector3(localpos.X, localpos.Y, localpos.Z); | ||
903 | |||
904 | if (!localPos.IsFinite()) | ||
905 | { | ||
906 | |||
907 | m_log.Warn("[PHYSICS]: Avatar Position is non-finite!"); | ||
908 | defects.Add(this); | ||
909 | // _parent_scene.RemoveCharacter(this); | ||
910 | |||
911 | // destroy avatar capsule and related ODE data | ||
912 | if (Amotor != IntPtr.Zero) | ||
913 | { | ||
914 | // Kill the Amotor | ||
915 | d.JointDestroy(Amotor); | ||
916 | Amotor = IntPtr.Zero; | ||
917 | } | ||
918 | |||
919 | //kill the Geometry | ||
920 | _parent_scene.waitForSpaceUnlock(_parent_scene.space); | ||
921 | |||
922 | if (Body != IntPtr.Zero) | ||
923 | { | ||
924 | //kill the body | ||
925 | d.BodyDestroy(Body); | ||
926 | |||
927 | Body = IntPtr.Zero; | ||
928 | } | ||
929 | |||
930 | if (Shell != IntPtr.Zero) | ||
931 | { | ||
932 | d.GeomDestroy(Shell); | ||
933 | _parent_scene.geom_name_map.Remove(Shell); | ||
934 | Shell = IntPtr.Zero; | ||
935 | } | ||
936 | |||
937 | return; | ||
938 | } | ||
939 | |||
940 | Vector3 vec = Vector3.Zero; | ||
941 | d.Vector3 vel = d.BodyGetLinearVel(Body); | ||
942 | |||
943 | float movementdivisor = 1f; | ||
944 | |||
945 | if (!m_alwaysRun) | ||
946 | { | ||
947 | movementdivisor = walkDivisor; | ||
948 | } | ||
949 | else | ||
950 | { | ||
951 | movementdivisor = runDivisor; | ||
952 | } | ||
953 | |||
954 | // if velocity is zero, use position control; otherwise, velocity control | ||
955 | if (_target_velocity.X == 0.0f && _target_velocity.Y == 0.0f && _target_velocity.Z == 0.0f && m_iscolliding) | ||
956 | { | ||
957 | // keep track of where we stopped. No more slippin' & slidin' | ||
958 | if (!_zeroFlag) | ||
959 | { | ||
960 | _zeroFlag = true; | ||
961 | _zeroPosition = d.BodyGetPosition(Body); | ||
962 | } | ||
963 | if (m_pidControllerActive) | ||
964 | { | ||
965 | // We only want to deactivate the PID Controller if we think we want to have our surrogate | ||
966 | // react to the physics scene by moving it's position. | ||
967 | // Avatar to Avatar collisions | ||
968 | // Prim to avatar collisions | ||
969 | |||
970 | d.Vector3 pos = d.BodyGetPosition(Body); | ||
971 | vec.X = (_target_velocity.X - vel.X) * (PID_D) + (_zeroPosition.X - pos.X) * (PID_P * 2); | ||
972 | vec.Y = (_target_velocity.Y - vel.Y)*(PID_D) + (_zeroPosition.Y - pos.Y)* (PID_P * 2); | ||
973 | if (flying) | ||
974 | { | ||
975 | vec.Z = (_target_velocity.Z - vel.Z) * (PID_D) + (_zeroPosition.Z - pos.Z) * PID_P; | ||
976 | } | ||
977 | } | ||
978 | //PidStatus = true; | ||
979 | } | ||
980 | else | ||
981 | { | ||
982 | m_pidControllerActive = true; | ||
983 | _zeroFlag = false; | ||
984 | if (m_iscolliding && !flying) | ||
985 | { | ||
986 | // We're standing on something | ||
987 | vec.X = ((_target_velocity.X / movementdivisor) - vel.X) * (PID_D); | ||
988 | vec.Y = ((_target_velocity.Y / movementdivisor) - vel.Y) * (PID_D); | ||
989 | } | ||
990 | else if (m_iscolliding && flying) | ||
991 | { | ||
992 | // We're flying and colliding with something | ||
993 | vec.X = ((_target_velocity.X/movementdivisor) - vel.X)*(PID_D / 16); | ||
994 | vec.Y = ((_target_velocity.Y/movementdivisor) - vel.Y)*(PID_D / 16); | ||
995 | } | ||
996 | else if (!m_iscolliding && flying) | ||
997 | { | ||
998 | // we're in mid air suspended | ||
999 | vec.X = ((_target_velocity.X / movementdivisor) - vel.X) * (PID_D/6); | ||
1000 | vec.Y = ((_target_velocity.Y / movementdivisor) - vel.Y) * (PID_D/6); | ||
1001 | } | ||
1002 | |||
1003 | if (m_iscolliding && !flying && _target_velocity.Z > 0.0f) | ||
1004 | { | ||
1005 | // We're colliding with something and we're not flying but we're moving | ||
1006 | // This means we're walking or running. | ||
1007 | d.Vector3 pos = d.BodyGetPosition(Body); | ||
1008 | vec.Z = (_target_velocity.Z - vel.Z)*PID_D + (_zeroPosition.Z - pos.Z)*PID_P; | ||
1009 | if (_target_velocity.X > 0) | ||
1010 | { | ||
1011 | vec.X = ((_target_velocity.X - vel.X)/1.2f)*PID_D; | ||
1012 | } | ||
1013 | if (_target_velocity.Y > 0) | ||
1014 | { | ||
1015 | vec.Y = ((_target_velocity.Y - vel.Y)/1.2f)*PID_D; | ||
1016 | } | ||
1017 | } | ||
1018 | else if (!m_iscolliding && !flying) | ||
1019 | { | ||
1020 | // we're not colliding and we're not flying so that means we're falling! | ||
1021 | // m_iscolliding includes collisions with the ground. | ||
1022 | |||
1023 | // d.Vector3 pos = d.BodyGetPosition(Body); | ||
1024 | if (_target_velocity.X > 0) | ||
1025 | { | ||
1026 | vec.X = ((_target_velocity.X - vel.X)/1.2f)*PID_D; | ||
1027 | } | ||
1028 | if (_target_velocity.Y > 0) | ||
1029 | { | ||
1030 | vec.Y = ((_target_velocity.Y - vel.Y)/1.2f)*PID_D; | ||
1031 | } | ||
1032 | } | ||
1033 | |||
1034 | if (flying) | ||
1035 | { | ||
1036 | vec.Z = (_target_velocity.Z - vel.Z) * (PID_D); | ||
1037 | } | ||
1038 | } | ||
1039 | if (flying) | ||
1040 | { | ||
1041 | vec.Z += ((-1 * _parent_scene.gravityz)*m_mass); | ||
1042 | |||
1043 | //Added for auto fly height. Kitto Flora | ||
1044 | //d.Vector3 pos = d.BodyGetPosition(Body); | ||
1045 | float target_altitude = _parent_scene.GetTerrainHeightAtXY(_position.X, _position.Y) + MinimumGroundFlightOffset; | ||
1046 | |||
1047 | if (_position.Z < target_altitude) | ||
1048 | { | ||
1049 | vec.Z += (target_altitude - _position.Z) * PID_P * 5.0f; | ||
1050 | } | ||
1051 | // end add Kitto Flora | ||
1052 | } | ||
1053 | if (vec.IsFinite()) | ||
1054 | { | ||
1055 | doForce(vec); | ||
1056 | if (!_zeroFlag) | ||
1057 | { | ||
1058 | AlignAvatarTiltWithCurrentDirectionOfMovement(vec); | ||
1059 | } | ||
1060 | } | ||
1061 | else | ||
1062 | { | ||
1063 | m_log.Warn("[PHYSICS]: Got a NaN force vector in Move()"); | ||
1064 | m_log.Warn("[PHYSICS]: Avatar Position is non-finite!"); | ||
1065 | defects.Add(this); | ||
1066 | // _parent_scene.RemoveCharacter(this); | ||
1067 | // destroy avatar capsule and related ODE data | ||
1068 | if (Amotor != IntPtr.Zero) | ||
1069 | { | ||
1070 | // Kill the Amotor | ||
1071 | d.JointDestroy(Amotor); | ||
1072 | Amotor = IntPtr.Zero; | ||
1073 | } | ||
1074 | //kill the Geometry | ||
1075 | _parent_scene.waitForSpaceUnlock(_parent_scene.space); | ||
1076 | |||
1077 | if (Body != IntPtr.Zero) | ||
1078 | { | ||
1079 | //kill the body | ||
1080 | d.BodyDestroy(Body); | ||
1081 | |||
1082 | Body = IntPtr.Zero; | ||
1083 | } | ||
1084 | |||
1085 | if (Shell != IntPtr.Zero) | ||
1086 | { | ||
1087 | d.GeomDestroy(Shell); | ||
1088 | _parent_scene.geom_name_map.Remove(Shell); | ||
1089 | Shell = IntPtr.Zero; | ||
1090 | } | ||
1091 | } | ||
1092 | } | ||
1093 | |||
1094 | /// <summary> | ||
1095 | /// Updates the reported position and velocity. This essentially sends the data up to ScenePresence. | ||
1096 | /// </summary> | ||
1097 | public void UpdatePositionAndVelocity() | ||
1098 | { | ||
1099 | // no lock; called from Simulate() -- if you call this from elsewhere, gotta lock or do Monitor.Enter/Exit! | ||
1100 | d.Vector3 vec; | ||
1101 | try | ||
1102 | { | ||
1103 | vec = d.BodyGetPosition(Body); | ||
1104 | } | ||
1105 | catch (NullReferenceException) | ||
1106 | { | ||
1107 | bad = true; | ||
1108 | _parent_scene.BadCharacter(this); | ||
1109 | vec = new d.Vector3(_position.X, _position.Y, _position.Z); | ||
1110 | base.RaiseOutOfBounds(_position); // Tells ScenePresence that there's a problem! | ||
1111 | m_log.WarnFormat("[ODEPLUGIN]: Avatar Null reference for Avatar {0}, physical actor {1}", m_name, m_uuid); | ||
1112 | } | ||
1113 | |||
1114 | |||
1115 | // kluge to keep things in bounds. ODE lets dead avatars drift away (they should be removed!) | ||
1116 | if (vec.X < 0.0f) vec.X = 0.0f; | ||
1117 | if (vec.Y < 0.0f) vec.Y = 0.0f; | ||
1118 | if (vec.X > (int)_parent_scene.WorldExtents.X - 0.05f) vec.X = (int)_parent_scene.WorldExtents.X - 0.05f; | ||
1119 | if (vec.Y > (int)_parent_scene.WorldExtents.Y - 0.05f) vec.Y = (int)_parent_scene.WorldExtents.Y - 0.05f; | ||
1120 | |||
1121 | _position.X = vec.X; | ||
1122 | _position.Y = vec.Y; | ||
1123 | _position.Z = vec.Z; | ||
1124 | |||
1125 | // Did we move last? = zeroflag | ||
1126 | // This helps keep us from sliding all over | ||
1127 | |||
1128 | if (_zeroFlag) | ||
1129 | { | ||
1130 | _velocity.X = 0.0f; | ||
1131 | _velocity.Y = 0.0f; | ||
1132 | _velocity.Z = 0.0f; | ||
1133 | |||
1134 | // Did we send out the 'stopped' message? | ||
1135 | if (!m_lastUpdateSent) | ||
1136 | { | ||
1137 | m_lastUpdateSent = true; | ||
1138 | //base.RequestPhysicsterseUpdate(); | ||
1139 | |||
1140 | } | ||
1141 | } | ||
1142 | else | ||
1143 | { | ||
1144 | m_lastUpdateSent = false; | ||
1145 | try | ||
1146 | { | ||
1147 | vec = d.BodyGetLinearVel(Body); | ||
1148 | } | ||
1149 | catch (NullReferenceException) | ||
1150 | { | ||
1151 | vec.X = _velocity.X; | ||
1152 | vec.Y = _velocity.Y; | ||
1153 | vec.Z = _velocity.Z; | ||
1154 | } | ||
1155 | _velocity.X = (vec.X); | ||
1156 | _velocity.Y = (vec.Y); | ||
1157 | |||
1158 | _velocity.Z = (vec.Z); | ||
1159 | |||
1160 | if (_velocity.Z < -6 && !m_hackSentFall) | ||
1161 | { | ||
1162 | m_hackSentFall = true; | ||
1163 | m_pidControllerActive = false; | ||
1164 | } | ||
1165 | else if (flying && !m_hackSentFly) | ||
1166 | { | ||
1167 | //m_hackSentFly = true; | ||
1168 | //base.SendCollisionUpdate(new CollisionEventUpdate()); | ||
1169 | } | ||
1170 | else | ||
1171 | { | ||
1172 | m_hackSentFly = false; | ||
1173 | m_hackSentFall = false; | ||
1174 | } | ||
1175 | } | ||
1176 | } | ||
1177 | |||
1178 | /// <summary> | ||
1179 | /// Cleanup the things we use in the scene. | ||
1180 | /// </summary> | ||
1181 | public void Destroy() | ||
1182 | { | ||
1183 | m_tainted_isPhysical = false; | ||
1184 | _parent_scene.AddPhysicsActorTaint(this); | ||
1185 | } | ||
1186 | |||
1187 | public override void CrossingFailure() | ||
1188 | { | ||
1189 | } | ||
1190 | |||
1191 | public override Vector3 PIDTarget { set { return; } } | ||
1192 | public override bool PIDActive { set { return; } } | ||
1193 | public override float PIDTau { set { return; } } | ||
1194 | |||
1195 | public override float PIDHoverHeight { set { return; } } | ||
1196 | public override bool PIDHoverActive { set { return; } } | ||
1197 | public override PIDHoverType PIDHoverType { set { return; } } | ||
1198 | public override float PIDHoverTau { set { return; } } | ||
1199 | |||
1200 | public override Quaternion APIDTarget{ set { return; } } | ||
1201 | |||
1202 | public override bool APIDActive{ set { return; } } | ||
1203 | |||
1204 | public override float APIDStrength{ set { return; } } | ||
1205 | |||
1206 | public override float APIDDamping{ set { return; } } | ||
1207 | |||
1208 | |||
1209 | public override void SubscribeEvents(int ms) | ||
1210 | { | ||
1211 | m_requestedUpdateFrequency = ms; | ||
1212 | m_eventsubscription = ms; | ||
1213 | _parent_scene.addCollisionEventReporting(this); | ||
1214 | } | ||
1215 | public override void UnSubscribeEvents() | ||
1216 | { | ||
1217 | _parent_scene.remCollisionEventReporting(this); | ||
1218 | m_requestedUpdateFrequency = 0; | ||
1219 | m_eventsubscription = 0; | ||
1220 | } | ||
1221 | public void AddCollisionEvent(uint CollidedWith, ContactPoint contact) | ||
1222 | { | ||
1223 | if (m_eventsubscription > 0) | ||
1224 | { | ||
1225 | CollisionEventsThisFrame.addCollider(CollidedWith, contact); | ||
1226 | } | ||
1227 | } | ||
1228 | |||
1229 | public void SendCollisions() | ||
1230 | { | ||
1231 | if (m_eventsubscription > m_requestedUpdateFrequency) | ||
1232 | { | ||
1233 | if (CollisionEventsThisFrame != null) | ||
1234 | { | ||
1235 | base.SendCollisionUpdate(CollisionEventsThisFrame); | ||
1236 | } | ||
1237 | CollisionEventsThisFrame = new CollisionEventUpdate(); | ||
1238 | m_eventsubscription = 0; | ||
1239 | } | ||
1240 | } | ||
1241 | public override bool SubscribedEvents() | ||
1242 | { | ||
1243 | if (m_eventsubscription > 0) | ||
1244 | return true; | ||
1245 | return false; | ||
1246 | } | ||
1247 | |||
1248 | public void ProcessTaints(float timestep) | ||
1249 | { | ||
1250 | |||
1251 | if (m_tainted_isPhysical != m_isPhysical) | ||
1252 | { | ||
1253 | if (m_tainted_isPhysical) | ||
1254 | { | ||
1255 | // Create avatar capsule and related ODE data | ||
1256 | if (!(Shell == IntPtr.Zero && Body == IntPtr.Zero && Amotor == IntPtr.Zero)) | ||
1257 | { | ||
1258 | m_log.Warn("[PHYSICS]: re-creating the following avatar ODE data, even though it already exists - " | ||
1259 | + (Shell!=IntPtr.Zero ? "Shell ":"") | ||
1260 | + (Body!=IntPtr.Zero ? "Body ":"") | ||
1261 | + (Amotor!=IntPtr.Zero ? "Amotor ":"")); | ||
1262 | } | ||
1263 | AvatarGeomAndBodyCreation(_position.X, _position.Y, _position.Z, m_tensor); | ||
1264 | |||
1265 | _parent_scene.geom_name_map[Shell] = m_name; | ||
1266 | _parent_scene.actor_name_map[Shell] = (PhysicsActor)this; | ||
1267 | _parent_scene.AddCharacter(this); | ||
1268 | } | ||
1269 | else | ||
1270 | { | ||
1271 | _parent_scene.RemoveCharacter(this); | ||
1272 | // destroy avatar capsule and related ODE data | ||
1273 | if (Amotor != IntPtr.Zero) | ||
1274 | { | ||
1275 | // Kill the Amotor | ||
1276 | d.JointDestroy(Amotor); | ||
1277 | Amotor = IntPtr.Zero; | ||
1278 | } | ||
1279 | //kill the Geometry | ||
1280 | _parent_scene.waitForSpaceUnlock(_parent_scene.space); | ||
1281 | |||
1282 | if (Body != IntPtr.Zero) | ||
1283 | { | ||
1284 | //kill the body | ||
1285 | d.BodyDestroy(Body); | ||
1286 | |||
1287 | Body = IntPtr.Zero; | ||
1288 | } | ||
1289 | |||
1290 | if (Shell != IntPtr.Zero) | ||
1291 | { | ||
1292 | d.GeomDestroy(Shell); | ||
1293 | _parent_scene.geom_name_map.Remove(Shell); | ||
1294 | Shell = IntPtr.Zero; | ||
1295 | } | ||
1296 | |||
1297 | } | ||
1298 | |||
1299 | m_isPhysical = m_tainted_isPhysical; | ||
1300 | } | ||
1301 | |||
1302 | if (m_tainted_CAPSULE_LENGTH != CAPSULE_LENGTH) | ||
1303 | { | ||
1304 | if (Shell != IntPtr.Zero && Body != IntPtr.Zero && Amotor != IntPtr.Zero) | ||
1305 | { | ||
1306 | |||
1307 | m_pidControllerActive = true; | ||
1308 | // no lock needed on _parent_scene.OdeLock because we are called from within the thread lock in OdePlugin's simulate() | ||
1309 | d.JointDestroy(Amotor); | ||
1310 | float prevCapsule = CAPSULE_LENGTH; | ||
1311 | CAPSULE_LENGTH = m_tainted_CAPSULE_LENGTH; | ||
1312 | //m_log.Info("[SIZE]: " + CAPSULE_LENGTH.ToString()); | ||
1313 | d.BodyDestroy(Body); | ||
1314 | d.GeomDestroy(Shell); | ||
1315 | AvatarGeomAndBodyCreation(_position.X, _position.Y, | ||
1316 | _position.Z + (Math.Abs(CAPSULE_LENGTH - prevCapsule) * 2), m_tensor); | ||
1317 | Velocity = Vector3.Zero; | ||
1318 | |||
1319 | _parent_scene.geom_name_map[Shell] = m_name; | ||
1320 | _parent_scene.actor_name_map[Shell] = (PhysicsActor)this; | ||
1321 | } | ||
1322 | else | ||
1323 | { | ||
1324 | m_log.Warn("[PHYSICS]: trying to change capsule size, but the following ODE data is missing - " | ||
1325 | + (Shell==IntPtr.Zero ? "Shell ":"") | ||
1326 | + (Body==IntPtr.Zero ? "Body ":"") | ||
1327 | + (Amotor==IntPtr.Zero ? "Amotor ":"")); | ||
1328 | } | ||
1329 | } | ||
1330 | |||
1331 | if (!m_taintPosition.ApproxEquals(_position, 0.05f)) | ||
1332 | { | ||
1333 | if (Body != IntPtr.Zero) | ||
1334 | { | ||
1335 | d.BodySetPosition(Body, m_taintPosition.X, m_taintPosition.Y, m_taintPosition.Z); | ||
1336 | |||
1337 | _position.X = m_taintPosition.X; | ||
1338 | _position.Y = m_taintPosition.Y; | ||
1339 | _position.Z = m_taintPosition.Z; | ||
1340 | } | ||
1341 | } | ||
1342 | |||
1343 | } | ||
1344 | |||
1345 | internal void AddCollisionFrameTime(int p) | ||
1346 | { | ||
1347 | // protect it from overflow crashing | ||
1348 | if (m_eventsubscription + p >= int.MaxValue) | ||
1349 | m_eventsubscription = 0; | ||
1350 | m_eventsubscription += p; | ||
1351 | } | ||
1352 | } | ||
1353 | } | ||
diff --git a/OpenSim/Region/Physics/ChOdePlugin/ODEDynamics.c_comments b/OpenSim/Region/Physics/ChOdePlugin/ODEDynamics.c_comments new file mode 100644 index 0000000..1060aa6 --- /dev/null +++ b/OpenSim/Region/Physics/ChOdePlugin/ODEDynamics.c_comments | |||
@@ -0,0 +1,630 @@ | |||
1 | /* | ||
2 | * Revised August 26 2009 by Kitto Flora. ODEDynamics.cs replaces | ||
3 | * ODEVehicleSettings.cs. It and ODEPrim.cs are re-organised: | ||
4 | * ODEPrim.cs contains methods dealing with Prim editing, Prim | ||
5 | * characteristics and Kinetic motion. | ||
6 | * ODEDynamics.cs contains methods dealing with Prim Physical motion | ||
7 | * (dynamics) and the associated settings. Old Linear and angular | ||
8 | * motors for dynamic motion have been replace with MoveLinear() | ||
9 | * and MoveAngular(); 'Physical' is used only to switch ODE dynamic | ||
10 | * simualtion on/off; VEHICAL_TYPE_NONE/VEHICAL_TYPE_<other> is to | ||
11 | * switch between 'VEHICLE' parameter use and general dynamics | ||
12 | * settings use. | ||
13 | * | ||
14 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
15 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
16 | * | ||
17 | * Redistribution and use in source and binary forms, with or without | ||
18 | * modification, are permitted provided that the following conditions are met: | ||
19 | * * Redistributions of source code must retain the above copyright | ||
20 | * notice, this list of conditions and the following disclaimer. | ||
21 | * * Redistributions in binary form must reproduce the above copyright | ||
22 | * notice, this list of conditions and the following disclaimer in the | ||
23 | * documentation and/or other materials provided with the distribution. | ||
24 | * * Neither the name of the OpenSimulator Project nor the | ||
25 | * names of its contributors may be used to endorse or promote products | ||
26 | * derived from this software without specific prior written permission. | ||
27 | * | ||
28 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
29 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
30 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
31 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
32 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
33 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
34 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
35 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
36 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
37 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
38 | */ | ||
39 | |||
40 | using System; | ||
41 | using System.Collections.Generic; | ||
42 | using System.Reflection; | ||
43 | using System.Runtime.InteropServices; | ||
44 | using log4net; | ||
45 | using OpenMetaverse; | ||
46 | using Ode.NET; | ||
47 | using OpenSim.Framework; | ||
48 | using OpenSim.Region.Physics.Manager; | ||
49 | |||
50 | namespace OpenSim.Region.Physics.OdePlugin | ||
51 | { | ||
52 | public class ODEDynamics | ||
53 | { | ||
54 | public Vehicle Type | ||
55 | { | ||
56 | get { return m_type; } | ||
57 | } | ||
58 | |||
59 | public IntPtr Body | ||
60 | { | ||
61 | get { return m_body; } | ||
62 | } | ||
63 | |||
64 | private int frcount = 0; // Used to limit dynamics debug output to | ||
65 | // every 100th frame | ||
66 | |||
67 | // private OdeScene m_parentScene = null; | ||
68 | private IntPtr m_body = IntPtr.Zero; | ||
69 | private IntPtr m_jointGroup = IntPtr.Zero; | ||
70 | private IntPtr m_aMotor = IntPtr.Zero; | ||
71 | |||
72 | |||
73 | // Vehicle properties | ||
74 | private Vehicle m_type = Vehicle.TYPE_NONE; // If a 'VEHICLE', and what kind | ||
75 | // private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier | ||
76 | private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings: | ||
77 | // HOVER_TERRAIN_ONLY | ||
78 | // HOVER_GLOBAL_HEIGHT | ||
79 | // NO_DEFLECTION_UP | ||
80 | // HOVER_WATER_ONLY | ||
81 | // HOVER_UP_ONLY | ||
82 | // LIMIT_MOTOR_UP | ||
83 | // LIMIT_ROLL_ONLY | ||
84 | |||
85 | // Linear properties | ||
86 | private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time | ||
87 | private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL | ||
88 | private Vector3 m_dir = Vector3.Zero; // velocity applied to body | ||
89 | private Vector3 m_linearFrictionTimescale = Vector3.Zero; | ||
90 | private float m_linearMotorDecayTimescale = 0; | ||
91 | private float m_linearMotorTimescale = 0; | ||
92 | private Vector3 m_lastLinearVelocityVector = Vector3.Zero; | ||
93 | // private bool m_LinearMotorSetLastFrame = false; | ||
94 | // private Vector3 m_linearMotorOffset = Vector3.Zero; | ||
95 | |||
96 | //Angular properties | ||
97 | private Vector3 m_angularMotorDirection = Vector3.Zero; | ||
98 | private Vector3 m_angularMotorDirectionLASTSET = Vector3.Zero; | ||
99 | private Vector3 m_angularFrictionTimescale = Vector3.Zero; | ||
100 | private float m_angularMotorDecayTimescale = 0; | ||
101 | private float m_angularMotorTimescale = 0; | ||
102 | private Vector3 m_lastAngularVelocityVector = Vector3.Zero; | ||
103 | |||
104 | //Deflection properties | ||
105 | // private float m_angularDeflectionEfficiency = 0; | ||
106 | // private float m_angularDeflectionTimescale = 0; | ||
107 | // private float m_linearDeflectionEfficiency = 0; | ||
108 | // private float m_linearDeflectionTimescale = 0; | ||
109 | |||
110 | //Banking properties | ||
111 | // private float m_bankingEfficiency = 0; | ||
112 | // private float m_bankingMix = 0; | ||
113 | // private float m_bankingTimescale = 0; | ||
114 | |||
115 | //Hover and Buoyancy properties | ||
116 | private float m_VhoverHeight = 0f; | ||
117 | private float m_VhoverEfficiency = 0f; | ||
118 | private float m_VhoverTimescale = 0f; | ||
119 | private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height | ||
120 | private float m_VehicleBuoyancy = 0f; //KF: m_VehicleBuoyancy is set by VEHICLE_BUOYANCY for a vehicle. | ||
121 | // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity) | ||
122 | // KF: So far I have found no good method to combine a script-requested .Z velocity and gravity. | ||
123 | // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity. | ||
124 | |||
125 | //Attractor properties | ||
126 | private float m_verticalAttractionEfficiency = 0; | ||
127 | private float m_verticalAttractionTimescale = 0; | ||
128 | |||
129 | |||
130 | |||
131 | |||
132 | |||
133 | internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue) | ||
134 | { | ||
135 | switch (pParam) | ||
136 | { | ||
137 | case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: | ||
138 | if (pValue < 0.01f) pValue = 0.01f; | ||
139 | // m_angularDeflectionEfficiency = pValue; | ||
140 | break; | ||
141 | case Vehicle.ANGULAR_DEFLECTION_TIMESCALE: | ||
142 | if (pValue < 0.01f) pValue = 0.01f; | ||
143 | // m_angularDeflectionTimescale = pValue; | ||
144 | break; | ||
145 | case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: | ||
146 | if (pValue < 0.01f) pValue = 0.01f; | ||
147 | m_angularMotorDecayTimescale = pValue; | ||
148 | break; | ||
149 | case Vehicle.ANGULAR_MOTOR_TIMESCALE: | ||
150 | if (pValue < 0.01f) pValue = 0.01f; | ||
151 | m_angularMotorTimescale = pValue; | ||
152 | break; | ||
153 | case Vehicle.BANKING_EFFICIENCY: | ||
154 | if (pValue < 0.01f) pValue = 0.01f; | ||
155 | // m_bankingEfficiency = pValue; | ||
156 | break; | ||
157 | case Vehicle.BANKING_MIX: | ||
158 | if (pValue < 0.01f) pValue = 0.01f; | ||
159 | // m_bankingMix = pValue; | ||
160 | break; | ||
161 | case Vehicle.BANKING_TIMESCALE: | ||
162 | if (pValue < 0.01f) pValue = 0.01f; | ||
163 | // m_bankingTimescale = pValue; | ||
164 | break; | ||
165 | case Vehicle.BUOYANCY: | ||
166 | if (pValue < -1f) pValue = -1f; | ||
167 | if (pValue > 1f) pValue = 1f; | ||
168 | m_VehicleBuoyancy = pValue; | ||
169 | break; | ||
170 | case Vehicle.HOVER_EFFICIENCY: | ||
171 | if (pValue < 0f) pValue = 0f; | ||
172 | if (pValue > 1f) pValue = 1f; | ||
173 | m_VhoverEfficiency = pValue; | ||
174 | break; | ||
175 | case Vehicle.HOVER_HEIGHT: | ||
176 | m_VhoverHeight = pValue; | ||
177 | break; | ||
178 | case Vehicle.HOVER_TIMESCALE: | ||
179 | if (pValue < 0.01f) pValue = 0.01f; | ||
180 | m_VhoverTimescale = pValue; | ||
181 | break; | ||
182 | case Vehicle.LINEAR_DEFLECTION_EFFICIENCY: | ||
183 | if (pValue < 0.01f) pValue = 0.01f; | ||
184 | // m_linearDeflectionEfficiency = pValue; | ||
185 | break; | ||
186 | case Vehicle.LINEAR_DEFLECTION_TIMESCALE: | ||
187 | if (pValue < 0.01f) pValue = 0.01f; | ||
188 | // m_linearDeflectionTimescale = pValue; | ||
189 | break; | ||
190 | case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: | ||
191 | if (pValue < 0.01f) pValue = 0.01f; | ||
192 | m_linearMotorDecayTimescale = pValue; | ||
193 | break; | ||
194 | case Vehicle.LINEAR_MOTOR_TIMESCALE: | ||
195 | if (pValue < 0.01f) pValue = 0.01f; | ||
196 | m_linearMotorTimescale = pValue; | ||
197 | break; | ||
198 | case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: | ||
199 | if (pValue < 0.0f) pValue = 0.0f; | ||
200 | if (pValue > 1.0f) pValue = 1.0f; | ||
201 | m_verticalAttractionEfficiency = pValue; | ||
202 | break; | ||
203 | case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: | ||
204 | if (pValue < 0.01f) pValue = 0.01f; | ||
205 | m_verticalAttractionTimescale = pValue; | ||
206 | break; | ||
207 | |||
208 | // These are vector properties but the engine lets you use a single float value to | ||
209 | // set all of the components to the same value | ||
210 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: | ||
211 | m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); | ||
212 | break; | ||
213 | case Vehicle.ANGULAR_MOTOR_DIRECTION: | ||
214 | m_angularMotorDirection = new Vector3(pValue, pValue, pValue); | ||
215 | m_angularMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); | ||
216 | break; | ||
217 | case Vehicle.LINEAR_FRICTION_TIMESCALE: | ||
218 | m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); | ||
219 | break; | ||
220 | case Vehicle.LINEAR_MOTOR_DIRECTION: | ||
221 | m_linearMotorDirection = new Vector3(pValue, pValue, pValue); | ||
222 | m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); | ||
223 | break; | ||
224 | case Vehicle.LINEAR_MOTOR_OFFSET: | ||
225 | // m_linearMotorOffset = new Vector3(pValue, pValue, pValue); | ||
226 | break; | ||
227 | |||
228 | } | ||
229 | |||
230 | }//end ProcessFloatVehicleParam | ||
231 | |||
232 | internal void ProcessVectorVehicleParam(Vehicle pParam, PhysicsVector pValue) | ||
233 | { | ||
234 | switch (pParam) | ||
235 | { | ||
236 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: | ||
237 | m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
238 | break; | ||
239 | case Vehicle.ANGULAR_MOTOR_DIRECTION: | ||
240 | m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
241 | m_angularMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
242 | break; | ||
243 | case Vehicle.LINEAR_FRICTION_TIMESCALE: | ||
244 | m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
245 | break; | ||
246 | case Vehicle.LINEAR_MOTOR_DIRECTION: | ||
247 | m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
248 | m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
249 | break; | ||
250 | case Vehicle.LINEAR_MOTOR_OFFSET: | ||
251 | // m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
252 | break; | ||
253 | } | ||
254 | |||
255 | }//end ProcessVectorVehicleParam | ||
256 | |||
257 | internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue) | ||
258 | { | ||
259 | switch (pParam) | ||
260 | { | ||
261 | case Vehicle.REFERENCE_FRAME: | ||
262 | // m_referenceFrame = pValue; | ||
263 | break; | ||
264 | } | ||
265 | |||
266 | }//end ProcessRotationVehicleParam | ||
267 | |||
268 | internal void ProcessTypeChange(Vehicle pType) | ||
269 | { | ||
270 | Console.WriteLine("ProcessTypeChange to " + pType); | ||
271 | |||
272 | // Set Defaults For Type | ||
273 | m_type = pType; | ||
274 | switch (pType) | ||
275 | { | ||
276 | case Vehicle.TYPE_SLED: | ||
277 | m_linearFrictionTimescale = new Vector3(30, 1, 1000); | ||
278 | m_angularFrictionTimescale = new Vector3(1000, 1000, 1000); | ||
279 | m_linearMotorDirection = Vector3.Zero; | ||
280 | m_linearMotorTimescale = 1000; | ||
281 | m_linearMotorDecayTimescale = 120; | ||
282 | m_angularMotorDirection = Vector3.Zero; | ||
283 | m_angularMotorTimescale = 1000; | ||
284 | m_angularMotorDecayTimescale = 120; | ||
285 | m_VhoverHeight = 0; | ||
286 | m_VhoverEfficiency = 1; | ||
287 | m_VhoverTimescale = 10; | ||
288 | m_VehicleBuoyancy = 0; | ||
289 | // m_linearDeflectionEfficiency = 1; | ||
290 | // m_linearDeflectionTimescale = 1; | ||
291 | // m_angularDeflectionEfficiency = 1; | ||
292 | // m_angularDeflectionTimescale = 1000; | ||
293 | // m_bankingEfficiency = 0; | ||
294 | // m_bankingMix = 1; | ||
295 | // m_bankingTimescale = 10; | ||
296 | // m_referenceFrame = Quaternion.Identity; | ||
297 | m_flags &= | ||
298 | ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | | ||
299 | VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); | ||
300 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP); | ||
301 | break; | ||
302 | case Vehicle.TYPE_CAR: | ||
303 | m_linearFrictionTimescale = new Vector3(100, 2, 1000); | ||
304 | m_angularFrictionTimescale = new Vector3(1000, 1000, 1000); | ||
305 | m_linearMotorDirection = Vector3.Zero; | ||
306 | m_linearMotorTimescale = 1; | ||
307 | m_linearMotorDecayTimescale = 60; | ||
308 | m_angularMotorDirection = Vector3.Zero; | ||
309 | m_angularMotorTimescale = 1; | ||
310 | m_angularMotorDecayTimescale = 0.8f; | ||
311 | m_VhoverHeight = 0; | ||
312 | m_VhoverEfficiency = 0; | ||
313 | m_VhoverTimescale = 1000; | ||
314 | m_VehicleBuoyancy = 0; | ||
315 | // // m_linearDeflectionEfficiency = 1; | ||
316 | // // m_linearDeflectionTimescale = 2; | ||
317 | // // m_angularDeflectionEfficiency = 0; | ||
318 | // m_angularDeflectionTimescale = 10; | ||
319 | m_verticalAttractionEfficiency = 1; | ||
320 | m_verticalAttractionTimescale = 10; | ||
321 | // m_bankingEfficiency = -0.2f; | ||
322 | // m_bankingMix = 1; | ||
323 | // m_bankingTimescale = 1; | ||
324 | // m_referenceFrame = Quaternion.Identity; | ||
325 | m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT); | ||
326 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.HOVER_UP_ONLY | | ||
327 | VehicleFlag.LIMIT_MOTOR_UP); | ||
328 | break; | ||
329 | case Vehicle.TYPE_BOAT: | ||
330 | m_linearFrictionTimescale = new Vector3(10, 3, 2); | ||
331 | m_angularFrictionTimescale = new Vector3(10,10,10); | ||
332 | m_linearMotorDirection = Vector3.Zero; | ||
333 | m_linearMotorTimescale = 5; | ||
334 | m_linearMotorDecayTimescale = 60; | ||
335 | m_angularMotorDirection = Vector3.Zero; | ||
336 | m_angularMotorTimescale = 4; | ||
337 | m_angularMotorDecayTimescale = 4; | ||
338 | m_VhoverHeight = 0; | ||
339 | m_VhoverEfficiency = 0.5f; | ||
340 | m_VhoverTimescale = 2; | ||
341 | m_VehicleBuoyancy = 1; | ||
342 | // m_linearDeflectionEfficiency = 0.5f; | ||
343 | // m_linearDeflectionTimescale = 3; | ||
344 | // m_angularDeflectionEfficiency = 0.5f; | ||
345 | // m_angularDeflectionTimescale = 5; | ||
346 | m_verticalAttractionEfficiency = 0.5f; | ||
347 | m_verticalAttractionTimescale = 5; | ||
348 | // m_bankingEfficiency = -0.3f; | ||
349 | // m_bankingMix = 0.8f; | ||
350 | // m_bankingTimescale = 1; | ||
351 | // m_referenceFrame = Quaternion.Identity; | ||
352 | m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.LIMIT_ROLL_ONLY | | ||
353 | VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); | ||
354 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.HOVER_WATER_ONLY | | ||
355 | VehicleFlag.LIMIT_MOTOR_UP); | ||
356 | break; | ||
357 | case Vehicle.TYPE_AIRPLANE: | ||
358 | m_linearFrictionTimescale = new Vector3(200, 10, 5); | ||
359 | m_angularFrictionTimescale = new Vector3(20, 20, 20); | ||
360 | m_linearMotorDirection = Vector3.Zero; | ||
361 | m_linearMotorTimescale = 2; | ||
362 | m_linearMotorDecayTimescale = 60; | ||
363 | m_angularMotorDirection = Vector3.Zero; | ||
364 | m_angularMotorTimescale = 4; | ||
365 | m_angularMotorDecayTimescale = 4; | ||
366 | m_VhoverHeight = 0; | ||
367 | m_VhoverEfficiency = 0.5f; | ||
368 | m_VhoverTimescale = 1000; | ||
369 | m_VehicleBuoyancy = 0; | ||
370 | // m_linearDeflectionEfficiency = 0.5f; | ||
371 | // m_linearDeflectionTimescale = 3; | ||
372 | // m_angularDeflectionEfficiency = 1; | ||
373 | // m_angularDeflectionTimescale = 2; | ||
374 | m_verticalAttractionEfficiency = 0.9f; | ||
375 | m_verticalAttractionTimescale = 2; | ||
376 | // m_bankingEfficiency = 1; | ||
377 | // m_bankingMix = 0.7f; | ||
378 | // m_bankingTimescale = 2; | ||
379 | // m_referenceFrame = Quaternion.Identity; | ||
380 | m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | | ||
381 | VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY | VehicleFlag.LIMIT_MOTOR_UP); | ||
382 | m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY); | ||
383 | break; | ||
384 | case Vehicle.TYPE_BALLOON: | ||
385 | m_linearFrictionTimescale = new Vector3(5, 5, 5); | ||
386 | m_angularFrictionTimescale = new Vector3(10, 10, 10); | ||
387 | m_linearMotorDirection = Vector3.Zero; | ||
388 | m_linearMotorTimescale = 5; | ||
389 | m_linearMotorDecayTimescale = 60; | ||
390 | m_angularMotorDirection = Vector3.Zero; | ||
391 | m_angularMotorTimescale = 6; | ||
392 | m_angularMotorDecayTimescale = 10; | ||
393 | m_VhoverHeight = 5; | ||
394 | m_VhoverEfficiency = 0.8f; | ||
395 | m_VhoverTimescale = 10; | ||
396 | m_VehicleBuoyancy = 1; | ||
397 | // m_linearDeflectionEfficiency = 0; | ||
398 | // m_linearDeflectionTimescale = 5; | ||
399 | // m_angularDeflectionEfficiency = 0; | ||
400 | // m_angularDeflectionTimescale = 5; | ||
401 | m_verticalAttractionEfficiency = 1; | ||
402 | m_verticalAttractionTimescale = 1000; | ||
403 | // m_bankingEfficiency = 0; | ||
404 | // m_bankingMix = 0.7f; | ||
405 | // m_bankingTimescale = 5; | ||
406 | // m_referenceFrame = Quaternion.Identity; | ||
407 | m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | | ||
408 | VehicleFlag.HOVER_UP_ONLY | VehicleFlag.LIMIT_MOTOR_UP); | ||
409 | m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT); | ||
410 | break; | ||
411 | |||
412 | } | ||
413 | }//end SetDefaultsForType | ||
414 | |||
415 | internal void Enable(IntPtr pBody, OdeScene pParentScene) | ||
416 | { | ||
417 | //Console.WriteLine("Enable m_type=" + m_type + " m_VehicleBuoyancy=" + m_VehicleBuoyancy); | ||
418 | if (m_type == Vehicle.TYPE_NONE) | ||
419 | return; | ||
420 | |||
421 | m_body = pBody; | ||
422 | //KF: This used to set up the linear and angular joints | ||
423 | } | ||
424 | |||
425 | internal void Step(float pTimestep, OdeScene pParentScene) | ||
426 | { | ||
427 | if (m_body == IntPtr.Zero || m_type == Vehicle.TYPE_NONE) | ||
428 | return; | ||
429 | frcount++; // used to limit debug comment output | ||
430 | if (frcount > 100) | ||
431 | frcount = 0; | ||
432 | |||
433 | MoveLinear(pTimestep, pParentScene); | ||
434 | MoveAngular(pTimestep); | ||
435 | }// end Step | ||
436 | |||
437 | private void MoveLinear(float pTimestep, OdeScene _pParentScene) | ||
438 | { | ||
439 | if (!m_linearMotorDirection.ApproxEquals(Vector3.Zero, 0.01f)) // requested m_linearMotorDirection is significant | ||
440 | { | ||
441 | if(!d.BodyIsEnabled (Body)) d.BodyEnable (Body); | ||
442 | |||
443 | // add drive to body | ||
444 | Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale/pTimestep); | ||
445 | m_lastLinearVelocityVector += (addAmount*10); // lastLinearVelocityVector is the current body velocity vector? | ||
446 | |||
447 | // This will work temporarily, but we really need to compare speed on an axis | ||
448 | // KF: Limit body velocity to applied velocity? | ||
449 | if (Math.Abs(m_lastLinearVelocityVector.X) > Math.Abs(m_linearMotorDirectionLASTSET.X)) | ||
450 | m_lastLinearVelocityVector.X = m_linearMotorDirectionLASTSET.X; | ||
451 | if (Math.Abs(m_lastLinearVelocityVector.Y) > Math.Abs(m_linearMotorDirectionLASTSET.Y)) | ||
452 | m_lastLinearVelocityVector.Y = m_linearMotorDirectionLASTSET.Y; | ||
453 | if (Math.Abs(m_lastLinearVelocityVector.Z) > Math.Abs(m_linearMotorDirectionLASTSET.Z)) | ||
454 | m_lastLinearVelocityVector.Z = m_linearMotorDirectionLASTSET.Z; | ||
455 | |||
456 | // decay applied velocity | ||
457 | Vector3 decayfraction = ((Vector3.One/(m_linearMotorDecayTimescale/pTimestep))); | ||
458 | //Console.WriteLine("decay: " + decayfraction); | ||
459 | m_linearMotorDirection -= m_linearMotorDirection * decayfraction; | ||
460 | //Console.WriteLine("actual: " + m_linearMotorDirection); | ||
461 | } | ||
462 | else | ||
463 | { // requested is not significant | ||
464 | // if what remains of applied is small, zero it. | ||
465 | if (m_lastLinearVelocityVector.ApproxEquals(Vector3.Zero, 0.01f)) | ||
466 | m_lastLinearVelocityVector = Vector3.Zero; | ||
467 | } | ||
468 | |||
469 | |||
470 | // convert requested object velocity to world-referenced vector | ||
471 | m_dir = m_lastLinearVelocityVector; | ||
472 | d.Quaternion rot = d.BodyGetQuaternion(Body); | ||
473 | Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); // rotq = rotation of object | ||
474 | m_dir *= rotq; // apply obj rotation to velocity vector | ||
475 | |||
476 | // add Gravity andBuoyancy | ||
477 | // KF: So far I have found no good method to combine a script-requested | ||
478 | // .Z velocity and gravity. Therefore only 0g will used script-requested | ||
479 | // .Z velocity. >0g (m_VehicleBuoyancy < 1) will used modified gravity only. | ||
480 | Vector3 grav = Vector3.Zero; | ||
481 | if(m_VehicleBuoyancy < 1.0f) | ||
482 | { | ||
483 | // There is some gravity, make a gravity force vector | ||
484 | // that is applied after object velocity. | ||
485 | d.Mass objMass; | ||
486 | d.BodyGetMass(Body, out objMass); | ||
487 | // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; | ||
488 | grav.Z = _pParentScene.gravityz * objMass.mass * (1f - m_VehicleBuoyancy); | ||
489 | // Preserve the current Z velocity | ||
490 | d.Vector3 vel_now = d.BodyGetLinearVel(Body); | ||
491 | m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity | ||
492 | } // else its 1.0, no gravity. | ||
493 | |||
494 | // Check if hovering | ||
495 | if( (m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) | ||
496 | { | ||
497 | // We should hover, get the target height | ||
498 | d.Vector3 pos = d.BodyGetPosition(Body); | ||
499 | if((m_flags & VehicleFlag.HOVER_WATER_ONLY) == VehicleFlag.HOVER_WATER_ONLY) | ||
500 | { | ||
501 | m_VhoverTargetHeight = _pParentScene.GetWaterLevel() + m_VhoverHeight; | ||
502 | } | ||
503 | else if((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) == VehicleFlag.HOVER_TERRAIN_ONLY) | ||
504 | { | ||
505 | m_VhoverTargetHeight = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y) + m_VhoverHeight; | ||
506 | } | ||
507 | else if((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) == VehicleFlag.HOVER_GLOBAL_HEIGHT) | ||
508 | { | ||
509 | m_VhoverTargetHeight = m_VhoverHeight; | ||
510 | } | ||
511 | |||
512 | if((m_flags & VehicleFlag.HOVER_UP_ONLY) == VehicleFlag.HOVER_UP_ONLY) | ||
513 | { | ||
514 | // If body is aready heigher, use its height as target height | ||
515 | if(pos.Z > m_VhoverTargetHeight) m_VhoverTargetHeight = pos.Z; | ||
516 | } | ||
517 | |||
518 | // m_VhoverEfficiency = 0f; // 0=boucy, 1=Crit.damped | ||
519 | // m_VhoverTimescale = 0f; // time to acheive height | ||
520 | // pTimestep is time since last frame,in secs | ||
521 | float herr0 = pos.Z - m_VhoverTargetHeight; | ||
522 | //if(frcount == 0) Console.WriteLine("herr0=" + herr0); | ||
523 | // Replace Vertical speed with correction figure if significant | ||
524 | if(Math.Abs(herr0) > 0.01f ) | ||
525 | { | ||
526 | d.Mass objMass; | ||
527 | d.BodyGetMass(Body, out objMass); | ||
528 | m_dir.Z = - ( (herr0 * pTimestep * 50.0f) / m_VhoverTimescale); | ||
529 | // m_VhoverEfficiency is not yet implemented | ||
530 | } | ||
531 | else | ||
532 | { | ||
533 | m_dir.Z = 0f; | ||
534 | } | ||
535 | } | ||
536 | |||
537 | // Apply velocity | ||
538 | d.BodySetLinearVel(Body, m_dir.X, m_dir.Y, m_dir.Z); | ||
539 | //if(frcount == 0) Console.WriteLine("Move " + Body + ":"+ m_dir.X + " " + m_dir.Y + " " + m_dir.Z); | ||
540 | // apply gravity force | ||
541 | d.BodyAddForce(Body, grav.X, grav.Y, grav.Z); | ||
542 | //if(frcount == 0) Console.WriteLine("Force " + Body + ":" + grav.X + " " + grav.Y + " " + grav.Z); | ||
543 | |||
544 | |||
545 | // apply friction | ||
546 | Vector3 decayamount = Vector3.One / (m_linearFrictionTimescale / pTimestep); | ||
547 | m_lastLinearVelocityVector -= m_lastLinearVelocityVector * decayamount; | ||
548 | } // end MoveLinear() | ||
549 | |||
550 | private void MoveAngular(float pTimestep) | ||
551 | { | ||
552 | |||
553 | // m_angularMotorDirection is the latest value from the script, and is decayed here | ||
554 | // m_angularMotorDirectionLASTSET is the latest value from the script | ||
555 | // m_lastAngularVelocityVector is what is being applied to the Body, varied up and down here | ||
556 | |||
557 | if (!m_angularMotorDirection.ApproxEquals(Vector3.Zero, 0.01f)) | ||
558 | { | ||
559 | if(!d.BodyIsEnabled (Body)) d.BodyEnable (Body); | ||
560 | // ramp up to new value | ||
561 | Vector3 addAmount = m_angularMotorDirection / (m_angularMotorTimescale / pTimestep); | ||
562 | m_lastAngularVelocityVector += (addAmount * 10f); | ||
563 | //if(frcount == 0) Console.WriteLine("add: " + addAmount); | ||
564 | |||
565 | // limit applied value to what was set by script | ||
566 | // This will work temporarily, but we really need to compare speed on an axis | ||
567 | if (Math.Abs(m_lastAngularVelocityVector.X) > Math.Abs(m_angularMotorDirectionLASTSET.X)) | ||
568 | m_lastAngularVelocityVector.X = m_angularMotorDirectionLASTSET.X; | ||
569 | if (Math.Abs(m_lastAngularVelocityVector.Y) > Math.Abs(m_angularMotorDirectionLASTSET.Y)) | ||
570 | m_lastAngularVelocityVector.Y = m_angularMotorDirectionLASTSET.Y; | ||
571 | if (Math.Abs(m_lastAngularVelocityVector.Z) > Math.Abs(m_angularMotorDirectionLASTSET.Z)) | ||
572 | m_lastAngularVelocityVector.Z = m_angularMotorDirectionLASTSET.Z; | ||
573 | |||
574 | // decay the requested value | ||
575 | Vector3 decayfraction = ((Vector3.One / (m_angularMotorDecayTimescale / pTimestep))); | ||
576 | //Console.WriteLine("decay: " + decayfraction); | ||
577 | m_angularMotorDirection -= m_angularMotorDirection * decayfraction; | ||
578 | //Console.WriteLine("actual: " + m_linearMotorDirection); | ||
579 | } | ||
580 | // KF: m_lastAngularVelocityVector is rotational speed in rad/sec ? | ||
581 | |||
582 | // Vertical attractor section | ||
583 | |||
584 | // d.Mass objMass; | ||
585 | // d.BodyGetMass(Body, out objMass); | ||
586 | // float servo = 100f * objMass.mass * m_verticalAttractionEfficiency / (m_verticalAttractionTimescale * pTimestep); | ||
587 | float servo = 0.1f * m_verticalAttractionEfficiency / (m_verticalAttractionTimescale * pTimestep); | ||
588 | // get present body rotation | ||
589 | d.Quaternion rot = d.BodyGetQuaternion(Body); | ||
590 | Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); | ||
591 | // make a vector pointing up | ||
592 | Vector3 verterr = Vector3.Zero; | ||
593 | verterr.Z = 1.0f; | ||
594 | // rotate it to Body Angle | ||
595 | verterr = verterr * rotq; | ||
596 | // verterr.X and .Y are the World error ammounts. They are 0 when there is no error (Vehicle Body is 'vertical'), and .Z will be 1. | ||
597 | // As the body leans to its side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall and .Z will go | ||
598 | // negative. Similar for tilt and |.Y|. .X and .Y must be modulated to prevent a stable inverted body. | ||
599 | if (verterr.Z < 0.0f) | ||
600 | { | ||
601 | verterr.X = 2.0f - verterr.X; | ||
602 | verterr.Y = 2.0f - verterr.Y; | ||
603 | } | ||
604 | // Error is 0 (no error) to +/- 2 (max error) | ||
605 | // scale it by servo | ||
606 | verterr = verterr * servo; | ||
607 | |||
608 | // rotate to object frame | ||
609 | // verterr = verterr * rotq; | ||
610 | |||
611 | // As the body rotates around the X axis, then verterr.Y increases; Rotated around Y then .X increases, so | ||
612 | // Change Body angular velocity X based on Y, and Y based on X. Z is not changed. | ||
613 | m_lastAngularVelocityVector.X += verterr.Y; | ||
614 | m_lastAngularVelocityVector.Y -= verterr.X; | ||
615 | /* | ||
616 | if(frcount == 0) | ||
617 | { | ||
618 | // Console.WriteLine("AngleMotor " + m_lastAngularVelocityVector); | ||
619 | Console.WriteLine(String.Format("VA Body:{0} servo:{1} err:<{2},{3},{4}> VAE:{5}", | ||
620 | Body, servo, verterr.X, verterr.Y, verterr.Z, m_verticalAttractionEfficiency)); | ||
621 | } | ||
622 | */ | ||
623 | d.BodySetAngularVel (Body, m_lastAngularVelocityVector.X, m_lastAngularVelocityVector.Y, m_lastAngularVelocityVector.Z); | ||
624 | // apply friction | ||
625 | Vector3 decayamount = Vector3.One / (m_angularFrictionTimescale / pTimestep); | ||
626 | m_lastAngularVelocityVector -= m_lastAngularVelocityVector * decayamount; | ||
627 | |||
628 | } //end MoveAngular | ||
629 | } | ||
630 | } | ||
diff --git a/OpenSim/Region/Physics/ChOdePlugin/ODEDynamics.cs b/OpenSim/Region/Physics/ChOdePlugin/ODEDynamics.cs new file mode 100644 index 0000000..ef2dccc --- /dev/null +++ b/OpenSim/Region/Physics/ChOdePlugin/ODEDynamics.cs | |||
@@ -0,0 +1,697 @@ | |||
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 | * Revised Aug, Sept 2009 by Kitto Flora. ODEDynamics.cs replaces | ||
28 | * ODEVehicleSettings.cs. It and ODEPrim.cs are re-organised: | ||
29 | * ODEPrim.cs contains methods dealing with Prim editing, Prim | ||
30 | * characteristics and Kinetic motion. | ||
31 | * ODEDynamics.cs contains methods dealing with Prim Physical motion | ||
32 | * (dynamics) and the associated settings. Old Linear and angular | ||
33 | * motors for dynamic motion have been replace with MoveLinear() | ||
34 | * and MoveAngular(); 'Physical' is used only to switch ODE dynamic | ||
35 | * simualtion on/off; VEHICAL_TYPE_NONE/VEHICAL_TYPE_<other> is to | ||
36 | * switch between 'VEHICLE' parameter use and general dynamics | ||
37 | * settings use. | ||
38 | * | ||
39 | */ | ||
40 | |||
41 | /* Revised Aug, Sept 2009 by Kitto Flora. ODEDynamics.cs replaces | ||
42 | * ODEVehicleSettings.cs. It and ODEPrim.cs are re-organised: | ||
43 | * ODEPrim.cs contains methods dealing with Prim editing, Prim | ||
44 | * characteristics and Kinetic motion. | ||
45 | * ODEDynamics.cs contains methods dealing with Prim Physical motion | ||
46 | * (dynamics) and the associated settings. Old Linear and angular | ||
47 | * motors for dynamic motion have been replace with MoveLinear() | ||
48 | * and MoveAngular(); 'Physical' is used only to switch ODE dynamic | ||
49 | * simualtion on/off; VEHICAL_TYPE_NONE/VEHICAL_TYPE_<other> is to | ||
50 | * switch between 'VEHICLE' parameter use and general dynamics | ||
51 | * settings use. | ||
52 | */ | ||
53 | |||
54 | using System; | ||
55 | using System.Collections.Generic; | ||
56 | using System.Reflection; | ||
57 | using System.Runtime.InteropServices; | ||
58 | using log4net; | ||
59 | using OpenMetaverse; | ||
60 | using Ode.NET; | ||
61 | using OpenSim.Framework; | ||
62 | using OpenSim.Region.Physics.Manager; | ||
63 | |||
64 | namespace OpenSim.Region.Physics.OdePlugin | ||
65 | { | ||
66 | public class ODEDynamics | ||
67 | { | ||
68 | public Vehicle Type | ||
69 | { | ||
70 | get { return m_type; } | ||
71 | } | ||
72 | |||
73 | public IntPtr Body | ||
74 | { | ||
75 | get { return m_body; } | ||
76 | } | ||
77 | |||
78 | private int frcount = 0; // Used to limit dynamics debug output to | ||
79 | // every 100th frame | ||
80 | |||
81 | // private OdeScene m_parentScene = null; | ||
82 | private IntPtr m_body = IntPtr.Zero; | ||
83 | // private IntPtr m_jointGroup = IntPtr.Zero; | ||
84 | // private IntPtr m_aMotor = IntPtr.Zero; | ||
85 | |||
86 | // Correction factors, to match Sl | ||
87 | private static float m_linearVelocityFactor = 0.9f; | ||
88 | private static float m_linearAttackFactor = 0.4f; | ||
89 | private static float m_linearDecayFactor = 0.5f; | ||
90 | private static float m_linearFrictionFactor = 1.2f; | ||
91 | |||
92 | |||
93 | // Vehicle properties | ||
94 | private Vehicle m_type = Vehicle.TYPE_NONE; // If a 'VEHICLE', and what kind | ||
95 | // private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier | ||
96 | private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings: | ||
97 | // HOVER_TERRAIN_ONLY | ||
98 | // HOVER_GLOBAL_HEIGHT | ||
99 | // NO_DEFLECTION_UP | ||
100 | // HOVER_WATER_ONLY | ||
101 | // HOVER_UP_ONLY | ||
102 | // LIMIT_MOTOR_UP | ||
103 | // LIMIT_ROLL_ONLY | ||
104 | |||
105 | // Linear properties | ||
106 | private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time | ||
107 | private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL, for max limiting | ||
108 | private Vector3 m_dir = Vector3.Zero; // velocity applied to body | ||
109 | private Vector3 m_linearFrictionTimescale = Vector3.Zero; | ||
110 | private float m_linearMotorDecayTimescale = 0; | ||
111 | private float m_linearMotorTimescale = 0; | ||
112 | private Vector3 m_lastLinearVelocityVector = Vector3.Zero; | ||
113 | // private bool m_LinearMotorSetLastFrame = false; | ||
114 | // private Vector3 m_linearMotorOffset = Vector3.Zero; | ||
115 | |||
116 | //Angular properties | ||
117 | private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor | ||
118 | private int m_angularMotorApply = 0; // application frame counter | ||
119 | private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity | ||
120 | private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate | ||
121 | private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate | ||
122 | private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate | ||
123 | private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body | ||
124 | // private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body | ||
125 | |||
126 | //Deflection properties | ||
127 | // private float m_angularDeflectionEfficiency = 0; | ||
128 | // private float m_angularDeflectionTimescale = 0; | ||
129 | // private float m_linearDeflectionEfficiency = 0; | ||
130 | // private float m_linearDeflectionTimescale = 0; | ||
131 | |||
132 | //Banking properties | ||
133 | // private float m_bankingEfficiency = 0; | ||
134 | // private float m_bankingMix = 0; | ||
135 | // private float m_bankingTimescale = 0; | ||
136 | |||
137 | //Hover and Buoyancy properties | ||
138 | private float m_VhoverHeight = 0f; | ||
139 | // private float m_VhoverEfficiency = 0f; | ||
140 | private float m_VhoverTimescale = 0f; | ||
141 | private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height | ||
142 | private float m_VehicleBuoyancy = 0f; // Set by VEHICLE_BUOYANCY, for a vehicle. | ||
143 | // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity) | ||
144 | // KF: So far I have found no good method to combine a script-requested .Z velocity and gravity. | ||
145 | // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity. | ||
146 | |||
147 | //Attractor properties | ||
148 | private float m_verticalAttractionEfficiency = 1.0f; // damped | ||
149 | private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor. | ||
150 | |||
151 | |||
152 | |||
153 | |||
154 | |||
155 | internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue) | ||
156 | { | ||
157 | switch (pParam) | ||
158 | { | ||
159 | case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: | ||
160 | if (pValue < 0.01f) pValue = 0.01f; | ||
161 | // m_angularDeflectionEfficiency = pValue; | ||
162 | break; | ||
163 | case Vehicle.ANGULAR_DEFLECTION_TIMESCALE: | ||
164 | if (pValue < 0.01f) pValue = 0.01f; | ||
165 | // m_angularDeflectionTimescale = pValue; | ||
166 | break; | ||
167 | case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: | ||
168 | if (pValue < 0.01f) pValue = 0.01f; | ||
169 | m_angularMotorDecayTimescale = pValue; | ||
170 | break; | ||
171 | case Vehicle.ANGULAR_MOTOR_TIMESCALE: | ||
172 | if (pValue < 0.01f) pValue = 0.01f; | ||
173 | m_angularMotorTimescale = pValue; | ||
174 | break; | ||
175 | case Vehicle.BANKING_EFFICIENCY: | ||
176 | if (pValue < 0.01f) pValue = 0.01f; | ||
177 | // m_bankingEfficiency = pValue; | ||
178 | break; | ||
179 | case Vehicle.BANKING_MIX: | ||
180 | if (pValue < 0.01f) pValue = 0.01f; | ||
181 | // m_bankingMix = pValue; | ||
182 | break; | ||
183 | case Vehicle.BANKING_TIMESCALE: | ||
184 | if (pValue < 0.01f) pValue = 0.01f; | ||
185 | // m_bankingTimescale = pValue; | ||
186 | break; | ||
187 | case Vehicle.BUOYANCY: | ||
188 | if (pValue < -1f) pValue = -1f; | ||
189 | if (pValue > 1f) pValue = 1f; | ||
190 | m_VehicleBuoyancy = pValue; | ||
191 | break; | ||
192 | // case Vehicle.HOVER_EFFICIENCY: | ||
193 | // if (pValue < 0f) pValue = 0f; | ||
194 | // if (pValue > 1f) pValue = 1f; | ||
195 | // m_VhoverEfficiency = pValue; | ||
196 | // break; | ||
197 | case Vehicle.HOVER_HEIGHT: | ||
198 | m_VhoverHeight = pValue; | ||
199 | break; | ||
200 | case Vehicle.HOVER_TIMESCALE: | ||
201 | if (pValue < 0.01f) pValue = 0.01f; | ||
202 | m_VhoverTimescale = pValue; | ||
203 | break; | ||
204 | case Vehicle.LINEAR_DEFLECTION_EFFICIENCY: | ||
205 | if (pValue < 0.01f) pValue = 0.01f; | ||
206 | // m_linearDeflectionEfficiency = pValue; | ||
207 | break; | ||
208 | case Vehicle.LINEAR_DEFLECTION_TIMESCALE: | ||
209 | if (pValue < 0.01f) pValue = 0.01f; | ||
210 | // m_linearDeflectionTimescale = pValue; | ||
211 | break; | ||
212 | case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: | ||
213 | if (pValue < 0.01f) pValue = 0.01f; | ||
214 | m_linearMotorDecayTimescale = pValue; | ||
215 | break; | ||
216 | case Vehicle.LINEAR_MOTOR_TIMESCALE: | ||
217 | if (pValue < 0.01f) pValue = 0.01f; | ||
218 | m_linearMotorTimescale = pValue; | ||
219 | break; | ||
220 | case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: | ||
221 | if (pValue < 0.1f) pValue = 0.1f; // Less goes unstable | ||
222 | if (pValue > 1.0f) pValue = 1.0f; | ||
223 | m_verticalAttractionEfficiency = pValue; | ||
224 | break; | ||
225 | case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: | ||
226 | if (pValue < 0.01f) pValue = 0.01f; | ||
227 | m_verticalAttractionTimescale = pValue; | ||
228 | break; | ||
229 | |||
230 | // These are vector properties but the engine lets you use a single float value to | ||
231 | // set all of the components to the same value | ||
232 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: | ||
233 | m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); | ||
234 | break; | ||
235 | case Vehicle.ANGULAR_MOTOR_DIRECTION: | ||
236 | m_angularMotorDirection = new Vector3(pValue, pValue, pValue); | ||
237 | m_angularMotorApply = 10; | ||
238 | break; | ||
239 | case Vehicle.LINEAR_FRICTION_TIMESCALE: | ||
240 | m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); | ||
241 | break; | ||
242 | case Vehicle.LINEAR_MOTOR_DIRECTION: | ||
243 | m_linearMotorDirection = new Vector3(pValue, pValue, pValue); | ||
244 | m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); | ||
245 | break; | ||
246 | case Vehicle.LINEAR_MOTOR_OFFSET: | ||
247 | // m_linearMotorOffset = new Vector3(pValue, pValue, pValue); | ||
248 | break; | ||
249 | |||
250 | } | ||
251 | |||
252 | }//end ProcessFloatVehicleParam | ||
253 | |||
254 | internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue) | ||
255 | { | ||
256 | switch (pParam) | ||
257 | { | ||
258 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: | ||
259 | m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
260 | break; | ||
261 | case Vehicle.ANGULAR_MOTOR_DIRECTION: | ||
262 | m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
263 | // Limit requested angular speed to 2 rps= 4 pi rads/sec | ||
264 | if(m_angularMotorDirection.X > 12.56f) m_angularMotorDirection.X = 12.56f; | ||
265 | if(m_angularMotorDirection.X < - 12.56f) m_angularMotorDirection.X = - 12.56f; | ||
266 | if(m_angularMotorDirection.Y > 12.56f) m_angularMotorDirection.Y = 12.56f; | ||
267 | if(m_angularMotorDirection.Y < - 12.56f) m_angularMotorDirection.Y = - 12.56f; | ||
268 | if(m_angularMotorDirection.Z > 12.56f) m_angularMotorDirection.Z = 12.56f; | ||
269 | if(m_angularMotorDirection.Z < - 12.56f) m_angularMotorDirection.Z = - 12.56f; | ||
270 | m_angularMotorApply = 10; | ||
271 | break; | ||
272 | case Vehicle.LINEAR_FRICTION_TIMESCALE: | ||
273 | m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
274 | break; | ||
275 | case Vehicle.LINEAR_MOTOR_DIRECTION: | ||
276 | pValue *= m_linearVelocityFactor; | ||
277 | m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); // velocity requested by LSL, decayed by time | ||
278 | m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); // velocity requested by LSL, for max limiting | ||
279 | break; | ||
280 | case Vehicle.LINEAR_MOTOR_OFFSET: | ||
281 | // m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); | ||
282 | break; | ||
283 | } | ||
284 | |||
285 | }//end ProcessVectorVehicleParam | ||
286 | |||
287 | internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue) | ||
288 | { | ||
289 | switch (pParam) | ||
290 | { | ||
291 | case Vehicle.REFERENCE_FRAME: | ||
292 | // m_referenceFrame = pValue; | ||
293 | break; | ||
294 | } | ||
295 | |||
296 | }//end ProcessRotationVehicleParam | ||
297 | |||
298 | internal void ProcessTypeChange(Vehicle pType) | ||
299 | { | ||
300 | // Set Defaults For Type | ||
301 | m_type = pType; | ||
302 | switch (pType) | ||
303 | { | ||
304 | case Vehicle.TYPE_SLED: | ||
305 | m_linearFrictionTimescale = new Vector3(30, 1, 1000); | ||
306 | m_angularFrictionTimescale = new Vector3(1000, 1000, 1000); | ||
307 | m_linearMotorDirection = Vector3.Zero; | ||
308 | m_linearMotorTimescale = 1000; | ||
309 | m_linearMotorDecayTimescale = 120; | ||
310 | m_angularMotorDirection = Vector3.Zero; | ||
311 | m_angularMotorTimescale = 1000; | ||
312 | m_angularMotorDecayTimescale = 120; | ||
313 | m_VhoverHeight = 0; | ||
314 | // m_VhoverEfficiency = 1; | ||
315 | m_VhoverTimescale = 10; | ||
316 | m_VehicleBuoyancy = 0; | ||
317 | // m_linearDeflectionEfficiency = 1; | ||
318 | // m_linearDeflectionTimescale = 1; | ||
319 | // m_angularDeflectionEfficiency = 1; | ||
320 | // m_angularDeflectionTimescale = 1000; | ||
321 | // m_bankingEfficiency = 0; | ||
322 | // m_bankingMix = 1; | ||
323 | // m_bankingTimescale = 10; | ||
324 | // m_referenceFrame = Quaternion.Identity; | ||
325 | m_flags &= | ||
326 | ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | | ||
327 | VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); | ||
328 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP); | ||
329 | break; | ||
330 | case Vehicle.TYPE_CAR: | ||
331 | m_linearFrictionTimescale = new Vector3(100, 2, 1000); | ||
332 | m_angularFrictionTimescale = new Vector3(1000, 1000, 1000); | ||
333 | m_linearMotorDirection = Vector3.Zero; | ||
334 | m_linearMotorTimescale = 1; | ||
335 | m_linearMotorDecayTimescale = 60; | ||
336 | m_angularMotorDirection = Vector3.Zero; | ||
337 | m_angularMotorTimescale = 1; | ||
338 | m_angularMotorDecayTimescale = 0.8f; | ||
339 | m_VhoverHeight = 0; | ||
340 | // m_VhoverEfficiency = 0; | ||
341 | m_VhoverTimescale = 1000; | ||
342 | m_VehicleBuoyancy = 0; | ||
343 | // // m_linearDeflectionEfficiency = 1; | ||
344 | // // m_linearDeflectionTimescale = 2; | ||
345 | // // m_angularDeflectionEfficiency = 0; | ||
346 | // m_angularDeflectionTimescale = 10; | ||
347 | m_verticalAttractionEfficiency = 1f; | ||
348 | m_verticalAttractionTimescale = 10f; | ||
349 | // m_bankingEfficiency = -0.2f; | ||
350 | // m_bankingMix = 1; | ||
351 | // m_bankingTimescale = 1; | ||
352 | // m_referenceFrame = Quaternion.Identity; | ||
353 | m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT); | ||
354 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.HOVER_UP_ONLY | | ||
355 | VehicleFlag.LIMIT_MOTOR_UP); | ||
356 | break; | ||
357 | case Vehicle.TYPE_BOAT: | ||
358 | m_linearFrictionTimescale = new Vector3(10, 3, 2); | ||
359 | m_angularFrictionTimescale = new Vector3(10,10,10); | ||
360 | m_linearMotorDirection = Vector3.Zero; | ||
361 | m_linearMotorTimescale = 5; | ||
362 | m_linearMotorDecayTimescale = 60; | ||
363 | m_angularMotorDirection = Vector3.Zero; | ||
364 | m_angularMotorTimescale = 4; | ||
365 | m_angularMotorDecayTimescale = 4; | ||
366 | m_VhoverHeight = 0; | ||
367 | // m_VhoverEfficiency = 0.5f; | ||
368 | m_VhoverTimescale = 2; | ||
369 | m_VehicleBuoyancy = 1; | ||
370 | // m_linearDeflectionEfficiency = 0.5f; | ||
371 | // m_linearDeflectionTimescale = 3; | ||
372 | // m_angularDeflectionEfficiency = 0.5f; | ||
373 | // m_angularDeflectionTimescale = 5; | ||
374 | m_verticalAttractionEfficiency = 0.5f; | ||
375 | m_verticalAttractionTimescale = 5f; | ||
376 | // m_bankingEfficiency = -0.3f; | ||
377 | // m_bankingMix = 0.8f; | ||
378 | // m_bankingTimescale = 1; | ||
379 | // m_referenceFrame = Quaternion.Identity; | ||
380 | m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.LIMIT_ROLL_ONLY | | ||
381 | VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); | ||
382 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.HOVER_WATER_ONLY | | ||
383 | VehicleFlag.LIMIT_MOTOR_UP); | ||
384 | break; | ||
385 | case Vehicle.TYPE_AIRPLANE: | ||
386 | m_linearFrictionTimescale = new Vector3(200, 10, 5); | ||
387 | m_angularFrictionTimescale = new Vector3(20, 20, 20); | ||
388 | m_linearMotorDirection = Vector3.Zero; | ||
389 | m_linearMotorTimescale = 2; | ||
390 | m_linearMotorDecayTimescale = 60; | ||
391 | m_angularMotorDirection = Vector3.Zero; | ||
392 | m_angularMotorTimescale = 4; | ||
393 | m_angularMotorDecayTimescale = 4; | ||
394 | m_VhoverHeight = 0; | ||
395 | // m_VhoverEfficiency = 0.5f; | ||
396 | m_VhoverTimescale = 1000; | ||
397 | m_VehicleBuoyancy = 0; | ||
398 | // m_linearDeflectionEfficiency = 0.5f; | ||
399 | // m_linearDeflectionTimescale = 3; | ||
400 | // m_angularDeflectionEfficiency = 1; | ||
401 | // m_angularDeflectionTimescale = 2; | ||
402 | m_verticalAttractionEfficiency = 0.9f; | ||
403 | m_verticalAttractionTimescale = 2f; | ||
404 | // m_bankingEfficiency = 1; | ||
405 | // m_bankingMix = 0.7f; | ||
406 | // m_bankingTimescale = 2; | ||
407 | // m_referenceFrame = Quaternion.Identity; | ||
408 | m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | | ||
409 | VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY | VehicleFlag.LIMIT_MOTOR_UP); | ||
410 | m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY); | ||
411 | break; | ||
412 | case Vehicle.TYPE_BALLOON: | ||
413 | m_linearFrictionTimescale = new Vector3(5, 5, 5); | ||
414 | m_angularFrictionTimescale = new Vector3(10, 10, 10); | ||
415 | m_linearMotorDirection = Vector3.Zero; | ||
416 | m_linearMotorTimescale = 5; | ||
417 | m_linearMotorDecayTimescale = 60; | ||
418 | m_angularMotorDirection = Vector3.Zero; | ||
419 | m_angularMotorTimescale = 6; | ||
420 | m_angularMotorDecayTimescale = 10; | ||
421 | m_VhoverHeight = 5; | ||
422 | // m_VhoverEfficiency = 0.8f; | ||
423 | m_VhoverTimescale = 10; | ||
424 | m_VehicleBuoyancy = 1; | ||
425 | // m_linearDeflectionEfficiency = 0; | ||
426 | // m_linearDeflectionTimescale = 5; | ||
427 | // m_angularDeflectionEfficiency = 0; | ||
428 | // m_angularDeflectionTimescale = 5; | ||
429 | m_verticalAttractionEfficiency = 1f; | ||
430 | m_verticalAttractionTimescale = 100f; | ||
431 | // m_bankingEfficiency = 0; | ||
432 | // m_bankingMix = 0.7f; | ||
433 | // m_bankingTimescale = 5; | ||
434 | // m_referenceFrame = Quaternion.Identity; | ||
435 | m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | | ||
436 | VehicleFlag.HOVER_UP_ONLY | VehicleFlag.LIMIT_MOTOR_UP); | ||
437 | m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT); | ||
438 | break; | ||
439 | |||
440 | } | ||
441 | }//end SetDefaultsForType | ||
442 | |||
443 | internal void Enable(IntPtr pBody, OdeScene pParentScene) | ||
444 | { | ||
445 | if (m_type == Vehicle.TYPE_NONE) | ||
446 | return; | ||
447 | |||
448 | m_body = pBody; | ||
449 | } | ||
450 | |||
451 | internal void Step(float pTimestep, OdeScene pParentScene) | ||
452 | { | ||
453 | if (m_body == IntPtr.Zero || m_type == Vehicle.TYPE_NONE) | ||
454 | return; | ||
455 | frcount++; // used to limit debug comment output | ||
456 | if (frcount > 100) | ||
457 | frcount = 0; | ||
458 | |||
459 | MoveLinear(pTimestep, pParentScene); | ||
460 | MoveAngular(pTimestep); | ||
461 | }// end Step | ||
462 | |||
463 | internal void Halt() | ||
464 | { // Kill all motions, when non-physical | ||
465 | m_linearMotorDirection = Vector3.Zero; | ||
466 | m_linearMotorDirectionLASTSET = Vector3.Zero; | ||
467 | m_dir = Vector3.Zero; | ||
468 | m_lastLinearVelocityVector = Vector3.Zero; | ||
469 | m_angularMotorDirection = Vector3.Zero; | ||
470 | m_angularMotorVelocity = Vector3.Zero; | ||
471 | m_lastAngularVelocity = Vector3.Zero; | ||
472 | } | ||
473 | |||
474 | private void MoveLinear(float pTimestep, OdeScene _pParentScene) | ||
475 | { | ||
476 | if (!m_linearMotorDirection.ApproxEquals(Vector3.Zero, 0.01f)) // requested m_linearMotorDirection is significant | ||
477 | { | ||
478 | if(!d.BodyIsEnabled (Body)) d.BodyEnable (Body); | ||
479 | |||
480 | // add drive to body | ||
481 | float linfactor = m_linearMotorTimescale/pTimestep; | ||
482 | // Linear accel | ||
483 | Vector3 addAmount1 = (m_linearMotorDirection/linfactor) * 0.8f; | ||
484 | // Differential accel | ||
485 | Vector3 addAmount2 = ((m_linearMotorDirection - m_lastLinearVelocityVector)/linfactor) * 1.6f; | ||
486 | // SL correction | ||
487 | Vector3 addAmount = (addAmount1 + addAmount2) * m_linearAttackFactor; | ||
488 | m_lastLinearVelocityVector += addAmount; // lastLinearVelocityVector is the current body velocity vector | ||
489 | //if(frcount == 0) Console.WriteLine("AL {0} + AD {1} AS{2} V {3}", addAmount1, addAmount2, addAmount, m_lastLinearVelocityVector); | ||
490 | // This will work temporarily, but we really need to compare speed on an axis | ||
491 | // KF: Limit body velocity to applied velocity? | ||
492 | if (Math.Abs(m_lastLinearVelocityVector.X) > Math.Abs(m_linearMotorDirectionLASTSET.X)) | ||
493 | m_lastLinearVelocityVector.X = m_linearMotorDirectionLASTSET.X; | ||
494 | if (Math.Abs(m_lastLinearVelocityVector.Y) > Math.Abs(m_linearMotorDirectionLASTSET.Y)) | ||
495 | m_lastLinearVelocityVector.Y = m_linearMotorDirectionLASTSET.Y; | ||
496 | if (Math.Abs(m_lastLinearVelocityVector.Z) > Math.Abs(m_linearMotorDirectionLASTSET.Z)) | ||
497 | m_lastLinearVelocityVector.Z = m_linearMotorDirectionLASTSET.Z; | ||
498 | |||
499 | // decay applied velocity | ||
500 | Vector3 decayfraction = ((Vector3.One/(m_linearMotorDecayTimescale/pTimestep))); | ||
501 | //Console.WriteLine("decay: " + decayfraction); | ||
502 | m_linearMotorDirection -= m_linearMotorDirection * decayfraction * m_linearDecayFactor; | ||
503 | //Console.WriteLine("actual: " + m_linearMotorDirection); | ||
504 | } | ||
505 | else | ||
506 | { // requested is not significant | ||
507 | // if what remains of applied is small, zero it. | ||
508 | if (m_lastLinearVelocityVector.ApproxEquals(Vector3.Zero, 0.01f)) | ||
509 | m_lastLinearVelocityVector = Vector3.Zero; | ||
510 | } | ||
511 | |||
512 | |||
513 | // convert requested object velocity to world-referenced vector | ||
514 | m_dir = m_lastLinearVelocityVector; | ||
515 | d.Quaternion rot = d.BodyGetQuaternion(Body); | ||
516 | Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); // rotq = rotation of object | ||
517 | m_dir *= rotq; // apply obj rotation to velocity vector | ||
518 | |||
519 | // add Gravity and Buoyancy | ||
520 | // KF: So far I have found no good method to combine a script-requested | ||
521 | // .Z velocity and gravity. Therefore only 0g will used script-requested | ||
522 | // .Z velocity. >0g (m_VehicleBuoyancy < 1) will used modified gravity only. | ||
523 | Vector3 grav = Vector3.Zero; | ||
524 | if(m_VehicleBuoyancy < 1.0f) | ||
525 | { | ||
526 | // There is some gravity, make a gravity force vector | ||
527 | // that is applied after object velocity. | ||
528 | d.Mass objMass; | ||
529 | d.BodyGetMass(Body, out objMass); | ||
530 | // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; | ||
531 | grav.Z = _pParentScene.gravityz * objMass.mass * (1f - m_VehicleBuoyancy); | ||
532 | // Preserve the current Z velocity | ||
533 | d.Vector3 vel_now = d.BodyGetLinearVel(Body); | ||
534 | m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity | ||
535 | } // else its 1.0, no gravity. | ||
536 | |||
537 | // Check if hovering | ||
538 | if( (m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) | ||
539 | { | ||
540 | // We should hover, get the target height | ||
541 | d.Vector3 pos = d.BodyGetPosition(Body); | ||
542 | if((m_flags & VehicleFlag.HOVER_WATER_ONLY) == VehicleFlag.HOVER_WATER_ONLY) | ||
543 | { | ||
544 | m_VhoverTargetHeight = _pParentScene.GetWaterLevel() + m_VhoverHeight; | ||
545 | } | ||
546 | else if((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) == VehicleFlag.HOVER_TERRAIN_ONLY) | ||
547 | { | ||
548 | m_VhoverTargetHeight = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y) + m_VhoverHeight; | ||
549 | } | ||
550 | else if((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) == VehicleFlag.HOVER_GLOBAL_HEIGHT) | ||
551 | { | ||
552 | m_VhoverTargetHeight = m_VhoverHeight; | ||
553 | } | ||
554 | |||
555 | if((m_flags & VehicleFlag.HOVER_UP_ONLY) == VehicleFlag.HOVER_UP_ONLY) | ||
556 | { | ||
557 | // If body is aready heigher, use its height as target height | ||
558 | if(pos.Z > m_VhoverTargetHeight) m_VhoverTargetHeight = pos.Z; | ||
559 | } | ||
560 | |||
561 | // m_VhoverEfficiency = 0f; // 0=boucy, 1=Crit.damped | ||
562 | // m_VhoverTimescale = 0f; // time to acheive height | ||
563 | // pTimestep is time since last frame,in secs | ||
564 | float herr0 = pos.Z - m_VhoverTargetHeight; | ||
565 | // Replace Vertical speed with correction figure if significant | ||
566 | if(Math.Abs(herr0) > 0.01f ) | ||
567 | { | ||
568 | d.Mass objMass; | ||
569 | d.BodyGetMass(Body, out objMass); | ||
570 | m_dir.Z = - ( (herr0 * pTimestep * 50.0f) / m_VhoverTimescale); | ||
571 | //KF: m_VhoverEfficiency is not yet implemented | ||
572 | } | ||
573 | else | ||
574 | { | ||
575 | m_dir.Z = 0f; | ||
576 | } | ||
577 | } | ||
578 | |||
579 | // Apply velocity | ||
580 | d.BodySetLinearVel(Body, m_dir.X, m_dir.Y, m_dir.Z); | ||
581 | // apply gravity force | ||
582 | d.BodyAddForce(Body, grav.X, grav.Y, grav.Z); | ||
583 | |||
584 | |||
585 | // apply friction | ||
586 | Vector3 decayamount = Vector3.One / (m_linearFrictionTimescale / pTimestep); | ||
587 | m_lastLinearVelocityVector -= m_lastLinearVelocityVector * decayamount * m_linearFrictionFactor; | ||
588 | } // end MoveLinear() | ||
589 | |||
590 | private void MoveAngular(float pTimestep) | ||
591 | { | ||
592 | /* | ||
593 | private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor | ||
594 | private int m_angularMotorApply = 0; // application frame counter | ||
595 | private float m_angularMotorVelocity = 0; // current angular motor velocity (ramps up and down) | ||
596 | private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate | ||
597 | private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate | ||
598 | private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate | ||
599 | private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body | ||
600 | */ | ||
601 | //if(frcount == 0) Console.WriteLine("MoveAngular "); | ||
602 | |||
603 | // Get what the body is doing, this includes 'external' influences | ||
604 | d.Vector3 angularVelocity = d.BodyGetAngularVel(Body); | ||
605 | // Vector3 angularVelocity = Vector3.Zero; | ||
606 | |||
607 | if (m_angularMotorApply > 0) | ||
608 | { | ||
609 | // ramp up to new value | ||
610 | // current velocity += error / ( time to get there / step interval ) | ||
611 | // requested speed - last motor speed | ||
612 | m_angularMotorVelocity.X += (m_angularMotorDirection.X - m_angularMotorVelocity.X) / (m_angularMotorTimescale / pTimestep); | ||
613 | m_angularMotorVelocity.Y += (m_angularMotorDirection.Y - m_angularMotorVelocity.Y) / (m_angularMotorTimescale / pTimestep); | ||
614 | m_angularMotorVelocity.Z += (m_angularMotorDirection.Z - m_angularMotorVelocity.Z) / (m_angularMotorTimescale / pTimestep); | ||
615 | |||
616 | m_angularMotorApply--; // This is done so that if script request rate is less than phys frame rate the expected | ||
617 | // velocity may still be acheived. | ||
618 | } | ||
619 | else | ||
620 | { | ||
621 | // no motor recently applied, keep the body velocity | ||
622 | /* m_angularMotorVelocity.X = angularVelocity.X; | ||
623 | m_angularMotorVelocity.Y = angularVelocity.Y; | ||
624 | m_angularMotorVelocity.Z = angularVelocity.Z; */ | ||
625 | |||
626 | // and decay the velocity | ||
627 | m_angularMotorVelocity -= m_angularMotorVelocity / (m_angularMotorDecayTimescale / pTimestep); | ||
628 | } // end motor section | ||
629 | |||
630 | |||
631 | // Vertical attractor section | ||
632 | Vector3 vertattr = Vector3.Zero; | ||
633 | |||
634 | if(m_verticalAttractionTimescale < 300) | ||
635 | { | ||
636 | float VAservo = 0.2f / (m_verticalAttractionTimescale * pTimestep); | ||
637 | // get present body rotation | ||
638 | d.Quaternion rot = d.BodyGetQuaternion(Body); | ||
639 | Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); | ||
640 | // make a vector pointing up | ||
641 | Vector3 verterr = Vector3.Zero; | ||
642 | verterr.Z = 1.0f; | ||
643 | // rotate it to Body Angle | ||
644 | verterr = verterr * rotq; | ||
645 | // verterr.X and .Y are the World error ammounts. They are 0 when there is no error (Vehicle Body is 'vertical'), and .Z will be 1. | ||
646 | // As the body leans to its side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall and .Z will go | ||
647 | // negative. Similar for tilt and |.Y|. .X and .Y must be modulated to prevent a stable inverted body. | ||
648 | if (verterr.Z < 0.0f) | ||
649 | { | ||
650 | verterr.X = 2.0f - verterr.X; | ||
651 | verterr.Y = 2.0f - verterr.Y; | ||
652 | } | ||
653 | // Error is 0 (no error) to +/- 2 (max error) | ||
654 | // scale it by VAservo | ||
655 | verterr = verterr * VAservo; | ||
656 | //if(frcount == 0) Console.WriteLine("VAerr=" + verterr); | ||
657 | |||
658 | // As the body rotates around the X axis, then verterr.Y increases; Rotated around Y then .X increases, so | ||
659 | // Change Body angular velocity X based on Y, and Y based on X. Z is not changed. | ||
660 | vertattr.X = verterr.Y; | ||
661 | vertattr.Y = - verterr.X; | ||
662 | vertattr.Z = 0f; | ||
663 | |||
664 | // scaling appears better usingsquare-law | ||
665 | float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); | ||
666 | vertattr.X += bounce * angularVelocity.X; | ||
667 | vertattr.Y += bounce * angularVelocity.Y; | ||
668 | |||
669 | } // else vertical attractor is off | ||
670 | |||
671 | // m_lastVertAttractor = vertattr; | ||
672 | |||
673 | // Bank section tba | ||
674 | // Deflection section tba | ||
675 | |||
676 | // Sum velocities | ||
677 | m_lastAngularVelocity = m_angularMotorVelocity + vertattr; // tba: + bank + deflection | ||
678 | |||
679 | if (!m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) | ||
680 | { | ||
681 | if(!d.BodyIsEnabled (Body)) d.BodyEnable (Body); | ||
682 | } | ||
683 | else | ||
684 | { | ||
685 | m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero. | ||
686 | } | ||
687 | |||
688 | // apply friction | ||
689 | Vector3 decayamount = Vector3.One / (m_angularFrictionTimescale / pTimestep); | ||
690 | m_lastAngularVelocity -= m_lastAngularVelocity * decayamount; | ||
691 | |||
692 | // Apply to the body | ||
693 | d.BodySetAngularVel (Body, m_lastAngularVelocity.X, m_lastAngularVelocity.Y, m_lastAngularVelocity.Z); | ||
694 | |||
695 | } //end MoveAngular | ||
696 | } | ||
697 | } | ||
diff --git a/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs new file mode 100644 index 0000000..6e6b44f --- /dev/null +++ b/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs | |||
@@ -0,0 +1,3277 @@ | |||
1 | /* Copyright (c) Contributors, http://opensimulator.org/ | ||
2 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
3 | * Redistribution and use in source and binary forms, with or without | ||
4 | * modification, are permitted provided that the following conditions are met: | ||
5 | * * Redistributions of source code must retain the above copyright | ||
6 | * notice, this list of conditions and the following disclaimer. | ||
7 | * * Redistributions in binary form must reproduce the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer in the | ||
9 | * documentation and/or other materials provided with the distribution. | ||
10 | * * Neither the name of the OpenSimulator Project nor the | ||
11 | * names of its contributors may be used to endorse or promote products | ||
12 | * derived from this software without specific prior written permission. | ||
13 | * | ||
14 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
15 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
17 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
18 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
24 | * | ||
25 | * Revised August 26 2009 by Kitto Flora. ODEDynamics.cs replaces | ||
26 | * ODEVehicleSettings.cs. It and ODEPrim.cs are re-organised: | ||
27 | * ODEPrim.cs contains methods dealing with Prim editing, Prim | ||
28 | * characteristics and Kinetic motion. | ||
29 | * ODEDynamics.cs contains methods dealing with Prim Physical motion | ||
30 | * (dynamics) and the associated settings. Old Linear and angular | ||
31 | * motors for dynamic motion have been replace with MoveLinear() | ||
32 | * and MoveAngular(); 'Physical' is used only to switch ODE dynamic | ||
33 | * simualtion on/off; VEHICAL_TYPE_NONE/VEHICAL_TYPE_<other> is to | ||
34 | * switch between 'VEHICLE' parameter use and general dynamics | ||
35 | * settings use. | ||
36 | */ | ||
37 | |||
38 | /* | ||
39 | * Revised August 26 2009 by Kitto Flora. ODEDynamics.cs replaces | ||
40 | * ODEVehicleSettings.cs. It and ODEPrim.cs are re-organised: | ||
41 | * ODEPrim.cs contains methods dealing with Prim editing, Prim | ||
42 | * characteristics and Kinetic motion. | ||
43 | * ODEDynamics.cs contains methods dealing with Prim Physical motion | ||
44 | * (dynamics) and the associated settings. Old Linear and angular | ||
45 | * motors for dynamic motion have been replace with MoveLinear() | ||
46 | * and MoveAngular(); 'Physical' is used only to switch ODE dynamic | ||
47 | * simualtion on/off; VEHICAL_TYPE_NONE/VEHICAL_TYPE_<other> is to | ||
48 | * switch between 'VEHICLE' parameter use and general dynamics | ||
49 | * settings use. | ||
50 | */ | ||
51 | using System; | ||
52 | using System.Collections.Generic; | ||
53 | using System.Reflection; | ||
54 | using System.Runtime.InteropServices; | ||
55 | using System.Threading; | ||
56 | using log4net; | ||
57 | using OpenMetaverse; | ||
58 | using Ode.NET; | ||
59 | using OpenSim.Framework; | ||
60 | using OpenSim.Region.Physics.Manager; | ||
61 | |||
62 | namespace OpenSim.Region.Physics.OdePlugin | ||
63 | { | ||
64 | /// <summary> | ||
65 | /// Various properties that ODE uses for AMotors but isn't exposed in ODE.NET so we must define them ourselves. | ||
66 | /// </summary> | ||
67 | |||
68 | public class OdePrim : PhysicsActor | ||
69 | { | ||
70 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
71 | |||
72 | private Vector3 _position; | ||
73 | private Vector3 _velocity; | ||
74 | private Vector3 _torque; | ||
75 | private Vector3 m_lastVelocity; | ||
76 | private Vector3 m_lastposition; | ||
77 | private Quaternion m_lastorientation = new Quaternion(); | ||
78 | private Vector3 m_rotationalVelocity; | ||
79 | private Vector3 _size; | ||
80 | private Vector3 _acceleration; | ||
81 | // private d.Vector3 _zeroPosition = new d.Vector3(0.0f, 0.0f, 0.0f); | ||
82 | private Quaternion _orientation; | ||
83 | private Vector3 m_taintposition; | ||
84 | private Vector3 m_taintsize; | ||
85 | private Vector3 m_taintVelocity; | ||
86 | private Vector3 m_taintTorque; | ||
87 | private Quaternion m_taintrot; | ||
88 | private Vector3 m_angularlock = Vector3.One; | ||
89 | private Vector3 m_taintAngularLock = Vector3.One; | ||
90 | private IntPtr Amotor = IntPtr.Zero; | ||
91 | |||
92 | private Vector3 m_PIDTarget; | ||
93 | private float m_PIDTau; | ||
94 | private float PID_D = 35f; | ||
95 | private float PID_G = 25f; | ||
96 | private bool m_usePID = false; | ||
97 | |||
98 | private Quaternion m_APIDTarget = new Quaternion(); | ||
99 | private float m_APIDStrength = 0.5f; | ||
100 | private float m_APIDDamping = 0.5f; | ||
101 | private bool m_useAPID = false; | ||
102 | |||
103 | // KF: These next 7 params apply to llSetHoverHeight(float height, integer water, float tau), | ||
104 | // and are for non-VEHICLES only. | ||
105 | |||
106 | private float m_PIDHoverHeight; | ||
107 | private float m_PIDHoverTau; | ||
108 | private bool m_useHoverPID; | ||
109 | private PIDHoverType m_PIDHoverType = PIDHoverType.Ground; | ||
110 | private float m_targetHoverHeight; | ||
111 | private float m_groundHeight; | ||
112 | private float m_waterHeight; | ||
113 | private float m_buoyancy; //KF: m_buoyancy should be set by llSetBuoyancy() for non-vehicle. | ||
114 | |||
115 | // private float m_tensor = 5f; | ||
116 | private int body_autodisable_frames = 20; | ||
117 | |||
118 | |||
119 | private const CollisionCategories m_default_collisionFlags = (CollisionCategories.Geom | ||
120 | | CollisionCategories.Space | ||
121 | | CollisionCategories.Body | ||
122 | | CollisionCategories.Character | ||
123 | ); | ||
124 | private bool m_taintshape; | ||
125 | private bool m_taintPhysics; | ||
126 | private bool m_collidesLand = true; | ||
127 | private bool m_collidesWater; | ||
128 | public bool m_returnCollisions; | ||
129 | |||
130 | // Default we're a Geometry | ||
131 | private CollisionCategories m_collisionCategories = (CollisionCategories.Geom); | ||
132 | |||
133 | // Default, Collide with Other Geometries, spaces and Bodies | ||
134 | private CollisionCategories m_collisionFlags = m_default_collisionFlags; | ||
135 | |||
136 | public bool m_taintremove; | ||
137 | public bool m_taintdisable; | ||
138 | public bool m_disabled; | ||
139 | public bool m_taintadd; | ||
140 | public bool m_taintselected; | ||
141 | public bool m_taintCollidesWater; | ||
142 | |||
143 | public uint m_localID; | ||
144 | |||
145 | //public GCHandle gc; | ||
146 | private CollisionLocker ode; | ||
147 | |||
148 | private bool m_taintforce = false; | ||
149 | private bool m_taintaddangularforce = false; | ||
150 | private Vector3 m_force; | ||
151 | private List<Vector3> m_forcelist = new List<Vector3>(); | ||
152 | private List<Vector3> m_angularforcelist = new List<Vector3>(); | ||
153 | |||
154 | private IMesh _mesh; | ||
155 | private PrimitiveBaseShape _pbs; | ||
156 | private OdeScene _parent_scene; | ||
157 | public IntPtr m_targetSpace = IntPtr.Zero; | ||
158 | public IntPtr prim_geom; | ||
159 | public IntPtr prev_geom; | ||
160 | public IntPtr _triMeshData; | ||
161 | |||
162 | private IntPtr _linkJointGroup = IntPtr.Zero; | ||
163 | private PhysicsActor _parent; | ||
164 | private PhysicsActor m_taintparent; | ||
165 | |||
166 | private List<OdePrim> childrenPrim = new List<OdePrim>(); | ||
167 | |||
168 | private bool iscolliding; | ||
169 | private bool m_isphysical; | ||
170 | private bool m_isSelected; | ||
171 | |||
172 | internal bool m_isVolumeDetect; // If true, this prim only detects collisions but doesn't collide actively | ||
173 | |||
174 | private bool m_throttleUpdates; | ||
175 | private int throttleCounter; | ||
176 | public int m_interpenetrationcount; | ||
177 | public float m_collisionscore; | ||
178 | public int m_roundsUnderMotionThreshold; | ||
179 | private int m_crossingfailures; | ||
180 | |||
181 | public bool outofBounds; | ||
182 | private float m_density = 10.000006836f; // Aluminum g/cm3; | ||
183 | |||
184 | public bool _zeroFlag; | ||
185 | private bool m_lastUpdateSent; | ||
186 | |||
187 | public IntPtr Body = IntPtr.Zero; | ||
188 | public String m_primName; | ||
189 | private Vector3 _target_velocity; | ||
190 | public d.Mass pMass; | ||
191 | |||
192 | public int m_eventsubscription; | ||
193 | private CollisionEventUpdate CollisionEventsThisFrame; | ||
194 | |||
195 | private IntPtr m_linkJoint = IntPtr.Zero; | ||
196 | |||
197 | public volatile bool childPrim; | ||
198 | |||
199 | private ODEDynamics m_vehicle; | ||
200 | |||
201 | internal int m_material = (int)Material.Wood; | ||
202 | |||
203 | private int frcount = 0; // Used to limit dynamics debug output to | ||
204 | |||
205 | |||
206 | public OdePrim(String primName, OdeScene parent_scene, Vector3 pos, Vector3 size, | ||
207 | Quaternion rotation, IMesh mesh, PrimitiveBaseShape pbs, bool pisPhysical, CollisionLocker dode) | ||
208 | { | ||
209 | m_vehicle = new ODEDynamics(); | ||
210 | //gc = GCHandle.Alloc(prim_geom, GCHandleType.Pinned); | ||
211 | ode = dode; | ||
212 | if (!pos.IsFinite()) | ||
213 | { | ||
214 | pos = new Vector3(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f), | ||
215 | parent_scene.GetTerrainHeightAtXY(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f)) + 0.5f); | ||
216 | m_log.Warn("[PHYSICS]: Got nonFinite Object create Position"); | ||
217 | } | ||
218 | |||
219 | _position = pos; | ||
220 | m_taintposition = pos; | ||
221 | PID_D = parent_scene.bodyPIDD; | ||
222 | PID_G = parent_scene.bodyPIDG; | ||
223 | m_density = parent_scene.geomDefaultDensity; | ||
224 | // m_tensor = parent_scene.bodyMotorJointMaxforceTensor; | ||
225 | body_autodisable_frames = parent_scene.bodyFramesAutoDisable; | ||
226 | |||
227 | |||
228 | prim_geom = IntPtr.Zero; | ||
229 | prev_geom = IntPtr.Zero; | ||
230 | |||
231 | if (!pos.IsFinite()) | ||
232 | { | ||
233 | size = new Vector3(0.5f, 0.5f, 0.5f); | ||
234 | m_log.Warn("[PHYSICS]: Got nonFinite Object create Size"); | ||
235 | } | ||
236 | |||
237 | if (size.X <= 0) size.X = 0.01f; | ||
238 | if (size.Y <= 0) size.Y = 0.01f; | ||
239 | if (size.Z <= 0) size.Z = 0.01f; | ||
240 | |||
241 | _size = size; | ||
242 | m_taintsize = _size; | ||
243 | |||
244 | if (!QuaternionIsFinite(rotation)) | ||
245 | { | ||
246 | rotation = Quaternion.Identity; | ||
247 | m_log.Warn("[PHYSICS]: Got nonFinite Object create Rotation"); | ||
248 | } | ||
249 | |||
250 | _orientation = rotation; | ||
251 | m_taintrot = _orientation; | ||
252 | _mesh = mesh; | ||
253 | _pbs = pbs; | ||
254 | |||
255 | _parent_scene = parent_scene; | ||
256 | m_targetSpace = (IntPtr)0; | ||
257 | |||
258 | // if (pos.Z < 0) | ||
259 | if (pos.Z < parent_scene.GetTerrainHeightAtXY(pos.X, pos.Y)) | ||
260 | m_isphysical = false; | ||
261 | else | ||
262 | { | ||
263 | m_isphysical = pisPhysical; | ||
264 | // If we're physical, we need to be in the master space for now. | ||
265 | // linksets *should* be in a space together.. but are not currently | ||
266 | if (m_isphysical) | ||
267 | m_targetSpace = _parent_scene.space; | ||
268 | } | ||
269 | m_primName = primName; | ||
270 | m_taintadd = true; | ||
271 | _parent_scene.AddPhysicsActorTaint(this); | ||
272 | // don't do .add() here; old geoms get recycled with the same hash | ||
273 | } | ||
274 | |||
275 | public override int PhysicsActorType | ||
276 | { | ||
277 | get { return (int) ActorTypes.Prim; } | ||
278 | set { return; } | ||
279 | } | ||
280 | |||
281 | public override bool SetAlwaysRun | ||
282 | { | ||
283 | get { return false; } | ||
284 | set { return; } | ||
285 | } | ||
286 | |||
287 | public override uint LocalID | ||
288 | { | ||
289 | set { | ||
290 | //m_log.Info("[PHYSICS]: Setting TrackerID: " + value); | ||
291 | m_localID = value; } | ||
292 | } | ||
293 | |||
294 | public override bool Grabbed | ||
295 | { | ||
296 | set { return; } | ||
297 | } | ||
298 | |||
299 | public override bool Selected | ||
300 | { | ||
301 | set { | ||
302 | |||
303 | |||
304 | // This only makes the object not collidable if the object | ||
305 | // is physical or the object is modified somehow *IN THE FUTURE* | ||
306 | // without this, if an avatar selects prim, they can walk right | ||
307 | // through it while it's selected | ||
308 | m_collisionscore = 0; | ||
309 | if ((m_isphysical && !_zeroFlag) || !value) | ||
310 | { | ||
311 | m_taintselected = value; | ||
312 | _parent_scene.AddPhysicsActorTaint(this); | ||
313 | } | ||
314 | else | ||
315 | { | ||
316 | m_taintselected = value; | ||
317 | m_isSelected = value; | ||
318 | } | ||
319 | if(m_isSelected) disableBodySoft(); | ||
320 | } | ||
321 | } | ||
322 | |||
323 | public void SetGeom(IntPtr geom) | ||
324 | { | ||
325 | prev_geom = prim_geom; | ||
326 | prim_geom = geom; | ||
327 | //Console.WriteLine("SetGeom to " + prim_geom + " for " + m_primName); | ||
328 | if (prim_geom != IntPtr.Zero) | ||
329 | { | ||
330 | d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); | ||
331 | d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); | ||
332 | } | ||
333 | |||
334 | if (childPrim) | ||
335 | { | ||
336 | if (_parent != null && _parent is OdePrim) | ||
337 | { | ||
338 | OdePrim parent = (OdePrim)_parent; | ||
339 | //Console.WriteLine("SetGeom calls ChildSetGeom"); | ||
340 | parent.ChildSetGeom(this); | ||
341 | } | ||
342 | } | ||
343 | //m_log.Warn("Setting Geom to: " + prim_geom); | ||
344 | } | ||
345 | |||
346 | |||
347 | |||
348 | public void enableBodySoft() | ||
349 | { | ||
350 | if (!childPrim) | ||
351 | { | ||
352 | if (m_isphysical && Body != IntPtr.Zero) | ||
353 | { | ||
354 | d.BodyEnable(Body); | ||
355 | if (m_vehicle.Type != Vehicle.TYPE_NONE) | ||
356 | m_vehicle.Enable(Body, _parent_scene); | ||
357 | } | ||
358 | |||
359 | m_disabled = false; | ||
360 | } | ||
361 | } | ||
362 | |||
363 | public void disableBodySoft() | ||
364 | { | ||
365 | m_disabled = true; | ||
366 | |||
367 | if (m_isphysical && Body != IntPtr.Zero) | ||
368 | { | ||
369 | d.BodyDisable(Body); | ||
370 | } | ||
371 | } | ||
372 | |||
373 | public void enableBody() | ||
374 | { | ||
375 | // Don't enable this body if we're a child prim | ||
376 | // this should be taken care of in the parent function not here | ||
377 | if (!childPrim) | ||
378 | { | ||
379 | // Sets the geom to a body | ||
380 | Body = d.BodyCreate(_parent_scene.world); | ||
381 | |||
382 | setMass(); | ||
383 | d.BodySetPosition(Body, _position.X, _position.Y, _position.Z); | ||
384 | d.Quaternion myrot = new d.Quaternion(); | ||
385 | myrot.X = _orientation.X; | ||
386 | myrot.Y = _orientation.Y; | ||
387 | myrot.Z = _orientation.Z; | ||
388 | myrot.W = _orientation.W; | ||
389 | d.BodySetQuaternion(Body, ref myrot); | ||
390 | d.GeomSetBody(prim_geom, Body); | ||
391 | m_collisionCategories |= CollisionCategories.Body; | ||
392 | m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind); | ||
393 | |||
394 | d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); | ||
395 | d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); | ||
396 | |||
397 | d.BodySetAutoDisableFlag(Body, true); | ||
398 | d.BodySetAutoDisableSteps(Body, body_autodisable_frames); | ||
399 | |||
400 | // disconnect from world gravity so we can apply buoyancy | ||
401 | d.BodySetGravityMode (Body, false); | ||
402 | |||
403 | m_interpenetrationcount = 0; | ||
404 | m_collisionscore = 0; | ||
405 | m_disabled = false; | ||
406 | |||
407 | // The body doesn't already have a finite rotation mode set here | ||
408 | if ((!m_angularlock.ApproxEquals(Vector3.Zero, 0.0f)) && _parent == null) | ||
409 | { | ||
410 | createAMotor(m_angularlock); | ||
411 | } | ||
412 | if (m_vehicle.Type != Vehicle.TYPE_NONE) | ||
413 | { | ||
414 | m_vehicle.Enable(Body, _parent_scene); | ||
415 | } | ||
416 | |||
417 | _parent_scene.addActivePrim(this); | ||
418 | } | ||
419 | } | ||
420 | |||
421 | #region Mass Calculation | ||
422 | |||
423 | private float CalculateMass() | ||
424 | { | ||
425 | float volume = 0; | ||
426 | |||
427 | // No material is passed to the physics engines yet.. soo.. | ||
428 | // we're using the m_density constant in the class definition | ||
429 | |||
430 | float returnMass = 0; | ||
431 | |||
432 | switch (_pbs.ProfileShape) | ||
433 | { | ||
434 | case ProfileShape.Square: | ||
435 | // Profile Volume | ||
436 | |||
437 | volume = _size.X*_size.Y*_size.Z; | ||
438 | |||
439 | // If the user has 'hollowed out' | ||
440 | // ProfileHollow is one of those 0 to 50000 values :P | ||
441 | // we like percentages better.. so turning into a percentage | ||
442 | |||
443 | if (((float) _pbs.ProfileHollow/50000f) > 0.0) | ||
444 | { | ||
445 | float hollowAmount = (float) _pbs.ProfileHollow/50000f; | ||
446 | |||
447 | // calculate the hollow volume by it's shape compared to the prim shape | ||
448 | float hollowVolume = 0; | ||
449 | switch (_pbs.HollowShape) | ||
450 | { | ||
451 | case HollowShape.Square: | ||
452 | case HollowShape.Same: | ||
453 | // Cube Hollow volume calculation | ||
454 | float hollowsizex = _size.X*hollowAmount; | ||
455 | float hollowsizey = _size.Y*hollowAmount; | ||
456 | float hollowsizez = _size.Z*hollowAmount; | ||
457 | hollowVolume = hollowsizex*hollowsizey*hollowsizez; | ||
458 | break; | ||
459 | |||
460 | case HollowShape.Circle: | ||
461 | // Hollow shape is a perfect cyllinder in respect to the cube's scale | ||
462 | // Cyllinder hollow volume calculation | ||
463 | float hRadius = _size.X/2; | ||
464 | float hLength = _size.Z; | ||
465 | |||
466 | // pi * r2 * h | ||
467 | hollowVolume = ((float) (Math.PI*Math.Pow(hRadius, 2)*hLength)*hollowAmount); | ||
468 | break; | ||
469 | |||
470 | case HollowShape.Triangle: | ||
471 | // Equilateral Triangular Prism volume hollow calculation | ||
472 | // Triangle is an Equilateral Triangular Prism with aLength = to _size.Y | ||
473 | |||
474 | float aLength = _size.Y; | ||
475 | // 1/2 abh | ||
476 | hollowVolume = (float) ((0.5*aLength*_size.X*_size.Z)*hollowAmount); | ||
477 | break; | ||
478 | |||
479 | default: | ||
480 | hollowVolume = 0; | ||
481 | break; | ||
482 | } | ||
483 | volume = volume - hollowVolume; | ||
484 | } | ||
485 | |||
486 | break; | ||
487 | case ProfileShape.Circle: | ||
488 | if (_pbs.PathCurve == (byte)Extrusion.Straight) | ||
489 | { | ||
490 | // Cylinder | ||
491 | float volume1 = (float)(Math.PI * Math.Pow(_size.X/2, 2) * _size.Z); | ||
492 | float volume2 = (float)(Math.PI * Math.Pow(_size.Y/2, 2) * _size.Z); | ||
493 | |||
494 | // Approximating the cylinder's irregularity. | ||
495 | if (volume1 > volume2) | ||
496 | { | ||
497 | volume = (float)volume1 - (volume1 - volume2); | ||
498 | } | ||
499 | else if (volume2 > volume1) | ||
500 | { | ||
501 | volume = (float)volume2 - (volume2 - volume1); | ||
502 | } | ||
503 | else | ||
504 | { | ||
505 | // Regular cylinder | ||
506 | volume = volume1; | ||
507 | } | ||
508 | } | ||
509 | else | ||
510 | { | ||
511 | // We don't know what the shape is yet, so use default | ||
512 | volume = _size.X * _size.Y * _size.Z; | ||
513 | } | ||
514 | // If the user has 'hollowed out' | ||
515 | // ProfileHollow is one of those 0 to 50000 values :P | ||
516 | // we like percentages better.. so turning into a percentage | ||
517 | |||
518 | if (((float)_pbs.ProfileHollow / 50000f) > 0.0) | ||
519 | { | ||
520 | float hollowAmount = (float)_pbs.ProfileHollow / 50000f; | ||
521 | |||
522 | // calculate the hollow volume by it's shape compared to the prim shape | ||
523 | float hollowVolume = 0; | ||
524 | switch (_pbs.HollowShape) | ||
525 | { | ||
526 | case HollowShape.Same: | ||
527 | case HollowShape.Circle: | ||
528 | // Hollow shape is a perfect cyllinder in respect to the cube's scale | ||
529 | // Cyllinder hollow volume calculation | ||
530 | float hRadius = _size.X / 2; | ||
531 | float hLength = _size.Z; | ||
532 | |||
533 | // pi * r2 * h | ||
534 | hollowVolume = ((float)(Math.PI * Math.Pow(hRadius, 2) * hLength) * hollowAmount); | ||
535 | break; | ||
536 | |||
537 | case HollowShape.Square: | ||
538 | // Cube Hollow volume calculation | ||
539 | float hollowsizex = _size.X * hollowAmount; | ||
540 | float hollowsizey = _size.Y * hollowAmount; | ||
541 | float hollowsizez = _size.Z * hollowAmount; | ||
542 | hollowVolume = hollowsizex * hollowsizey * hollowsizez; | ||
543 | break; | ||
544 | |||
545 | case HollowShape.Triangle: | ||
546 | // Equilateral Triangular Prism volume hollow calculation | ||
547 | // Triangle is an Equilateral Triangular Prism with aLength = to _size.Y | ||
548 | |||
549 | float aLength = _size.Y; | ||
550 | // 1/2 abh | ||
551 | hollowVolume = (float)((0.5 * aLength * _size.X * _size.Z) * hollowAmount); | ||
552 | break; | ||
553 | |||
554 | default: | ||
555 | hollowVolume = 0; | ||
556 | break; | ||
557 | } | ||
558 | volume = volume - hollowVolume; | ||
559 | } | ||
560 | break; | ||
561 | |||
562 | case ProfileShape.HalfCircle: | ||
563 | if (_pbs.PathCurve == (byte)Extrusion.Curve1) | ||
564 | { | ||
565 | if (_size.X == _size.Y && _size.Y == _size.Z) | ||
566 | { | ||
567 | // regular sphere | ||
568 | // v = 4/3 * pi * r^3 | ||
569 | float sradius3 = (float)Math.Pow((_size.X / 2), 3); | ||
570 | volume = (float)((4f / 3f) * Math.PI * sradius3); | ||
571 | } | ||
572 | else | ||
573 | { | ||
574 | // we treat this as a box currently | ||
575 | volume = _size.X * _size.Y * _size.Z; | ||
576 | } | ||
577 | } | ||
578 | else | ||
579 | { | ||
580 | // We don't know what the shape is yet, so use default | ||
581 | volume = _size.X * _size.Y * _size.Z; | ||
582 | } | ||
583 | break; | ||
584 | |||
585 | case ProfileShape.EquilateralTriangle: | ||
586 | /* | ||
587 | v = (abs((xB*yA-xA*yB)+(xC*yB-xB*yC)+(xA*yC-xC*yA))/2) * h | ||
588 | |||
589 | // seed mesh | ||
590 | Vertex MM = new Vertex(-0.25f, -0.45f, 0.0f); | ||
591 | Vertex PM = new Vertex(+0.5f, 0f, 0.0f); | ||
592 | Vertex PP = new Vertex(-0.25f, +0.45f, 0.0f); | ||
593 | */ | ||
594 | float xA = -0.25f * _size.X; | ||
595 | float yA = -0.45f * _size.Y; | ||
596 | |||
597 | float xB = 0.5f * _size.X; | ||
598 | float yB = 0; | ||
599 | |||
600 | float xC = -0.25f * _size.X; | ||
601 | float yC = 0.45f * _size.Y; | ||
602 | |||
603 | volume = (float)((Math.Abs((xB * yA - xA * yB) + (xC * yB - xB * yC) + (xA * yC - xC * yA)) / 2) * _size.Z); | ||
604 | |||
605 | // If the user has 'hollowed out' | ||
606 | // ProfileHollow is one of those 0 to 50000 values :P | ||
607 | // we like percentages better.. so turning into a percentage | ||
608 | float fhollowFactor = ((float)_pbs.ProfileHollow / 1.9f); | ||
609 | if (((float)fhollowFactor / 50000f) > 0.0) | ||
610 | { | ||
611 | float hollowAmount = (float)fhollowFactor / 50000f; | ||
612 | |||
613 | // calculate the hollow volume by it's shape compared to the prim shape | ||
614 | float hollowVolume = 0; | ||
615 | switch (_pbs.HollowShape) | ||
616 | { | ||
617 | case HollowShape.Same: | ||
618 | case HollowShape.Triangle: | ||
619 | // Equilateral Triangular Prism volume hollow calculation | ||
620 | // Triangle is an Equilateral Triangular Prism with aLength = to _size.Y | ||
621 | |||
622 | float aLength = _size.Y; | ||
623 | // 1/2 abh | ||
624 | hollowVolume = (float)((0.5 * aLength * _size.X * _size.Z) * hollowAmount); | ||
625 | break; | ||
626 | |||
627 | case HollowShape.Square: | ||
628 | // Cube Hollow volume calculation | ||
629 | float hollowsizex = _size.X * hollowAmount; | ||
630 | float hollowsizey = _size.Y * hollowAmount; | ||
631 | float hollowsizez = _size.Z * hollowAmount; | ||
632 | hollowVolume = hollowsizex * hollowsizey * hollowsizez; | ||
633 | break; | ||
634 | |||
635 | case HollowShape.Circle: | ||
636 | // Hollow shape is a perfect cyllinder in respect to the cube's scale | ||
637 | // Cyllinder hollow volume calculation | ||
638 | float hRadius = _size.X / 2; | ||
639 | float hLength = _size.Z; | ||
640 | |||
641 | // pi * r2 * h | ||
642 | hollowVolume = ((float)((Math.PI * Math.Pow(hRadius, 2) * hLength)/2) * hollowAmount); | ||
643 | break; | ||
644 | |||
645 | default: | ||
646 | hollowVolume = 0; | ||
647 | break; | ||
648 | } | ||
649 | volume = volume - hollowVolume; | ||
650 | } | ||
651 | break; | ||
652 | |||
653 | default: | ||
654 | // we don't have all of the volume formulas yet so | ||
655 | // use the common volume formula for all | ||
656 | volume = _size.X*_size.Y*_size.Z; | ||
657 | break; | ||
658 | } | ||
659 | |||
660 | // Calculate Path cut effect on volume | ||
661 | // Not exact, in the triangle hollow example | ||
662 | // They should never be zero or less then zero.. | ||
663 | // we'll ignore it if it's less then zero | ||
664 | |||
665 | // ProfileEnd and ProfileBegin are values | ||
666 | // from 0 to 50000 | ||
667 | |||
668 | // Turning them back into percentages so that I can cut that percentage off the volume | ||
669 | |||
670 | float PathCutEndAmount = _pbs.ProfileEnd; | ||
671 | float PathCutStartAmount = _pbs.ProfileBegin; | ||
672 | if (((PathCutStartAmount + PathCutEndAmount)/50000f) > 0.0f) | ||
673 | { | ||
674 | float pathCutAmount = ((PathCutStartAmount + PathCutEndAmount)/50000f); | ||
675 | |||
676 | // Check the return amount for sanity | ||
677 | if (pathCutAmount >= 0.99f) | ||
678 | pathCutAmount = 0.99f; | ||
679 | |||
680 | volume = volume - (volume*pathCutAmount); | ||
681 | } | ||
682 | UInt16 taperX = _pbs.PathScaleX; | ||
683 | UInt16 taperY = _pbs.PathScaleY; | ||
684 | float taperFactorX = 0; | ||
685 | float taperFactorY = 0; | ||
686 | |||
687 | // Mass = density * volume | ||
688 | if (taperX != 100) | ||
689 | { | ||
690 | if (taperX > 100) | ||
691 | { | ||
692 | taperFactorX = 1.0f - ((float)taperX / 200); | ||
693 | //m_log.Warn("taperTopFactorX: " + extr.taperTopFactorX.ToString()); | ||
694 | } | ||
695 | else | ||
696 | { | ||
697 | taperFactorX = 1.0f - ((100 - (float)taperX) / 100); | ||
698 | //m_log.Warn("taperBotFactorX: " + extr.taperBotFactorX.ToString()); | ||
699 | } | ||
700 | volume = (float)volume * ((taperFactorX / 3f) + 0.001f); | ||
701 | } | ||
702 | |||
703 | if (taperY != 100) | ||
704 | { | ||
705 | if (taperY > 100) | ||
706 | { | ||
707 | taperFactorY = 1.0f - ((float)taperY / 200); | ||
708 | //m_log.Warn("taperTopFactorY: " + extr.taperTopFactorY.ToString()); | ||
709 | } | ||
710 | else | ||
711 | { | ||
712 | taperFactorY = 1.0f - ((100 - (float)taperY) / 100); | ||
713 | //m_log.Warn("taperBotFactorY: " + extr.taperBotFactorY.ToString()); | ||
714 | } | ||
715 | volume = (float)volume * ((taperFactorY / 3f) + 0.001f); | ||
716 | } | ||
717 | returnMass = m_density*volume; | ||
718 | if (returnMass <= 0) returnMass = 0.0001f;//ckrinke: Mass must be greater then zero. | ||
719 | |||
720 | |||
721 | |||
722 | // Recursively calculate mass | ||
723 | bool HasChildPrim = false; | ||
724 | lock (childrenPrim) | ||
725 | { | ||
726 | if (childrenPrim.Count > 0) | ||
727 | { | ||
728 | HasChildPrim = true; | ||
729 | } | ||
730 | |||
731 | } | ||
732 | if (HasChildPrim) | ||
733 | { | ||
734 | OdePrim[] childPrimArr = new OdePrim[0]; | ||
735 | |||
736 | lock (childrenPrim) | ||
737 | childPrimArr = childrenPrim.ToArray(); | ||
738 | |||
739 | for (int i = 0; i < childPrimArr.Length; i++) | ||
740 | { | ||
741 | if (childPrimArr[i] != null && !childPrimArr[i].m_taintremove) | ||
742 | returnMass += childPrimArr[i].CalculateMass(); | ||
743 | // failsafe, this shouldn't happen but with OpenSim, you never know :) | ||
744 | if (i > 256) | ||
745 | break; | ||
746 | } | ||
747 | } | ||
748 | if (returnMass > _parent_scene.maximumMassObject) | ||
749 | returnMass = _parent_scene.maximumMassObject; | ||
750 | return returnMass; | ||
751 | }// end CalculateMass | ||
752 | |||
753 | #endregion | ||
754 | |||
755 | public void setMass() | ||
756 | { | ||
757 | if (Body != (IntPtr) 0) | ||
758 | { | ||
759 | float newmass = CalculateMass(); | ||
760 | |||
761 | //m_log.Info("[PHYSICS]: New Mass: " + newmass.ToString()); | ||
762 | |||
763 | d.MassSetBoxTotal(out pMass, newmass, _size.X, _size.Y, _size.Z); | ||
764 | d.BodySetMass(Body, ref pMass); | ||
765 | } | ||
766 | } | ||
767 | |||
768 | public void disableBody() | ||
769 | { | ||
770 | //this kills the body so things like 'mesh' can re-create it. | ||
771 | lock (this) | ||
772 | { | ||
773 | if (!childPrim) | ||
774 | { | ||
775 | if (Body != IntPtr.Zero) | ||
776 | { | ||
777 | _parent_scene.remActivePrim(this); | ||
778 | m_collisionCategories &= ~CollisionCategories.Body; | ||
779 | m_collisionFlags &= ~(CollisionCategories.Wind | CollisionCategories.Land); | ||
780 | |||
781 | if (prim_geom != IntPtr.Zero) | ||
782 | { | ||
783 | d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); | ||
784 | d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); | ||
785 | } | ||
786 | |||
787 | |||
788 | d.BodyDestroy(Body); | ||
789 | lock (childrenPrim) | ||
790 | { | ||
791 | if (childrenPrim.Count > 0) | ||
792 | { | ||
793 | foreach (OdePrim prm in childrenPrim) | ||
794 | { | ||
795 | _parent_scene.remActivePrim(prm); | ||
796 | prm.Body = IntPtr.Zero; | ||
797 | } | ||
798 | } | ||
799 | } | ||
800 | Body = IntPtr.Zero; | ||
801 | } | ||
802 | } | ||
803 | else | ||
804 | { | ||
805 | _parent_scene.remActivePrim(this); | ||
806 | |||
807 | m_collisionCategories &= ~CollisionCategories.Body; | ||
808 | m_collisionFlags &= ~(CollisionCategories.Wind | CollisionCategories.Land); | ||
809 | |||
810 | if (prim_geom != IntPtr.Zero) | ||
811 | { | ||
812 | d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); | ||
813 | d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); | ||
814 | } | ||
815 | |||
816 | |||
817 | Body = IntPtr.Zero; | ||
818 | } | ||
819 | } | ||
820 | m_disabled = true; | ||
821 | m_collisionscore = 0; | ||
822 | } | ||
823 | |||
824 | private static Dictionary<IMesh, IntPtr> m_MeshToTriMeshMap = new Dictionary<IMesh, IntPtr>(); | ||
825 | |||
826 | public void setMesh(OdeScene parent_scene, IMesh mesh) | ||
827 | { | ||
828 | // This sleeper is there to moderate how long it takes between | ||
829 | // setting up the mesh and pre-processing it when we get rapid fire mesh requests on a single object | ||
830 | |||
831 | //Thread.Sleep(10); | ||
832 | |||
833 | //Kill Body so that mesh can re-make the geom | ||
834 | if (IsPhysical && Body != IntPtr.Zero) | ||
835 | { | ||
836 | if (childPrim) | ||
837 | { | ||
838 | if (_parent != null) | ||
839 | { | ||
840 | OdePrim parent = (OdePrim)_parent; | ||
841 | parent.ChildDelink(this); | ||
842 | } | ||
843 | } | ||
844 | else | ||
845 | { | ||
846 | disableBody(); | ||
847 | } | ||
848 | } | ||
849 | |||
850 | IntPtr vertices, indices; | ||
851 | int vertexCount, indexCount; | ||
852 | int vertexStride, triStride; | ||
853 | mesh.getVertexListAsPtrToFloatArray(out vertices, out vertexStride, out vertexCount); // Note, that vertices are fixed in unmanaged heap | ||
854 | mesh.getIndexListAsPtrToIntArray(out indices, out triStride, out indexCount); // Also fixed, needs release after usage | ||
855 | |||
856 | mesh.releaseSourceMeshData(); // free up the original mesh data to save memory | ||
857 | if (m_MeshToTriMeshMap.ContainsKey(mesh)) | ||
858 | { | ||
859 | _triMeshData = m_MeshToTriMeshMap[mesh]; | ||
860 | } | ||
861 | else | ||
862 | { | ||
863 | _triMeshData = d.GeomTriMeshDataCreate(); | ||
864 | |||
865 | d.GeomTriMeshDataBuildSimple(_triMeshData, vertices, vertexStride, vertexCount, indices, indexCount, triStride); | ||
866 | d.GeomTriMeshDataPreprocess(_triMeshData); | ||
867 | m_MeshToTriMeshMap[mesh] = _triMeshData; | ||
868 | } | ||
869 | |||
870 | _parent_scene.waitForSpaceUnlock(m_targetSpace); | ||
871 | try | ||
872 | { | ||
873 | if (prim_geom == IntPtr.Zero) | ||
874 | { | ||
875 | SetGeom(d.CreateTriMesh(m_targetSpace, _triMeshData, parent_scene.triCallback, null, null)); | ||
876 | } | ||
877 | } | ||
878 | catch (AccessViolationException) | ||
879 | { | ||
880 | m_log.Error("[PHYSICS]: MESH LOCKED"); | ||
881 | return; | ||
882 | } | ||
883 | |||
884 | |||
885 | // if (IsPhysical && Body == (IntPtr) 0) | ||
886 | // { | ||
887 | // Recreate the body | ||
888 | // m_interpenetrationcount = 0; | ||
889 | // m_collisionscore = 0; | ||
890 | |||
891 | // enableBody(); | ||
892 | // } | ||
893 | } | ||
894 | |||
895 | public void ProcessTaints(float timestep) | ||
896 | { | ||
897 | //Console.WriteLine("ProcessTaints for " + m_primName ); | ||
898 | if (m_taintadd) | ||
899 | { | ||
900 | changeadd(timestep); | ||
901 | } | ||
902 | |||
903 | if (prim_geom != IntPtr.Zero) | ||
904 | { | ||
905 | if (!_position.ApproxEquals(m_taintposition, 0f)) | ||
906 | changemove(timestep); | ||
907 | |||
908 | if (m_taintrot != _orientation) | ||
909 | { | ||
910 | if(childPrim && IsPhysical) // For physical child prim... | ||
911 | { | ||
912 | rotate(timestep); | ||
913 | // KF: ODE will also rotate the parent prim! | ||
914 | // so rotate the root back to where it was | ||
915 | OdePrim parent = (OdePrim)_parent; | ||
916 | parent.rotate(timestep); | ||
917 | } | ||
918 | else | ||
919 | { | ||
920 | //Just rotate the prim | ||
921 | rotate(timestep); | ||
922 | } | ||
923 | } | ||
924 | // | ||
925 | |||
926 | if (m_taintPhysics != m_isphysical && !(m_taintparent != _parent)) | ||
927 | changePhysicsStatus(timestep); | ||
928 | // | ||
929 | |||
930 | if (!_size.ApproxEquals(m_taintsize,0f)) | ||
931 | changesize(timestep); | ||
932 | // | ||
933 | |||
934 | if (m_taintshape) | ||
935 | changeshape(timestep); | ||
936 | // | ||
937 | |||
938 | if (m_taintforce) | ||
939 | changeAddForce(timestep); | ||
940 | |||
941 | if (m_taintaddangularforce) | ||
942 | changeAddAngularForce(timestep); | ||
943 | |||
944 | if (!m_taintTorque.ApproxEquals(Vector3.Zero, 0.001f)) | ||
945 | changeSetTorque(timestep); | ||
946 | |||
947 | if (m_taintdisable) | ||
948 | changedisable(timestep); | ||
949 | |||
950 | if (m_taintselected != m_isSelected) | ||
951 | changeSelectedStatus(timestep); | ||
952 | |||
953 | if (!m_taintVelocity.ApproxEquals(Vector3.Zero, 0.001f)) | ||
954 | changevelocity(timestep); | ||
955 | |||
956 | if (m_taintparent != _parent) | ||
957 | changelink(timestep); | ||
958 | |||
959 | if (m_taintCollidesWater != m_collidesWater) | ||
960 | changefloatonwater(timestep); | ||
961 | |||
962 | if (!m_angularlock.ApproxEquals(m_taintAngularLock,0f)) | ||
963 | changeAngularLock(timestep); | ||
964 | |||
965 | } | ||
966 | else | ||
967 | { | ||
968 | m_log.Error("[PHYSICS]: The scene reused a disposed PhysActor! *waves finger*, Don't be evil. A couple of things can cause this. An improper prim breakdown(be sure to set prim_geom to zero after d.GeomDestroy! An improper buildup (creating the geom failed). Or, the Scene Reused a physics actor after disposing it.)"); | ||
969 | } | ||
970 | } | ||
971 | |||
972 | |||
973 | private void changeAngularLock(float timestep) | ||
974 | { | ||
975 | // do we have a Physical object? | ||
976 | if (Body != IntPtr.Zero) | ||
977 | { | ||
978 | //Check that we have a Parent | ||
979 | //If we have a parent then we're not authorative here | ||
980 | if (_parent == null) | ||
981 | { | ||
982 | if (!m_taintAngularLock.ApproxEquals(Vector3.One, 0f)) | ||
983 | { | ||
984 | //d.BodySetFiniteRotationMode(Body, 0); | ||
985 | //d.BodySetFiniteRotationAxis(Body,m_taintAngularLock.X,m_taintAngularLock.Y,m_taintAngularLock.Z); | ||
986 | createAMotor(m_taintAngularLock); | ||
987 | } | ||
988 | else | ||
989 | { | ||
990 | if (Amotor != IntPtr.Zero) | ||
991 | { | ||
992 | d.JointDestroy(Amotor); | ||
993 | Amotor = IntPtr.Zero; | ||
994 | } | ||
995 | } | ||
996 | } | ||
997 | } | ||
998 | // Store this for later in case we get turned into a separate body | ||
999 | m_angularlock = m_taintAngularLock; | ||
1000 | |||
1001 | } | ||
1002 | |||
1003 | private void changelink(float timestep) | ||
1004 | { | ||
1005 | // If the newly set parent is not null | ||
1006 | // create link | ||
1007 | if (_parent == null && m_taintparent != null) | ||
1008 | { | ||
1009 | if (m_taintparent.PhysicsActorType == (int)ActorTypes.Prim) | ||
1010 | { | ||
1011 | OdePrim obj = (OdePrim)m_taintparent; | ||
1012 | //obj.disableBody(); | ||
1013 | //Console.WriteLine("changelink calls ParentPrim"); | ||
1014 | obj.ParentPrim(this); | ||
1015 | |||
1016 | /* | ||
1017 | if (obj.Body != (IntPtr)0 && Body != (IntPtr)0 && obj.Body != Body) | ||
1018 | { | ||
1019 | _linkJointGroup = d.JointGroupCreate(0); | ||
1020 | m_linkJoint = d.JointCreateFixed(_parent_scene.world, _linkJointGroup); | ||
1021 | d.JointAttach(m_linkJoint, obj.Body, Body); | ||
1022 | d.JointSetFixed(m_linkJoint); | ||
1023 | } | ||
1024 | */ | ||
1025 | } | ||
1026 | } | ||
1027 | // If the newly set parent is null | ||
1028 | // destroy link | ||
1029 | else if (_parent != null && m_taintparent == null) | ||
1030 | { | ||
1031 | //Console.WriteLine(" changelink B"); | ||
1032 | |||
1033 | if (_parent is OdePrim) | ||
1034 | { | ||
1035 | OdePrim obj = (OdePrim)_parent; | ||
1036 | obj.ChildDelink(this); | ||
1037 | childPrim = false; | ||
1038 | //_parent = null; | ||
1039 | } | ||
1040 | |||
1041 | /* | ||
1042 | if (Body != (IntPtr)0 && _linkJointGroup != (IntPtr)0) | ||
1043 | d.JointGroupDestroy(_linkJointGroup); | ||
1044 | |||
1045 | _linkJointGroup = (IntPtr)0; | ||
1046 | m_linkJoint = (IntPtr)0; | ||
1047 | */ | ||
1048 | } | ||
1049 | |||
1050 | _parent = m_taintparent; | ||
1051 | m_taintPhysics = m_isphysical; | ||
1052 | } | ||
1053 | |||
1054 | // I'm the parent | ||
1055 | // prim is the child | ||
1056 | public void ParentPrim(OdePrim prim) | ||
1057 | { | ||
1058 | //Console.WriteLine("ParentPrim " + m_primName); | ||
1059 | if (this.m_localID != prim.m_localID) | ||
1060 | { | ||
1061 | if (Body == IntPtr.Zero) | ||
1062 | { | ||
1063 | Body = d.BodyCreate(_parent_scene.world); | ||
1064 | setMass(); | ||
1065 | } | ||
1066 | if (Body != IntPtr.Zero) | ||
1067 | { | ||
1068 | lock (childrenPrim) | ||
1069 | { | ||
1070 | if (!childrenPrim.Contains(prim)) | ||
1071 | { | ||
1072 | //Console.WriteLine("childrenPrim.Add " + prim); | ||
1073 | childrenPrim.Add(prim); | ||
1074 | |||
1075 | foreach (OdePrim prm in childrenPrim) | ||
1076 | { | ||
1077 | d.Mass m2; | ||
1078 | d.MassSetZero(out m2); | ||
1079 | d.MassSetBoxTotal(out m2, prim.CalculateMass(), prm._size.X, prm._size.Y, prm._size.Z); | ||
1080 | |||
1081 | |||
1082 | d.Quaternion quat = new d.Quaternion(); | ||
1083 | quat.W = prm._orientation.W; | ||
1084 | quat.X = prm._orientation.X; | ||
1085 | quat.Y = prm._orientation.Y; | ||
1086 | quat.Z = prm._orientation.Z; | ||
1087 | |||
1088 | d.Matrix3 mat = new d.Matrix3(); | ||
1089 | d.RfromQ(out mat, ref quat); | ||
1090 | d.MassRotate(ref m2, ref mat); | ||
1091 | d.MassTranslate(ref m2, Position.X - prm.Position.X, Position.Y - prm.Position.Y, Position.Z - prm.Position.Z); | ||
1092 | d.MassAdd(ref pMass, ref m2); | ||
1093 | } | ||
1094 | foreach (OdePrim prm in childrenPrim) | ||
1095 | { | ||
1096 | |||
1097 | prm.m_collisionCategories |= CollisionCategories.Body; | ||
1098 | prm.m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind); | ||
1099 | |||
1100 | if (prm.prim_geom == IntPtr.Zero) | ||
1101 | { | ||
1102 | m_log.Warn("[PHYSICS]: Unable to link one of the linkset elements. No geom yet"); | ||
1103 | continue; | ||
1104 | } | ||
1105 | //Console.WriteLine(" GeomSetCategoryBits 1: " + prm.prim_geom + " - " + (int)prm.m_collisionCategories + " for " + m_primName); | ||
1106 | d.GeomSetCategoryBits(prm.prim_geom, (int)prm.m_collisionCategories); | ||
1107 | d.GeomSetCollideBits(prm.prim_geom, (int)prm.m_collisionFlags); | ||
1108 | |||
1109 | |||
1110 | d.Quaternion quat = new d.Quaternion(); | ||
1111 | quat.W = prm._orientation.W; | ||
1112 | quat.X = prm._orientation.X; | ||
1113 | quat.Y = prm._orientation.Y; | ||
1114 | quat.Z = prm._orientation.Z; | ||
1115 | |||
1116 | d.Matrix3 mat = new d.Matrix3(); | ||
1117 | d.RfromQ(out mat, ref quat); | ||
1118 | if (Body != IntPtr.Zero) | ||
1119 | { | ||
1120 | d.GeomSetBody(prm.prim_geom, Body); | ||
1121 | prm.childPrim = true; | ||
1122 | d.GeomSetOffsetWorldPosition(prm.prim_geom, prm.Position.X , prm.Position.Y, prm.Position.Z); | ||
1123 | //d.GeomSetOffsetPosition(prim.prim_geom, | ||
1124 | // (Position.X - prm.Position.X) - pMass.c.X, | ||
1125 | // (Position.Y - prm.Position.Y) - pMass.c.Y, | ||
1126 | // (Position.Z - prm.Position.Z) - pMass.c.Z); | ||
1127 | d.GeomSetOffsetWorldRotation(prm.prim_geom, ref mat); | ||
1128 | //d.GeomSetOffsetRotation(prm.prim_geom, ref mat); | ||
1129 | d.MassTranslate(ref pMass, -pMass.c.X, -pMass.c.Y, -pMass.c.Z); | ||
1130 | d.BodySetMass(Body, ref pMass); | ||
1131 | } | ||
1132 | else | ||
1133 | { | ||
1134 | m_log.Debug("[PHYSICS]:I ain't got no boooooooooddy, no body"); | ||
1135 | } | ||
1136 | |||
1137 | |||
1138 | prm.m_interpenetrationcount = 0; | ||
1139 | prm.m_collisionscore = 0; | ||
1140 | prm.m_disabled = false; | ||
1141 | |||
1142 | // The body doesn't already have a finite rotation mode set here | ||
1143 | if ((!m_angularlock.ApproxEquals(Vector3.Zero, 0f)) && _parent == null) | ||
1144 | { | ||
1145 | prm.createAMotor(m_angularlock); | ||
1146 | } | ||
1147 | prm.Body = Body; | ||
1148 | _parent_scene.addActivePrim(prm); | ||
1149 | } | ||
1150 | m_collisionCategories |= CollisionCategories.Body; | ||
1151 | m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind); | ||
1152 | |||
1153 | //Console.WriteLine("GeomSetCategoryBits 2: " + prim_geom + " - " + (int)m_collisionCategories + " for " + m_primName); | ||
1154 | d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); | ||
1155 | //Console.WriteLine(" Post GeomSetCategoryBits 2"); | ||
1156 | d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); | ||
1157 | |||
1158 | |||
1159 | d.Quaternion quat2 = new d.Quaternion(); | ||
1160 | quat2.W = _orientation.W; | ||
1161 | quat2.X = _orientation.X; | ||
1162 | quat2.Y = _orientation.Y; | ||
1163 | quat2.Z = _orientation.Z; | ||
1164 | |||
1165 | d.Matrix3 mat2 = new d.Matrix3(); | ||
1166 | d.RfromQ(out mat2, ref quat2); | ||
1167 | d.GeomSetBody(prim_geom, Body); | ||
1168 | d.GeomSetOffsetWorldPosition(prim_geom, Position.X - pMass.c.X, Position.Y - pMass.c.Y, Position.Z - pMass.c.Z); | ||
1169 | //d.GeomSetOffsetPosition(prim.prim_geom, | ||
1170 | // (Position.X - prm.Position.X) - pMass.c.X, | ||
1171 | // (Position.Y - prm.Position.Y) - pMass.c.Y, | ||
1172 | // (Position.Z - prm.Position.Z) - pMass.c.Z); | ||
1173 | //d.GeomSetOffsetRotation(prim_geom, ref mat2); | ||
1174 | d.MassTranslate(ref pMass, -pMass.c.X, -pMass.c.Y, -pMass.c.Z); | ||
1175 | d.BodySetMass(Body, ref pMass); | ||
1176 | |||
1177 | d.BodySetAutoDisableFlag(Body, true); | ||
1178 | d.BodySetAutoDisableSteps(Body, body_autodisable_frames); | ||
1179 | |||
1180 | |||
1181 | m_interpenetrationcount = 0; | ||
1182 | m_collisionscore = 0; | ||
1183 | m_disabled = false; | ||
1184 | |||
1185 | // The body doesn't already have a finite rotation mode set here | ||
1186 | if ((!m_angularlock.ApproxEquals(Vector3.Zero, 0f)) && _parent == null) | ||
1187 | { | ||
1188 | createAMotor(m_angularlock); | ||
1189 | } | ||
1190 | d.BodySetPosition(Body, Position.X, Position.Y, Position.Z); | ||
1191 | if (m_vehicle.Type != Vehicle.TYPE_NONE) m_vehicle.Enable(Body, _parent_scene); | ||
1192 | _parent_scene.addActivePrim(this); | ||
1193 | } | ||
1194 | } | ||
1195 | } | ||
1196 | } | ||
1197 | |||
1198 | } | ||
1199 | |||
1200 | private void ChildSetGeom(OdePrim odePrim) | ||
1201 | { | ||
1202 | //if (m_isphysical && Body != IntPtr.Zero) | ||
1203 | lock (childrenPrim) | ||
1204 | { | ||
1205 | foreach (OdePrim prm in childrenPrim) | ||
1206 | { | ||
1207 | //prm.childPrim = true; | ||
1208 | prm.disableBody(); | ||
1209 | //prm.m_taintparent = null; | ||
1210 | //prm._parent = null; | ||
1211 | //prm.m_taintPhysics = false; | ||
1212 | //prm.m_disabled = true; | ||
1213 | //prm.childPrim = false; | ||
1214 | } | ||
1215 | } | ||
1216 | disableBody(); | ||
1217 | |||
1218 | |||
1219 | if (Body != IntPtr.Zero) | ||
1220 | { | ||
1221 | _parent_scene.remActivePrim(this); | ||
1222 | } | ||
1223 | |||
1224 | lock (childrenPrim) | ||
1225 | { | ||
1226 | foreach (OdePrim prm in childrenPrim) | ||
1227 | { | ||
1228 | //Console.WriteLine("ChildSetGeom calls ParentPrim"); | ||
1229 | ParentPrim(prm); | ||
1230 | } | ||
1231 | } | ||
1232 | |||
1233 | } | ||
1234 | |||
1235 | private void ChildDelink(OdePrim odePrim) | ||
1236 | { | ||
1237 | // Okay, we have a delinked child.. need to rebuild the body. | ||
1238 | lock (childrenPrim) | ||
1239 | { | ||
1240 | foreach (OdePrim prm in childrenPrim) | ||
1241 | { | ||
1242 | prm.childPrim = true; | ||
1243 | prm.disableBody(); | ||
1244 | //prm.m_taintparent = null; | ||
1245 | //prm._parent = null; | ||
1246 | //prm.m_taintPhysics = false; | ||
1247 | //prm.m_disabled = true; | ||
1248 | //prm.childPrim = false; | ||
1249 | } | ||
1250 | } | ||
1251 | disableBody(); | ||
1252 | |||
1253 | lock (childrenPrim) | ||
1254 | { | ||
1255 | //Console.WriteLine("childrenPrim.Remove " + odePrim); | ||
1256 | childrenPrim.Remove(odePrim); | ||
1257 | } | ||
1258 | |||
1259 | |||
1260 | |||
1261 | |||
1262 | if (Body != IntPtr.Zero) | ||
1263 | { | ||
1264 | _parent_scene.remActivePrim(this); | ||
1265 | } | ||
1266 | |||
1267 | |||
1268 | |||
1269 | lock (childrenPrim) | ||
1270 | { | ||
1271 | foreach (OdePrim prm in childrenPrim) | ||
1272 | { | ||
1273 | //Console.WriteLine("ChildDelink calls ParentPrim"); | ||
1274 | ParentPrim(prm); | ||
1275 | } | ||
1276 | } | ||
1277 | |||
1278 | |||
1279 | } | ||
1280 | |||
1281 | private void changeSelectedStatus(float timestep) | ||
1282 | { | ||
1283 | if (m_taintselected) | ||
1284 | { | ||
1285 | m_collisionCategories = CollisionCategories.Selected; | ||
1286 | m_collisionFlags = (CollisionCategories.Sensor | CollisionCategories.Space); | ||
1287 | |||
1288 | // We do the body disable soft twice because 'in theory' a collision could have happened | ||
1289 | // in between the disabling and the collision properties setting | ||
1290 | // which would wake the physical body up from a soft disabling and potentially cause it to fall | ||
1291 | // through the ground. | ||
1292 | |||
1293 | // NOTE FOR JOINTS: this doesn't always work for jointed assemblies because if you select | ||
1294 | // just one part of the assembly, the rest of the assembly is non-selected and still simulating, | ||
1295 | // so that causes the selected part to wake up and continue moving. | ||
1296 | |||
1297 | // even if you select all parts of a jointed assembly, it is not guaranteed that the entire | ||
1298 | // assembly will stop simulating during the selection, because of the lack of atomicity | ||
1299 | // of select operations (their processing could be interrupted by a thread switch, causing | ||
1300 | // simulation to continue before all of the selected object notifications trickle down to | ||
1301 | // the physics engine). | ||
1302 | |||
1303 | // e.g. we select 100 prims that are connected by joints. non-atomically, the first 50 are | ||
1304 | // selected and disabled. then, due to a thread switch, the selection processing is | ||
1305 | // interrupted and the physics engine continues to simulate, so the last 50 items, whose | ||
1306 | // selection was not yet processed, continues to simulate. this wakes up ALL of the | ||
1307 | // first 50 again. then the last 50 are disabled. then the first 50, which were just woken | ||
1308 | // up, start simulating again, which in turn wakes up the last 50. | ||
1309 | |||
1310 | if (m_isphysical) | ||
1311 | { | ||
1312 | disableBodySoft(); | ||
1313 | } | ||
1314 | |||
1315 | if (prim_geom != IntPtr.Zero) | ||
1316 | { | ||
1317 | d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); | ||
1318 | d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); | ||
1319 | } | ||
1320 | |||
1321 | if (m_isphysical) | ||
1322 | { | ||
1323 | disableBodySoft(); | ||
1324 | } | ||
1325 | } | ||
1326 | else | ||
1327 | { | ||
1328 | m_collisionCategories = CollisionCategories.Geom; | ||
1329 | |||
1330 | if (m_isphysical) | ||
1331 | m_collisionCategories |= CollisionCategories.Body; | ||
1332 | |||
1333 | m_collisionFlags = m_default_collisionFlags; | ||
1334 | |||
1335 | if (m_collidesLand) | ||
1336 | m_collisionFlags |= CollisionCategories.Land; | ||
1337 | if (m_collidesWater) | ||
1338 | m_collisionFlags |= CollisionCategories.Water; | ||
1339 | |||
1340 | if (prim_geom != IntPtr.Zero) | ||
1341 | { | ||
1342 | d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); | ||
1343 | d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); | ||
1344 | } | ||
1345 | if (m_isphysical) | ||
1346 | { | ||
1347 | if (Body != IntPtr.Zero) | ||
1348 | { | ||
1349 | d.BodySetLinearVel(Body, 0f, 0f, 0f); | ||
1350 | d.BodySetForce(Body, 0, 0, 0); | ||
1351 | enableBodySoft(); | ||
1352 | } | ||
1353 | } | ||
1354 | } | ||
1355 | |||
1356 | resetCollisionAccounting(); | ||
1357 | m_isSelected = m_taintselected; | ||
1358 | }//end changeSelectedStatus | ||
1359 | |||
1360 | public void ResetTaints() | ||
1361 | { | ||
1362 | m_taintposition = _position; | ||
1363 | m_taintrot = _orientation; | ||
1364 | m_taintPhysics = m_isphysical; | ||
1365 | m_taintselected = m_isSelected; | ||
1366 | m_taintsize = _size; | ||
1367 | m_taintshape = false; | ||
1368 | m_taintforce = false; | ||
1369 | m_taintdisable = false; | ||
1370 | m_taintVelocity = Vector3.Zero; | ||
1371 | } | ||
1372 | |||
1373 | public void CreateGeom(IntPtr m_targetSpace, IMesh _mesh) | ||
1374 | { | ||
1375 | //Console.WriteLine("CreateGeom:"); | ||
1376 | if (_mesh != null) | ||
1377 | { | ||
1378 | setMesh(_parent_scene, _mesh); | ||
1379 | } | ||
1380 | else | ||
1381 | { | ||
1382 | if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1) | ||
1383 | { | ||
1384 | if (_size.X == _size.Y && _size.Y == _size.Z && _size.X == _size.Z) | ||
1385 | { | ||
1386 | if (((_size.X / 2f) > 0f)) | ||
1387 | { | ||
1388 | _parent_scene.waitForSpaceUnlock(m_targetSpace); | ||
1389 | try | ||
1390 | { | ||
1391 | //Console.WriteLine(" CreateGeom 1"); | ||
1392 | SetGeom(d.CreateSphere(m_targetSpace, _size.X / 2)); | ||
1393 | } | ||
1394 | catch (AccessViolationException) | ||
1395 | { | ||
1396 | m_log.Warn("[PHYSICS]: Unable to create physics proxy for object"); | ||
1397 | ode.dunlock(_parent_scene.world); | ||
1398 | return; | ||
1399 | } | ||
1400 | } | ||
1401 | else | ||
1402 | { | ||
1403 | _parent_scene.waitForSpaceUnlock(m_targetSpace); | ||
1404 | try | ||
1405 | { | ||
1406 | //Console.WriteLine(" CreateGeom 2"); | ||
1407 | SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z)); | ||
1408 | } | ||
1409 | catch (AccessViolationException) | ||
1410 | { | ||
1411 | m_log.Warn("[PHYSICS]: Unable to create physics proxy for object"); | ||
1412 | ode.dunlock(_parent_scene.world); | ||
1413 | return; | ||
1414 | } | ||
1415 | } | ||
1416 | } | ||
1417 | else | ||
1418 | { | ||
1419 | _parent_scene.waitForSpaceUnlock(m_targetSpace); | ||
1420 | try | ||
1421 | { | ||
1422 | //Console.WriteLine(" CreateGeom 3"); | ||
1423 | SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z)); | ||
1424 | } | ||
1425 | catch (AccessViolationException) | ||
1426 | { | ||
1427 | m_log.Warn("[PHYSICS]: Unable to create physics proxy for object"); | ||
1428 | ode.dunlock(_parent_scene.world); | ||
1429 | return; | ||
1430 | } | ||
1431 | } | ||
1432 | } | ||
1433 | |||
1434 | else | ||
1435 | { | ||
1436 | _parent_scene.waitForSpaceUnlock(m_targetSpace); | ||
1437 | try | ||
1438 | { | ||
1439 | //Console.WriteLine(" CreateGeom 4"); | ||
1440 | SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z)); | ||
1441 | } | ||
1442 | catch (AccessViolationException) | ||
1443 | { | ||
1444 | m_log.Warn("[PHYSICS]: Unable to create physics proxy for object"); | ||
1445 | ode.dunlock(_parent_scene.world); | ||
1446 | return; | ||
1447 | } | ||
1448 | } | ||
1449 | } | ||
1450 | } | ||
1451 | |||
1452 | public void changeadd(float timestep) | ||
1453 | { | ||
1454 | int[] iprimspaceArrItem = _parent_scene.calculateSpaceArrayItemFromPos(_position); | ||
1455 | IntPtr targetspace = _parent_scene.calculateSpaceForGeom(_position); | ||
1456 | |||
1457 | if (targetspace == IntPtr.Zero) | ||
1458 | targetspace = _parent_scene.createprimspace(iprimspaceArrItem[0], iprimspaceArrItem[1]); | ||
1459 | |||
1460 | m_targetSpace = targetspace; | ||
1461 | |||
1462 | if (_mesh == null) | ||
1463 | { | ||
1464 | if (_parent_scene.needsMeshing(_pbs)) | ||
1465 | { | ||
1466 | // Don't need to re-enable body.. it's done in SetMesh | ||
1467 | _mesh = _parent_scene.mesher.CreateMesh(m_primName, _pbs, _size, _parent_scene.meshSculptLOD, IsPhysical); | ||
1468 | // createmesh returns null when it's a shape that isn't a cube. | ||
1469 | // m_log.Debug(m_localID); | ||
1470 | } | ||
1471 | } | ||
1472 | |||
1473 | |||
1474 | lock (_parent_scene.OdeLock) | ||
1475 | { | ||
1476 | //Console.WriteLine("changeadd 1"); | ||
1477 | CreateGeom(m_targetSpace, _mesh); | ||
1478 | |||
1479 | if (prim_geom != IntPtr.Zero) | ||
1480 | { | ||
1481 | d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z); | ||
1482 | d.Quaternion myrot = new d.Quaternion(); | ||
1483 | myrot.X = _orientation.X; | ||
1484 | myrot.Y = _orientation.Y; | ||
1485 | myrot.Z = _orientation.Z; | ||
1486 | myrot.W = _orientation.W; | ||
1487 | d.GeomSetQuaternion(prim_geom, ref myrot); | ||
1488 | } | ||
1489 | |||
1490 | if (m_isphysical && Body == IntPtr.Zero) | ||
1491 | { | ||
1492 | enableBody(); | ||
1493 | } | ||
1494 | } | ||
1495 | |||
1496 | _parent_scene.geom_name_map[prim_geom] = this.m_primName; | ||
1497 | _parent_scene.actor_name_map[prim_geom] = (PhysicsActor)this; | ||
1498 | |||
1499 | changeSelectedStatus(timestep); | ||
1500 | |||
1501 | m_taintadd = false; | ||
1502 | } | ||
1503 | |||
1504 | public void changemove(float timestep) | ||
1505 | { | ||
1506 | if (m_isphysical) | ||
1507 | { | ||
1508 | |||
1509 | if (!m_disabled && !m_taintremove && !childPrim) | ||
1510 | { | ||
1511 | if (Body == IntPtr.Zero) | ||
1512 | enableBody(); | ||
1513 | //Prim auto disable after 20 frames, | ||
1514 | //if you move it, re-enable the prim manually. | ||
1515 | if (_parent != null) | ||
1516 | { | ||
1517 | if (m_linkJoint != IntPtr.Zero) | ||
1518 | { | ||
1519 | d.JointDestroy(m_linkJoint); | ||
1520 | m_linkJoint = IntPtr.Zero; | ||
1521 | } | ||
1522 | } | ||
1523 | if (Body != IntPtr.Zero) | ||
1524 | { | ||
1525 | d.BodySetPosition(Body, _position.X, _position.Y, _position.Z); | ||
1526 | |||
1527 | if (_parent != null) | ||
1528 | { | ||
1529 | OdePrim odParent = (OdePrim)_parent; | ||
1530 | if (Body != (IntPtr)0 && odParent.Body != (IntPtr)0 && Body != odParent.Body) | ||
1531 | { | ||
1532 | // KF: Fixed Joints were removed? Anyway - this Console.WriteLine does not show up, so routine is not used?? | ||
1533 | Console.WriteLine(" JointCreateFixed"); | ||
1534 | m_linkJoint = d.JointCreateFixed(_parent_scene.world, _linkJointGroup); | ||
1535 | d.JointAttach(m_linkJoint, Body, odParent.Body); | ||
1536 | d.JointSetFixed(m_linkJoint); | ||
1537 | } | ||
1538 | } | ||
1539 | d.BodyEnable(Body); | ||
1540 | if (m_vehicle.Type != Vehicle.TYPE_NONE) | ||
1541 | { | ||
1542 | m_vehicle.Enable(Body, _parent_scene); | ||
1543 | } | ||
1544 | } | ||
1545 | else | ||
1546 | { | ||
1547 | m_log.Warn("[PHYSICS]: Body Still null after enableBody(). This is a crash scenario."); | ||
1548 | } | ||
1549 | } | ||
1550 | //else | ||
1551 | // { | ||
1552 | //m_log.Debug("[BUG]: race!"); | ||
1553 | //} | ||
1554 | } | ||
1555 | else | ||
1556 | { | ||
1557 | // string primScenAvatarIn = _parent_scene.whichspaceamIin(_position); | ||
1558 | // int[] arrayitem = _parent_scene.calculateSpaceArrayItemFromPos(_position); | ||
1559 | _parent_scene.waitForSpaceUnlock(m_targetSpace); | ||
1560 | |||
1561 | IntPtr tempspace = _parent_scene.recalculateSpaceForGeom(prim_geom, _position, m_targetSpace); | ||
1562 | m_targetSpace = tempspace; | ||
1563 | |||
1564 | _parent_scene.waitForSpaceUnlock(m_targetSpace); | ||
1565 | if (prim_geom != IntPtr.Zero) | ||
1566 | { | ||
1567 | d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z); | ||
1568 | |||
1569 | _parent_scene.waitForSpaceUnlock(m_targetSpace); | ||
1570 | d.SpaceAdd(m_targetSpace, prim_geom); | ||
1571 | } | ||
1572 | } | ||
1573 | |||
1574 | changeSelectedStatus(timestep); | ||
1575 | |||
1576 | resetCollisionAccounting(); | ||
1577 | m_taintposition = _position; | ||
1578 | } | ||
1579 | |||
1580 | public void Move(float timestep) | ||
1581 | { | ||
1582 | float fx = 0; | ||
1583 | float fy = 0; | ||
1584 | float fz = 0; | ||
1585 | |||
1586 | frcount++; // used to limit debug comment output | ||
1587 | if (frcount > 100) | ||
1588 | frcount = 0; | ||
1589 | |||
1590 | if (IsPhysical && (Body != IntPtr.Zero) && !m_isSelected && !childPrim) // KF: Only move root prims. | ||
1591 | { | ||
1592 | //if(frcount == 0) Console.WriteLine("Move " + m_primName + " VTyp " + m_vehicle.Type + | ||
1593 | // " usePID=" + m_usePID + " seHover=" + m_useHoverPID + " useAPID=" + m_useAPID); | ||
1594 | if (m_vehicle.Type != Vehicle.TYPE_NONE) | ||
1595 | { | ||
1596 | // 'VEHICLES' are dealt with in ODEDynamics.cs | ||
1597 | m_vehicle.Step(timestep, _parent_scene); | ||
1598 | } | ||
1599 | else | ||
1600 | { | ||
1601 | if(!d.BodyIsEnabled (Body)) d.BodyEnable (Body); // KF add 161009 | ||
1602 | // NON-'VEHICLES' are dealt with here | ||
1603 | if (d.BodyIsEnabled(Body) && !m_angularlock.ApproxEquals(Vector3.Zero, 0.003f)) | ||
1604 | { | ||
1605 | d.Vector3 avel2 = d.BodyGetAngularVel(Body); | ||
1606 | if (m_angularlock.X == 1) | ||
1607 | avel2.X = 0; | ||
1608 | if (m_angularlock.Y == 1) | ||
1609 | avel2.Y = 0; | ||
1610 | if (m_angularlock.Z == 1) | ||
1611 | avel2.Z = 0; | ||
1612 | d.BodySetAngularVel(Body, avel2.X, avel2.Y, avel2.Z); | ||
1613 | } | ||
1614 | //float PID_P = 900.0f; | ||
1615 | |||
1616 | float m_mass = CalculateMass(); | ||
1617 | |||
1618 | // fz = 0f; | ||
1619 | //m_log.Info(m_collisionFlags.ToString()); | ||
1620 | |||
1621 | |||
1622 | //KF: m_buoyancy is set by llSetBuoyancy() and is for non-vehicle. | ||
1623 | // m_buoyancy: (unlimited value) <0=Falls fast; 0=1g; 1=0g; >1 = floats up | ||
1624 | // NB Prims in ODE are no subject to global gravity | ||
1625 | fz = _parent_scene.gravityz * (1.0f - m_buoyancy) * m_mass; // force = acceleration * mass | ||
1626 | |||
1627 | if (m_usePID) | ||
1628 | { | ||
1629 | //if(frcount == 0) Console.WriteLine("PID " + m_primName); | ||
1630 | // KF - this is for object MoveToTarget. | ||
1631 | |||
1632 | //if (!d.BodyIsEnabled(Body)) | ||
1633 | //d.BodySetForce(Body, 0f, 0f, 0f); | ||
1634 | |||
1635 | // no lock; for now it's only called from within Simulate() | ||
1636 | |||
1637 | // If the PID Controller isn't active then we set our force | ||
1638 | // calculating base velocity to the current position | ||
1639 | |||
1640 | if ((m_PIDTau < 1) && (m_PIDTau != 0)) | ||
1641 | { | ||
1642 | //PID_G = PID_G / m_PIDTau; | ||
1643 | m_PIDTau = 1; | ||
1644 | } | ||
1645 | |||
1646 | if ((PID_G - m_PIDTau) <= 0) | ||
1647 | { | ||
1648 | PID_G = m_PIDTau + 1; | ||
1649 | } | ||
1650 | //PidStatus = true; | ||
1651 | |||
1652 | // PhysicsVector vec = new PhysicsVector(); | ||
1653 | d.Vector3 vel = d.BodyGetLinearVel(Body); | ||
1654 | |||
1655 | d.Vector3 pos = d.BodyGetPosition(Body); | ||
1656 | _target_velocity = | ||
1657 | new Vector3( | ||
1658 | (m_PIDTarget.X - pos.X) * ((PID_G - m_PIDTau) * timestep), | ||
1659 | (m_PIDTarget.Y - pos.Y) * ((PID_G - m_PIDTau) * timestep), | ||
1660 | (m_PIDTarget.Z - pos.Z) * ((PID_G - m_PIDTau) * timestep) | ||
1661 | ); | ||
1662 | |||
1663 | // if velocity is zero, use position control; otherwise, velocity control | ||
1664 | |||
1665 | if (_target_velocity.ApproxEquals(Vector3.Zero,0.1f)) | ||
1666 | { | ||
1667 | // keep track of where we stopped. No more slippin' & slidin' | ||
1668 | |||
1669 | // We only want to deactivate the PID Controller if we think we want to have our surrogate | ||
1670 | // react to the physics scene by moving it's position. | ||
1671 | // Avatar to Avatar collisions | ||
1672 | // Prim to avatar collisions | ||
1673 | |||
1674 | //fx = (_target_velocity.X - vel.X) * (PID_D) + (_zeroPosition.X - pos.X) * (PID_P * 2); | ||
1675 | //fy = (_target_velocity.Y - vel.Y) * (PID_D) + (_zeroPosition.Y - pos.Y) * (PID_P * 2); | ||
1676 | //fz = fz + (_target_velocity.Z - vel.Z) * (PID_D) + (_zeroPosition.Z - pos.Z) * PID_P; | ||
1677 | d.BodySetPosition(Body, m_PIDTarget.X, m_PIDTarget.Y, m_PIDTarget.Z); | ||
1678 | d.BodySetLinearVel(Body, 0, 0, 0); | ||
1679 | d.BodyAddForce(Body, 0, 0, fz); | ||
1680 | return; | ||
1681 | } | ||
1682 | else | ||
1683 | { | ||
1684 | _zeroFlag = false; | ||
1685 | |||
1686 | // We're flying and colliding with something | ||
1687 | fx = ((_target_velocity.X) - vel.X) * (PID_D); | ||
1688 | fy = ((_target_velocity.Y) - vel.Y) * (PID_D); | ||
1689 | |||
1690 | // vec.Z = (_target_velocity.Z - vel.Z) * PID_D + (_zeroPosition.Z - pos.Z) * PID_P; | ||
1691 | |||
1692 | fz = fz + ((_target_velocity.Z - vel.Z) * (PID_D) * m_mass); | ||
1693 | } | ||
1694 | } // end if (m_usePID) | ||
1695 | |||
1696 | // Hover PID Controller needs to be mutually exlusive to MoveTo PID controller | ||
1697 | if (m_useHoverPID && !m_usePID) | ||
1698 | { | ||
1699 | //Console.WriteLine("Hover " + m_primName); | ||
1700 | |||
1701 | // If we're using the PID controller, then we have no gravity | ||
1702 | fz = (-1 * _parent_scene.gravityz) * m_mass; | ||
1703 | |||
1704 | // no lock; for now it's only called from within Simulate() | ||
1705 | |||
1706 | // If the PID Controller isn't active then we set our force | ||
1707 | // calculating base velocity to the current position | ||
1708 | |||
1709 | if ((m_PIDTau < 1)) | ||
1710 | { | ||
1711 | PID_G = PID_G / m_PIDTau; | ||
1712 | } | ||
1713 | |||
1714 | if ((PID_G - m_PIDTau) <= 0) | ||
1715 | { | ||
1716 | PID_G = m_PIDTau + 1; | ||
1717 | } | ||
1718 | |||
1719 | |||
1720 | // Where are we, and where are we headed? | ||
1721 | d.Vector3 pos = d.BodyGetPosition(Body); | ||
1722 | d.Vector3 vel = d.BodyGetLinearVel(Body); | ||
1723 | |||
1724 | |||
1725 | // Non-Vehicles have a limited set of Hover options. | ||
1726 | // determine what our target height really is based on HoverType | ||
1727 | switch (m_PIDHoverType) | ||
1728 | { | ||
1729 | case PIDHoverType.Ground: | ||
1730 | m_groundHeight = _parent_scene.GetTerrainHeightAtXY(pos.X, pos.Y); | ||
1731 | m_targetHoverHeight = m_groundHeight + m_PIDHoverHeight; | ||
1732 | break; | ||
1733 | case PIDHoverType.GroundAndWater: | ||
1734 | m_groundHeight = _parent_scene.GetTerrainHeightAtXY(pos.X, pos.Y); | ||
1735 | m_waterHeight = _parent_scene.GetWaterLevel(); | ||
1736 | if (m_groundHeight > m_waterHeight) | ||
1737 | { | ||
1738 | m_targetHoverHeight = m_groundHeight + m_PIDHoverHeight; | ||
1739 | } | ||
1740 | else | ||
1741 | { | ||
1742 | m_targetHoverHeight = m_waterHeight + m_PIDHoverHeight; | ||
1743 | } | ||
1744 | break; | ||
1745 | |||
1746 | } // end switch (m_PIDHoverType) | ||
1747 | |||
1748 | |||
1749 | _target_velocity = | ||
1750 | new Vector3(0.0f, 0.0f, | ||
1751 | (m_targetHoverHeight - pos.Z) * ((PID_G - m_PIDHoverTau) * timestep) | ||
1752 | ); | ||
1753 | |||
1754 | // if velocity is zero, use position control; otherwise, velocity control | ||
1755 | |||
1756 | if (_target_velocity.ApproxEquals(Vector3.Zero, 0.1f)) | ||
1757 | { | ||
1758 | // keep track of where we stopped. No more slippin' & slidin' | ||
1759 | |||
1760 | // We only want to deactivate the PID Controller if we think we want to have our surrogate | ||
1761 | // react to the physics scene by moving it's position. | ||
1762 | // Avatar to Avatar collisions | ||
1763 | // Prim to avatar collisions | ||
1764 | |||
1765 | d.BodySetPosition(Body, pos.X, pos.Y, m_targetHoverHeight); | ||
1766 | d.BodySetLinearVel(Body, vel.X, vel.Y, 0); | ||
1767 | d.BodyAddForce(Body, 0, 0, fz); | ||
1768 | //KF this prevents furthur motions return; | ||
1769 | } | ||
1770 | else | ||
1771 | { | ||
1772 | _zeroFlag = false; | ||
1773 | |||
1774 | // We're flying and colliding with something | ||
1775 | fz = fz + ((_target_velocity.Z - vel.Z) * (PID_D) * m_mass); | ||
1776 | } | ||
1777 | } // end m_useHoverPID && !m_usePID | ||
1778 | |||
1779 | if (m_useAPID) | ||
1780 | { | ||
1781 | // RotLookAt, apparently overrides all other rotation sources. Inputs: | ||
1782 | // Quaternion m_APIDTarget | ||
1783 | // float m_APIDStrength // From SL experiments, this is the time to get there | ||
1784 | // float m_APIDDamping // From SL experiments, this is damping, 1.0 = damped, 0.1 = wobbly | ||
1785 | // Also in SL the mass of the object has no effect on time to get there. | ||
1786 | // Factors: | ||
1787 | //if(frcount == 0) Console.WriteLine("APID "); | ||
1788 | // get present body rotation | ||
1789 | float limit = 1.0f; | ||
1790 | float scaler = 50f; // adjusts damping time | ||
1791 | float RLAservo = 0f; | ||
1792 | |||
1793 | d.Quaternion rot = d.BodyGetQuaternion(Body); | ||
1794 | Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); | ||
1795 | Quaternion rot_diff = Quaternion.Inverse(rotq) * m_APIDTarget; | ||
1796 | float diff_angle; | ||
1797 | Vector3 diff_axis; | ||
1798 | rot_diff.GetAxisAngle(out diff_axis, out diff_angle); | ||
1799 | diff_axis.Normalize(); | ||
1800 | if(diff_angle > 0.01f) // diff_angle is always +ve | ||
1801 | { | ||
1802 | // PhysicsVector rotforce = new PhysicsVector(diff_axis.X, diff_axis.Y, diff_axis.Z); | ||
1803 | Vector3 rotforce = new Vector3(diff_axis.X, diff_axis.Y, diff_axis.Z); | ||
1804 | rotforce = rotforce * rotq; | ||
1805 | if(diff_angle > limit) diff_angle = limit; // cap the rotate rate | ||
1806 | // RLAservo = timestep / m_APIDStrength * m_mass * scaler; | ||
1807 | // rotforce = rotforce * RLAservo * diff_angle ; | ||
1808 | // d.BodyAddRelTorque(Body, rotforce.X, rotforce.Y, rotforce.Z); | ||
1809 | RLAservo = timestep / m_APIDStrength * scaler; | ||
1810 | rotforce = rotforce * RLAservo * diff_angle ; | ||
1811 | d.BodySetAngularVel (Body, rotforce.X, rotforce.Y, rotforce.Z); | ||
1812 | //Console.WriteLine("axis= " + diff_axis + " angle= " + diff_angle + "servo= " + RLAservo); | ||
1813 | } | ||
1814 | //if(frcount == 0) Console.WriteLine("mass= " + m_mass + " servo= " + RLAservo + " angle= " + diff_angle); | ||
1815 | } // end m_useAPID | ||
1816 | |||
1817 | fx *= m_mass; | ||
1818 | fy *= m_mass; | ||
1819 | //fz *= m_mass; | ||
1820 | |||
1821 | fx += m_force.X; | ||
1822 | fy += m_force.Y; | ||
1823 | fz += m_force.Z; | ||
1824 | |||
1825 | //m_log.Info("[OBJPID]: X:" + fx.ToString() + " Y:" + fy.ToString() + " Z:" + fz.ToString()); | ||
1826 | if (fx != 0 || fy != 0 || fz != 0) | ||
1827 | { | ||
1828 | //m_taintdisable = true; | ||
1829 | //base.RaiseOutOfBounds(Position); | ||
1830 | //d.BodySetLinearVel(Body, fx, fy, 0f); | ||
1831 | if (!d.BodyIsEnabled(Body)) | ||
1832 | { | ||
1833 | // A physical body at rest on a surface will auto-disable after a while, | ||
1834 | // this appears to re-enable it incase the surface it is upon vanishes, | ||
1835 | // and the body should fall again. | ||
1836 | d.BodySetLinearVel(Body, 0f, 0f, 0f); | ||
1837 | d.BodySetForce(Body, 0, 0, 0); | ||
1838 | enableBodySoft(); | ||
1839 | } | ||
1840 | |||
1841 | // 35x10 = 350n times the mass per second applied maximum. | ||
1842 | float nmax = 35f * m_mass; | ||
1843 | float nmin = -35f * m_mass; | ||
1844 | |||
1845 | |||
1846 | if (fx > nmax) | ||
1847 | fx = nmax; | ||
1848 | if (fx < nmin) | ||
1849 | fx = nmin; | ||
1850 | if (fy > nmax) | ||
1851 | fy = nmax; | ||
1852 | if (fy < nmin) | ||
1853 | fy = nmin; | ||
1854 | d.BodyAddForce(Body, fx, fy, fz); | ||
1855 | //Console.WriteLine("AddForce " + fx + "," + fy + "," + fz); | ||
1856 | } | ||
1857 | } | ||
1858 | } | ||
1859 | else | ||
1860 | { // is not physical, or is not a body or is selected | ||
1861 | // _zeroPosition = d.BodyGetPosition(Body); | ||
1862 | return; | ||
1863 | //Console.WriteLine("Nothing " + m_primName); | ||
1864 | |||
1865 | } | ||
1866 | } | ||
1867 | |||
1868 | |||
1869 | |||
1870 | public void rotate(float timestep) | ||
1871 | { | ||
1872 | d.Quaternion myrot = new d.Quaternion(); | ||
1873 | myrot.X = _orientation.X; | ||
1874 | myrot.Y = _orientation.Y; | ||
1875 | myrot.Z = _orientation.Z; | ||
1876 | myrot.W = _orientation.W; | ||
1877 | if (Body != IntPtr.Zero) | ||
1878 | { | ||
1879 | // KF: If this is a root prim do BodySet | ||
1880 | d.BodySetQuaternion(Body, ref myrot); | ||
1881 | if (m_isphysical) | ||
1882 | { | ||
1883 | if (!m_angularlock.ApproxEquals(Vector3.One, 0f)) | ||
1884 | createAMotor(m_angularlock); | ||
1885 | } | ||
1886 | } | ||
1887 | else | ||
1888 | { | ||
1889 | // daughter prim, do Geom set | ||
1890 | d.GeomSetQuaternion(prim_geom, ref myrot); | ||
1891 | } | ||
1892 | |||
1893 | resetCollisionAccounting(); | ||
1894 | m_taintrot = _orientation; | ||
1895 | } | ||
1896 | |||
1897 | private void resetCollisionAccounting() | ||
1898 | { | ||
1899 | m_collisionscore = 0; | ||
1900 | m_interpenetrationcount = 0; | ||
1901 | m_disabled = false; | ||
1902 | } | ||
1903 | |||
1904 | public void changedisable(float timestep) | ||
1905 | { | ||
1906 | m_disabled = true; | ||
1907 | if (Body != IntPtr.Zero) | ||
1908 | { | ||
1909 | d.BodyDisable(Body); | ||
1910 | Body = IntPtr.Zero; | ||
1911 | } | ||
1912 | |||
1913 | m_taintdisable = false; | ||
1914 | } | ||
1915 | |||
1916 | public void changePhysicsStatus(float timestep) | ||
1917 | { | ||
1918 | if (m_isphysical == true) | ||
1919 | { | ||
1920 | if (Body == IntPtr.Zero) | ||
1921 | { | ||
1922 | if (_pbs.SculptEntry && _parent_scene.meshSculptedPrim) | ||
1923 | { | ||
1924 | changeshape(2f); | ||
1925 | } | ||
1926 | else | ||
1927 | { | ||
1928 | enableBody(); | ||
1929 | } | ||
1930 | } | ||
1931 | } | ||
1932 | else | ||
1933 | { | ||
1934 | if (Body != IntPtr.Zero) | ||
1935 | { | ||
1936 | if (_pbs.SculptEntry && _parent_scene.meshSculptedPrim) | ||
1937 | { | ||
1938 | |||
1939 | |||
1940 | if (prim_geom != IntPtr.Zero) | ||
1941 | { | ||
1942 | try | ||
1943 | { | ||
1944 | d.GeomDestroy(prim_geom); | ||
1945 | prim_geom = IntPtr.Zero; | ||
1946 | _mesh = null; | ||
1947 | } | ||
1948 | catch (System.AccessViolationException) | ||
1949 | { | ||
1950 | prim_geom = IntPtr.Zero; | ||
1951 | m_log.Error("[PHYSICS]: PrimGeom dead"); | ||
1952 | } | ||
1953 | } | ||
1954 | //Console.WriteLine("changePhysicsStatus for " + m_primName ); | ||
1955 | changeadd(2f); | ||
1956 | } | ||
1957 | if (childPrim) | ||
1958 | { | ||
1959 | if (_parent != null) | ||
1960 | { | ||
1961 | OdePrim parent = (OdePrim)_parent; | ||
1962 | parent.ChildDelink(this); | ||
1963 | } | ||
1964 | } | ||
1965 | else | ||
1966 | { | ||
1967 | disableBody(); | ||
1968 | } | ||
1969 | } | ||
1970 | } | ||
1971 | |||
1972 | changeSelectedStatus(timestep); | ||
1973 | |||
1974 | resetCollisionAccounting(); | ||
1975 | m_taintPhysics = m_isphysical; | ||
1976 | } | ||
1977 | |||
1978 | public void changesize(float timestamp) | ||
1979 | { | ||
1980 | |||
1981 | string oldname = _parent_scene.geom_name_map[prim_geom]; | ||
1982 | |||
1983 | if (_size.X <= 0) _size.X = 0.01f; | ||
1984 | if (_size.Y <= 0) _size.Y = 0.01f; | ||
1985 | if (_size.Z <= 0) _size.Z = 0.01f; | ||
1986 | |||
1987 | // Cleanup of old prim geometry | ||
1988 | if (_mesh != null) | ||
1989 | { | ||
1990 | // Cleanup meshing here | ||
1991 | } | ||
1992 | //kill body to rebuild | ||
1993 | if (IsPhysical && Body != IntPtr.Zero) | ||
1994 | { | ||
1995 | if (childPrim) | ||
1996 | { | ||
1997 | if (_parent != null) | ||
1998 | { | ||
1999 | OdePrim parent = (OdePrim)_parent; | ||
2000 | parent.ChildDelink(this); | ||
2001 | } | ||
2002 | } | ||
2003 | else | ||
2004 | { | ||
2005 | disableBody(); | ||
2006 | } | ||
2007 | } | ||
2008 | if (d.SpaceQuery(m_targetSpace, prim_geom)) | ||
2009 | { | ||
2010 | _parent_scene.waitForSpaceUnlock(m_targetSpace); | ||
2011 | d.SpaceRemove(m_targetSpace, prim_geom); | ||
2012 | } | ||
2013 | d.GeomDestroy(prim_geom); | ||
2014 | prim_geom = IntPtr.Zero; | ||
2015 | // we don't need to do space calculation because the client sends a position update also. | ||
2016 | |||
2017 | // Construction of new prim | ||
2018 | if (_parent_scene.needsMeshing(_pbs)) | ||
2019 | { | ||
2020 | float meshlod = _parent_scene.meshSculptLOD; | ||
2021 | |||
2022 | if (IsPhysical) | ||
2023 | meshlod = _parent_scene.MeshSculptphysicalLOD; | ||
2024 | // Don't need to re-enable body.. it's done in SetMesh | ||
2025 | |||
2026 | IMesh mesh = null; | ||
2027 | |||
2028 | if (_parent_scene.needsMeshing(_pbs)) | ||
2029 | mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, meshlod, IsPhysical); | ||
2030 | |||
2031 | //IMesh mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, meshlod, IsPhysical); | ||
2032 | //Console.WriteLine("changesize 1"); | ||
2033 | CreateGeom(m_targetSpace, mesh); | ||
2034 | |||
2035 | |||
2036 | } | ||
2037 | else | ||
2038 | { | ||
2039 | _mesh = null; | ||
2040 | //Console.WriteLine("changesize 2"); | ||
2041 | CreateGeom(m_targetSpace, _mesh); | ||
2042 | } | ||
2043 | |||
2044 | d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z); | ||
2045 | d.Quaternion myrot = new d.Quaternion(); | ||
2046 | myrot.X = _orientation.X; | ||
2047 | myrot.Y = _orientation.Y; | ||
2048 | myrot.Z = _orientation.Z; | ||
2049 | myrot.W = _orientation.W; | ||
2050 | d.GeomSetQuaternion(prim_geom, ref myrot); | ||
2051 | |||
2052 | //d.GeomBoxSetLengths(prim_geom, _size.X, _size.Y, _size.Z); | ||
2053 | if (IsPhysical && Body == IntPtr.Zero && !childPrim) | ||
2054 | { | ||
2055 | // Re creates body on size. | ||
2056 | // EnableBody also does setMass() | ||
2057 | enableBody(); | ||
2058 | d.BodyEnable(Body); | ||
2059 | } | ||
2060 | |||
2061 | _parent_scene.geom_name_map[prim_geom] = oldname; | ||
2062 | |||
2063 | changeSelectedStatus(timestamp); | ||
2064 | if (childPrim) | ||
2065 | { | ||
2066 | if (_parent is OdePrim) | ||
2067 | { | ||
2068 | OdePrim parent = (OdePrim)_parent; | ||
2069 | parent.ChildSetGeom(this); | ||
2070 | } | ||
2071 | } | ||
2072 | resetCollisionAccounting(); | ||
2073 | m_taintsize = _size; | ||
2074 | } | ||
2075 | |||
2076 | |||
2077 | |||
2078 | public void changefloatonwater(float timestep) | ||
2079 | { | ||
2080 | m_collidesWater = m_taintCollidesWater; | ||
2081 | |||
2082 | if (prim_geom != IntPtr.Zero) | ||
2083 | { | ||
2084 | if (m_collidesWater) | ||
2085 | { | ||
2086 | m_collisionFlags |= CollisionCategories.Water; | ||
2087 | } | ||
2088 | else | ||
2089 | { | ||
2090 | m_collisionFlags &= ~CollisionCategories.Water; | ||
2091 | } | ||
2092 | d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); | ||
2093 | } | ||
2094 | } | ||
2095 | |||
2096 | public void changeshape(float timestamp) | ||
2097 | { | ||
2098 | string oldname = _parent_scene.geom_name_map[prim_geom]; | ||
2099 | |||
2100 | // Cleanup of old prim geometry and Bodies | ||
2101 | if (IsPhysical && Body != IntPtr.Zero) | ||
2102 | { | ||
2103 | if (childPrim) | ||
2104 | { | ||
2105 | if (_parent != null) | ||
2106 | { | ||
2107 | OdePrim parent = (OdePrim)_parent; | ||
2108 | parent.ChildDelink(this); | ||
2109 | } | ||
2110 | } | ||
2111 | else | ||
2112 | { | ||
2113 | disableBody(); | ||
2114 | } | ||
2115 | } | ||
2116 | try | ||
2117 | { | ||
2118 | d.GeomDestroy(prim_geom); | ||
2119 | } | ||
2120 | catch (System.AccessViolationException) | ||
2121 | { | ||
2122 | prim_geom = IntPtr.Zero; | ||
2123 | m_log.Error("[PHYSICS]: PrimGeom dead"); | ||
2124 | } | ||
2125 | prim_geom = IntPtr.Zero; | ||
2126 | // we don't need to do space calculation because the client sends a position update also. | ||
2127 | if (_size.X <= 0) _size.X = 0.01f; | ||
2128 | if (_size.Y <= 0) _size.Y = 0.01f; | ||
2129 | if (_size.Z <= 0) _size.Z = 0.01f; | ||
2130 | // Construction of new prim | ||
2131 | |||
2132 | if (_parent_scene.needsMeshing(_pbs)) | ||
2133 | { | ||
2134 | // Don't need to re-enable body.. it's done in SetMesh | ||
2135 | float meshlod = _parent_scene.meshSculptLOD; | ||
2136 | |||
2137 | if (IsPhysical) | ||
2138 | meshlod = _parent_scene.MeshSculptphysicalLOD; | ||
2139 | |||
2140 | IMesh mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, meshlod, IsPhysical); | ||
2141 | // createmesh returns null when it doesn't mesh. | ||
2142 | CreateGeom(m_targetSpace, mesh); | ||
2143 | } | ||
2144 | else | ||
2145 | { | ||
2146 | _mesh = null; | ||
2147 | //Console.WriteLine("changeshape"); | ||
2148 | CreateGeom(m_targetSpace, null); | ||
2149 | } | ||
2150 | |||
2151 | d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z); | ||
2152 | d.Quaternion myrot = new d.Quaternion(); | ||
2153 | //myrot.W = _orientation.w; | ||
2154 | myrot.W = _orientation.W; | ||
2155 | myrot.X = _orientation.X; | ||
2156 | myrot.Y = _orientation.Y; | ||
2157 | myrot.Z = _orientation.Z; | ||
2158 | d.GeomSetQuaternion(prim_geom, ref myrot); | ||
2159 | |||
2160 | //d.GeomBoxSetLengths(prim_geom, _size.X, _size.Y, _size.Z); | ||
2161 | if (IsPhysical && Body == IntPtr.Zero) | ||
2162 | { | ||
2163 | // Re creates body on size. | ||
2164 | // EnableBody also does setMass() | ||
2165 | enableBody(); | ||
2166 | if (Body != IntPtr.Zero) | ||
2167 | { | ||
2168 | d.BodyEnable(Body); | ||
2169 | } | ||
2170 | } | ||
2171 | _parent_scene.geom_name_map[prim_geom] = oldname; | ||
2172 | |||
2173 | changeSelectedStatus(timestamp); | ||
2174 | if (childPrim) | ||
2175 | { | ||
2176 | if (_parent is OdePrim) | ||
2177 | { | ||
2178 | OdePrim parent = (OdePrim)_parent; | ||
2179 | parent.ChildSetGeom(this); | ||
2180 | } | ||
2181 | } | ||
2182 | resetCollisionAccounting(); | ||
2183 | m_taintshape = false; | ||
2184 | } | ||
2185 | |||
2186 | public void changeAddForce(float timestamp) | ||
2187 | { | ||
2188 | if (!m_isSelected) | ||
2189 | { | ||
2190 | lock (m_forcelist) | ||
2191 | { | ||
2192 | //m_log.Info("[PHYSICS]: dequeing forcelist"); | ||
2193 | if (IsPhysical) | ||
2194 | { | ||
2195 | Vector3 iforce = Vector3.Zero; | ||
2196 | int i = 0; | ||
2197 | try | ||
2198 | { | ||
2199 | for (i = 0; i < m_forcelist.Count; i++) | ||
2200 | { | ||
2201 | |||
2202 | iforce = iforce + (m_forcelist[i] * 100); | ||
2203 | } | ||
2204 | } | ||
2205 | catch (IndexOutOfRangeException) | ||
2206 | { | ||
2207 | m_forcelist = new List<Vector3>(); | ||
2208 | m_collisionscore = 0; | ||
2209 | m_interpenetrationcount = 0; | ||
2210 | m_taintforce = false; | ||
2211 | return; | ||
2212 | } | ||
2213 | catch (ArgumentOutOfRangeException) | ||
2214 | { | ||
2215 | m_forcelist = new List<Vector3>(); | ||
2216 | m_collisionscore = 0; | ||
2217 | m_interpenetrationcount = 0; | ||
2218 | m_taintforce = false; | ||
2219 | return; | ||
2220 | } | ||
2221 | d.BodyEnable(Body); | ||
2222 | d.BodyAddForce(Body, iforce.X, iforce.Y, iforce.Z); | ||
2223 | } | ||
2224 | m_forcelist.Clear(); | ||
2225 | } | ||
2226 | |||
2227 | m_collisionscore = 0; | ||
2228 | m_interpenetrationcount = 0; | ||
2229 | } | ||
2230 | |||
2231 | m_taintforce = false; | ||
2232 | |||
2233 | } | ||
2234 | |||
2235 | |||
2236 | |||
2237 | public void changeSetTorque(float timestamp) | ||
2238 | { | ||
2239 | if (!m_isSelected) | ||
2240 | { | ||
2241 | if (IsPhysical && Body != IntPtr.Zero) | ||
2242 | { | ||
2243 | d.BodySetTorque(Body, m_taintTorque.X, m_taintTorque.Y, m_taintTorque.Z); | ||
2244 | } | ||
2245 | } | ||
2246 | |||
2247 | m_taintTorque = Vector3.Zero; | ||
2248 | } | ||
2249 | |||
2250 | public void changeAddAngularForce(float timestamp) | ||
2251 | { | ||
2252 | if (!m_isSelected) | ||
2253 | { | ||
2254 | lock (m_angularforcelist) | ||
2255 | { | ||
2256 | //m_log.Info("[PHYSICS]: dequeing forcelist"); | ||
2257 | if (IsPhysical) | ||
2258 | { | ||
2259 | Vector3 iforce = Vector3.Zero; | ||
2260 | for (int i = 0; i < m_angularforcelist.Count; i++) | ||
2261 | { | ||
2262 | iforce = iforce + (m_angularforcelist[i] * 100); | ||
2263 | } | ||
2264 | d.BodyEnable(Body); | ||
2265 | d.BodyAddTorque(Body, iforce.X, iforce.Y, iforce.Z); | ||
2266 | |||
2267 | } | ||
2268 | m_angularforcelist.Clear(); | ||
2269 | } | ||
2270 | |||
2271 | m_collisionscore = 0; | ||
2272 | m_interpenetrationcount = 0; | ||
2273 | } | ||
2274 | |||
2275 | m_taintaddangularforce = false; | ||
2276 | } | ||
2277 | |||
2278 | private void changevelocity(float timestep) | ||
2279 | { | ||
2280 | if (!m_isSelected) | ||
2281 | { | ||
2282 | Thread.Sleep(20); | ||
2283 | if (IsPhysical) | ||
2284 | { | ||
2285 | if (Body != IntPtr.Zero) | ||
2286 | { | ||
2287 | d.BodySetLinearVel(Body, m_taintVelocity.X, m_taintVelocity.Y, m_taintVelocity.Z); | ||
2288 | } | ||
2289 | } | ||
2290 | |||
2291 | //resetCollisionAccounting(); | ||
2292 | } | ||
2293 | m_taintVelocity = Vector3.Zero; | ||
2294 | } | ||
2295 | |||
2296 | public override bool IsPhysical | ||
2297 | { | ||
2298 | get { return m_isphysical; } | ||
2299 | set | ||
2300 | { | ||
2301 | m_isphysical = value; | ||
2302 | if (!m_isphysical) | ||
2303 | { // Zero the remembered last velocity | ||
2304 | m_lastVelocity = Vector3.Zero; | ||
2305 | if (m_vehicle.Type != Vehicle.TYPE_NONE) m_vehicle.Halt(); | ||
2306 | } | ||
2307 | } | ||
2308 | } | ||
2309 | |||
2310 | public void setPrimForRemoval() | ||
2311 | { | ||
2312 | m_taintremove = true; | ||
2313 | } | ||
2314 | |||
2315 | public override bool Flying | ||
2316 | { | ||
2317 | // no flying prims for you | ||
2318 | get { return false; } | ||
2319 | set { } | ||
2320 | } | ||
2321 | |||
2322 | public override bool IsColliding | ||
2323 | { | ||
2324 | get { return iscolliding; } | ||
2325 | set { iscolliding = value; } | ||
2326 | } | ||
2327 | |||
2328 | public override bool CollidingGround | ||
2329 | { | ||
2330 | get { return false; } | ||
2331 | set { return; } | ||
2332 | } | ||
2333 | |||
2334 | public override bool CollidingObj | ||
2335 | { | ||
2336 | get { return false; } | ||
2337 | set { return; } | ||
2338 | } | ||
2339 | |||
2340 | public override bool ThrottleUpdates | ||
2341 | { | ||
2342 | get { return m_throttleUpdates; } | ||
2343 | set { m_throttleUpdates = value; } | ||
2344 | } | ||
2345 | |||
2346 | public override bool Stopped | ||
2347 | { | ||
2348 | get { return _zeroFlag; } | ||
2349 | } | ||
2350 | |||
2351 | public override Vector3 Position | ||
2352 | { | ||
2353 | get { return _position; } | ||
2354 | |||
2355 | set { _position = value; | ||
2356 | //m_log.Info("[PHYSICS]: " + _position.ToString()); | ||
2357 | } | ||
2358 | } | ||
2359 | |||
2360 | public override Vector3 Size | ||
2361 | { | ||
2362 | get { return _size; } | ||
2363 | set | ||
2364 | { | ||
2365 | if (value.IsFinite()) | ||
2366 | { | ||
2367 | _size = value; | ||
2368 | } | ||
2369 | else | ||
2370 | { | ||
2371 | m_log.Warn("[PHYSICS]: Got NaN Size on object"); | ||
2372 | } | ||
2373 | } | ||
2374 | } | ||
2375 | |||
2376 | public override float Mass | ||
2377 | { | ||
2378 | get { return CalculateMass(); } | ||
2379 | } | ||
2380 | |||
2381 | public override Vector3 Force | ||
2382 | { | ||
2383 | //get { return Vector3.Zero; } | ||
2384 | get { return m_force; } | ||
2385 | set | ||
2386 | { | ||
2387 | if (value.IsFinite()) | ||
2388 | { | ||
2389 | m_force = value; | ||
2390 | } | ||
2391 | else | ||
2392 | { | ||
2393 | m_log.Warn("[PHYSICS]: NaN in Force Applied to an Object"); | ||
2394 | } | ||
2395 | } | ||
2396 | } | ||
2397 | |||
2398 | public override int VehicleType | ||
2399 | { | ||
2400 | get { return (int)m_vehicle.Type; } | ||
2401 | set { m_vehicle.ProcessTypeChange((Vehicle)value); } | ||
2402 | } | ||
2403 | |||
2404 | public override void VehicleFloatParam(int param, float value) | ||
2405 | { | ||
2406 | m_vehicle.ProcessFloatVehicleParam((Vehicle) param, value); | ||
2407 | } | ||
2408 | |||
2409 | public override void VehicleVectorParam(int param, Vector3 value) | ||
2410 | { | ||
2411 | m_vehicle.ProcessVectorVehicleParam((Vehicle) param, value); | ||
2412 | } | ||
2413 | |||
2414 | public override void VehicleRotationParam(int param, Quaternion rotation) | ||
2415 | { | ||
2416 | m_vehicle.ProcessRotationVehicleParam((Vehicle) param, rotation); | ||
2417 | } | ||
2418 | |||
2419 | public override void SetVolumeDetect(int param) | ||
2420 | { | ||
2421 | lock (_parent_scene.OdeLock) | ||
2422 | { | ||
2423 | m_isVolumeDetect = (param!=0); | ||
2424 | } | ||
2425 | } | ||
2426 | |||
2427 | public override Vector3 CenterOfMass | ||
2428 | { | ||
2429 | get { return Vector3.Zero; } | ||
2430 | } | ||
2431 | |||
2432 | public override Vector3 GeometricCenter | ||
2433 | { | ||
2434 | get { return Vector3.Zero; } | ||
2435 | } | ||
2436 | |||
2437 | public override PrimitiveBaseShape Shape | ||
2438 | { | ||
2439 | set | ||
2440 | { | ||
2441 | _pbs = value; | ||
2442 | m_taintshape = true; | ||
2443 | } | ||
2444 | } | ||
2445 | |||
2446 | public override Vector3 Velocity | ||
2447 | { | ||
2448 | get | ||
2449 | { | ||
2450 | // Averate previous velocity with the new one so | ||
2451 | // client object interpolation works a 'little' better | ||
2452 | if (_zeroFlag) | ||
2453 | return Vector3.Zero; | ||
2454 | |||
2455 | Vector3 returnVelocity = Vector3.Zero; | ||
2456 | returnVelocity.X = (m_lastVelocity.X + _velocity.X)/2; | ||
2457 | returnVelocity.Y = (m_lastVelocity.Y + _velocity.Y)/2; | ||
2458 | returnVelocity.Z = (m_lastVelocity.Z + _velocity.Z)/2; | ||
2459 | return returnVelocity; | ||
2460 | } | ||
2461 | set | ||
2462 | { | ||
2463 | if (value.IsFinite()) | ||
2464 | { | ||
2465 | _velocity = value; | ||
2466 | |||
2467 | m_taintVelocity = value; | ||
2468 | _parent_scene.AddPhysicsActorTaint(this); | ||
2469 | } | ||
2470 | else | ||
2471 | { | ||
2472 | m_log.Warn("[PHYSICS]: Got NaN Velocity in Object"); | ||
2473 | } | ||
2474 | |||
2475 | } | ||
2476 | } | ||
2477 | |||
2478 | public override Vector3 Torque | ||
2479 | { | ||
2480 | get | ||
2481 | { | ||
2482 | if (!m_isphysical || Body == IntPtr.Zero) | ||
2483 | return Vector3.Zero; | ||
2484 | |||
2485 | return _torque; | ||
2486 | } | ||
2487 | |||
2488 | set | ||
2489 | { | ||
2490 | if (value.IsFinite()) | ||
2491 | { | ||
2492 | m_taintTorque = value; | ||
2493 | _parent_scene.AddPhysicsActorTaint(this); | ||
2494 | } | ||
2495 | else | ||
2496 | { | ||
2497 | m_log.Warn("[PHYSICS]: Got NaN Torque in Object"); | ||
2498 | } | ||
2499 | } | ||
2500 | } | ||
2501 | |||
2502 | public override float CollisionScore | ||
2503 | { | ||
2504 | get { return m_collisionscore; } | ||
2505 | set { m_collisionscore = value; } | ||
2506 | } | ||
2507 | |||
2508 | public override bool Kinematic | ||
2509 | { | ||
2510 | get { return false; } | ||
2511 | set { } | ||
2512 | } | ||
2513 | |||
2514 | public override Quaternion Orientation | ||
2515 | { | ||
2516 | get { return _orientation; } | ||
2517 | set | ||
2518 | { | ||
2519 | if (QuaternionIsFinite(value)) | ||
2520 | { | ||
2521 | _orientation = value; | ||
2522 | } | ||
2523 | else | ||
2524 | m_log.Warn("[PHYSICS]: Got NaN quaternion Orientation from Scene in Object"); | ||
2525 | |||
2526 | } | ||
2527 | } | ||
2528 | |||
2529 | internal static bool QuaternionIsFinite(Quaternion q) | ||
2530 | { | ||
2531 | if (Single.IsNaN(q.X) || Single.IsInfinity(q.X)) | ||
2532 | return false; | ||
2533 | if (Single.IsNaN(q.Y) || Single.IsInfinity(q.Y)) | ||
2534 | return false; | ||
2535 | if (Single.IsNaN(q.Z) || Single.IsInfinity(q.Z)) | ||
2536 | return false; | ||
2537 | if (Single.IsNaN(q.W) || Single.IsInfinity(q.W)) | ||
2538 | return false; | ||
2539 | return true; | ||
2540 | } | ||
2541 | |||
2542 | public override Vector3 Acceleration | ||
2543 | { | ||
2544 | get { return _acceleration; } | ||
2545 | } | ||
2546 | |||
2547 | |||
2548 | public void SetAcceleration(Vector3 accel) | ||
2549 | { | ||
2550 | _acceleration = accel; | ||
2551 | } | ||
2552 | |||
2553 | public override void AddForce(Vector3 force, bool pushforce) | ||
2554 | { | ||
2555 | if (force.IsFinite()) | ||
2556 | { | ||
2557 | lock (m_forcelist) | ||
2558 | m_forcelist.Add(force); | ||
2559 | |||
2560 | m_taintforce = true; | ||
2561 | } | ||
2562 | else | ||
2563 | { | ||
2564 | m_log.Warn("[PHYSICS]: Got Invalid linear force vector from Scene in Object"); | ||
2565 | } | ||
2566 | //m_log.Info("[PHYSICS]: Added Force:" + force.ToString() + " to prim at " + Position.ToString()); | ||
2567 | } | ||
2568 | |||
2569 | public override void AddAngularForce(Vector3 force, bool pushforce) | ||
2570 | { | ||
2571 | if (force.IsFinite()) | ||
2572 | { | ||
2573 | m_angularforcelist.Add(force); | ||
2574 | m_taintaddangularforce = true; | ||
2575 | } | ||
2576 | else | ||
2577 | { | ||
2578 | m_log.Warn("[PHYSICS]: Got Invalid Angular force vector from Scene in Object"); | ||
2579 | } | ||
2580 | } | ||
2581 | |||
2582 | public override Vector3 RotationalVelocity | ||
2583 | { | ||
2584 | get | ||
2585 | { | ||
2586 | Vector3 pv = Vector3.Zero; | ||
2587 | if (_zeroFlag) | ||
2588 | return pv; | ||
2589 | m_lastUpdateSent = false; | ||
2590 | |||
2591 | if (m_rotationalVelocity.ApproxEquals(pv, 0.2f)) | ||
2592 | return pv; | ||
2593 | |||
2594 | return m_rotationalVelocity; | ||
2595 | } | ||
2596 | set | ||
2597 | { | ||
2598 | if (value.IsFinite()) | ||
2599 | { | ||
2600 | m_rotationalVelocity = value; | ||
2601 | } | ||
2602 | else | ||
2603 | { | ||
2604 | m_log.Warn("[PHYSICS]: Got NaN RotationalVelocity in Object"); | ||
2605 | } | ||
2606 | } | ||
2607 | } | ||
2608 | |||
2609 | public override void CrossingFailure() | ||
2610 | { | ||
2611 | m_crossingfailures++; | ||
2612 | if (m_crossingfailures > _parent_scene.geomCrossingFailuresBeforeOutofbounds) | ||
2613 | { | ||
2614 | base.RaiseOutOfBounds(_position); | ||
2615 | return; | ||
2616 | } | ||
2617 | else if (m_crossingfailures == _parent_scene.geomCrossingFailuresBeforeOutofbounds) | ||
2618 | { | ||
2619 | m_log.Warn("[PHYSICS]: Too many crossing failures for: " + m_primName); | ||
2620 | } | ||
2621 | } | ||
2622 | |||
2623 | public override float Buoyancy | ||
2624 | { | ||
2625 | get { return m_buoyancy; } | ||
2626 | set { m_buoyancy = value; } | ||
2627 | } | ||
2628 | |||
2629 | public override void link(PhysicsActor obj) | ||
2630 | { | ||
2631 | m_taintparent = obj; | ||
2632 | } | ||
2633 | |||
2634 | public override void delink() | ||
2635 | { | ||
2636 | m_taintparent = null; | ||
2637 | } | ||
2638 | |||
2639 | public override void LockAngularMotion(Vector3 axis) | ||
2640 | { | ||
2641 | // reverse the zero/non zero values for ODE. | ||
2642 | if (axis.IsFinite()) | ||
2643 | { | ||
2644 | axis.X = (axis.X > 0) ? 1f : 0f; | ||
2645 | axis.Y = (axis.Y > 0) ? 1f : 0f; | ||
2646 | axis.Z = (axis.Z > 0) ? 1f : 0f; | ||
2647 | m_log.DebugFormat("[axislock]: <{0},{1},{2}>", axis.X, axis.Y, axis.Z); | ||
2648 | m_taintAngularLock = axis; | ||
2649 | } | ||
2650 | else | ||
2651 | { | ||
2652 | m_log.Warn("[PHYSICS]: Got NaN locking axis from Scene on Object"); | ||
2653 | } | ||
2654 | } | ||
2655 | |||
2656 | public void UpdatePositionAndVelocity() | ||
2657 | { | ||
2658 | // no lock; called from Simulate() -- if you call this from elsewhere, gotta lock or do Monitor.Enter/Exit! | ||
2659 | if (_parent == null) | ||
2660 | { | ||
2661 | Vector3 pv = Vector3.Zero; | ||
2662 | bool lastZeroFlag = _zeroFlag; | ||
2663 | if (Body != (IntPtr)0) // FIXME -> or if it is a joint | ||
2664 | { | ||
2665 | d.Vector3 vec = d.BodyGetPosition(Body); | ||
2666 | d.Quaternion ori = d.BodyGetQuaternion(Body); | ||
2667 | d.Vector3 vel = d.BodyGetLinearVel(Body); | ||
2668 | d.Vector3 rotvel = d.BodyGetAngularVel(Body); | ||
2669 | d.Vector3 torque = d.BodyGetTorque(Body); | ||
2670 | _torque = new Vector3(torque.X, torque.Y, torque.Z); | ||
2671 | Vector3 l_position = Vector3.Zero; | ||
2672 | Quaternion l_orientation = Quaternion.Identity; | ||
2673 | |||
2674 | // kluge to keep things in bounds. ODE lets dead avatars drift away (they should be removed!) | ||
2675 | //if (vec.X < 0.0f) { vec.X = 0.0f; if (Body != (IntPtr)0) d.BodySetAngularVel(Body, 0, 0, 0); } | ||
2676 | //if (vec.Y < 0.0f) { vec.Y = 0.0f; if (Body != (IntPtr)0) d.BodySetAngularVel(Body, 0, 0, 0); } | ||
2677 | //if (vec.X > 255.95f) { vec.X = 255.95f; if (Body != (IntPtr)0) d.BodySetAngularVel(Body, 0, 0, 0); } | ||
2678 | //if (vec.Y > 255.95f) { vec.Y = 255.95f; if (Body != (IntPtr)0) d.BodySetAngularVel(Body, 0, 0, 0); } | ||
2679 | |||
2680 | m_lastposition = _position; | ||
2681 | m_lastorientation = _orientation; | ||
2682 | |||
2683 | l_position.X = vec.X; | ||
2684 | l_position.Y = vec.Y; | ||
2685 | l_position.Z = vec.Z; | ||
2686 | l_orientation.X = ori.X; | ||
2687 | l_orientation.Y = ori.Y; | ||
2688 | l_orientation.Z = ori.Z; | ||
2689 | l_orientation.W = ori.W; | ||
2690 | |||
2691 | // if(l_position.Y != m_lastposition.Y){ | ||
2692 | // Console.WriteLine("UP&V {0} {1}", m_primName, l_position); | ||
2693 | // } | ||
2694 | |||
2695 | if (l_position.X > ((int)_parent_scene.WorldExtents.X - 0.05f) || l_position.X < 0f || l_position.Y > ((int)_parent_scene.WorldExtents.Y - 0.05f) || l_position.Y < 0f) | ||
2696 | { | ||
2697 | //base.RaiseOutOfBounds(l_position); | ||
2698 | |||
2699 | if (m_crossingfailures < _parent_scene.geomCrossingFailuresBeforeOutofbounds) | ||
2700 | { | ||
2701 | _position = l_position; | ||
2702 | //_parent_scene.remActivePrim(this); | ||
2703 | if (_parent == null) | ||
2704 | base.RequestPhysicsterseUpdate(); | ||
2705 | return; | ||
2706 | } | ||
2707 | else | ||
2708 | { | ||
2709 | if (_parent == null) | ||
2710 | base.RaiseOutOfBounds(l_position); | ||
2711 | return; | ||
2712 | } | ||
2713 | } | ||
2714 | |||
2715 | if (l_position.Z < 0) | ||
2716 | { | ||
2717 | // This is so prim that get lost underground don't fall forever and suck up | ||
2718 | // | ||
2719 | // Sim resources and memory. | ||
2720 | // Disables the prim's movement physics.... | ||
2721 | // It's a hack and will generate a console message if it fails. | ||
2722 | |||
2723 | //IsPhysical = false; | ||
2724 | if (_parent == null) | ||
2725 | base.RaiseOutOfBounds(_position); | ||
2726 | |||
2727 | _acceleration.X = 0; | ||
2728 | _acceleration.Y = 0; | ||
2729 | _acceleration.Z = 0; | ||
2730 | |||
2731 | _velocity.X = 0; | ||
2732 | _velocity.Y = 0; | ||
2733 | _velocity.Z = 0; | ||
2734 | m_rotationalVelocity.X = 0; | ||
2735 | m_rotationalVelocity.Y = 0; | ||
2736 | m_rotationalVelocity.Z = 0; | ||
2737 | |||
2738 | if (_parent == null) | ||
2739 | base.RequestPhysicsterseUpdate(); | ||
2740 | |||
2741 | m_throttleUpdates = false; | ||
2742 | throttleCounter = 0; | ||
2743 | _zeroFlag = true; | ||
2744 | //outofBounds = true; | ||
2745 | } | ||
2746 | |||
2747 | //float Adiff = 1.0f - Math.Abs(Quaternion.Dot(m_lastorientation, l_orientation)); | ||
2748 | //Console.WriteLine("Adiff " + m_primName + " = " + Adiff); | ||
2749 | if ((Math.Abs(m_lastposition.X - l_position.X) < 0.02) | ||
2750 | && (Math.Abs(m_lastposition.Y - l_position.Y) < 0.02) | ||
2751 | && (Math.Abs(m_lastposition.Z - l_position.Z) < 0.02) | ||
2752 | // && (1.0 - Math.Abs(Quaternion.Dot(m_lastorientation, l_orientation)) < 0.01)) | ||
2753 | && (1.0 - Math.Abs(Quaternion.Dot(m_lastorientation, l_orientation)) < 0.0001)) // KF 0.01 is far to large | ||
2754 | { | ||
2755 | _zeroFlag = true; | ||
2756 | //Console.WriteLine("ZFT 2"); | ||
2757 | m_throttleUpdates = false; | ||
2758 | } | ||
2759 | else | ||
2760 | { | ||
2761 | //m_log.Debug(Math.Abs(m_lastposition.X - l_position.X).ToString()); | ||
2762 | _zeroFlag = false; | ||
2763 | m_lastUpdateSent = false; | ||
2764 | //m_throttleUpdates = false; | ||
2765 | } | ||
2766 | |||
2767 | if (_zeroFlag) | ||
2768 | { | ||
2769 | _velocity.X = 0.0f; | ||
2770 | _velocity.Y = 0.0f; | ||
2771 | _velocity.Z = 0.0f; | ||
2772 | |||
2773 | _acceleration.X = 0; | ||
2774 | _acceleration.Y = 0; | ||
2775 | _acceleration.Z = 0; | ||
2776 | |||
2777 | //_orientation.w = 0f; | ||
2778 | //_orientation.X = 0f; | ||
2779 | //_orientation.Y = 0f; | ||
2780 | //_orientation.Z = 0f; | ||
2781 | m_rotationalVelocity.X = 0; | ||
2782 | m_rotationalVelocity.Y = 0; | ||
2783 | m_rotationalVelocity.Z = 0; | ||
2784 | if (!m_lastUpdateSent) | ||
2785 | { | ||
2786 | m_throttleUpdates = false; | ||
2787 | throttleCounter = 0; | ||
2788 | m_rotationalVelocity = pv; | ||
2789 | |||
2790 | if (_parent == null) | ||
2791 | { | ||
2792 | base.RequestPhysicsterseUpdate(); | ||
2793 | } | ||
2794 | |||
2795 | m_lastUpdateSent = true; | ||
2796 | } | ||
2797 | } | ||
2798 | else | ||
2799 | { | ||
2800 | if (lastZeroFlag != _zeroFlag) | ||
2801 | { | ||
2802 | if (_parent == null) | ||
2803 | { | ||
2804 | base.RequestPhysicsterseUpdate(); | ||
2805 | } | ||
2806 | } | ||
2807 | |||
2808 | m_lastVelocity = _velocity; | ||
2809 | |||
2810 | _position = l_position; | ||
2811 | |||
2812 | _velocity.X = vel.X; | ||
2813 | _velocity.Y = vel.Y; | ||
2814 | _velocity.Z = vel.Z; | ||
2815 | |||
2816 | _acceleration = ((_velocity - m_lastVelocity) / 0.1f); | ||
2817 | _acceleration = new Vector3(_velocity.X - m_lastVelocity.X / 0.1f, _velocity.Y - m_lastVelocity.Y / 0.1f, _velocity.Z - m_lastVelocity.Z / 0.1f); | ||
2818 | //m_log.Info("[PHYSICS]: V1: " + _velocity + " V2: " + m_lastVelocity + " Acceleration: " + _acceleration.ToString()); | ||
2819 | |||
2820 | if (_velocity.ApproxEquals(pv, 0.5f)) | ||
2821 | { | ||
2822 | m_rotationalVelocity = pv; | ||
2823 | } | ||
2824 | else | ||
2825 | { | ||
2826 | m_rotationalVelocity = new Vector3(rotvel.X, rotvel.Y, rotvel.Z); | ||
2827 | } | ||
2828 | |||
2829 | //m_log.Debug("ODE: " + m_rotationalVelocity.ToString()); | ||
2830 | _orientation.X = ori.X; | ||
2831 | _orientation.Y = ori.Y; | ||
2832 | _orientation.Z = ori.Z; | ||
2833 | _orientation.W = ori.W; | ||
2834 | m_lastUpdateSent = false; | ||
2835 | if (!m_throttleUpdates || throttleCounter > _parent_scene.geomUpdatesPerThrottledUpdate) | ||
2836 | { | ||
2837 | if (_parent == null) | ||
2838 | { | ||
2839 | base.RequestPhysicsterseUpdate(); | ||
2840 | } | ||
2841 | } | ||
2842 | else | ||
2843 | { | ||
2844 | throttleCounter++; | ||
2845 | } | ||
2846 | } | ||
2847 | m_lastposition = l_position; | ||
2848 | } | ||
2849 | else | ||
2850 | { | ||
2851 | // Not a body.. so Make sure the client isn't interpolating | ||
2852 | _velocity.X = 0; | ||
2853 | _velocity.Y = 0; | ||
2854 | _velocity.Z = 0; | ||
2855 | |||
2856 | _acceleration.X = 0; | ||
2857 | _acceleration.Y = 0; | ||
2858 | _acceleration.Z = 0; | ||
2859 | |||
2860 | m_rotationalVelocity.X = 0; | ||
2861 | m_rotationalVelocity.Y = 0; | ||
2862 | m_rotationalVelocity.Z = 0; | ||
2863 | _zeroFlag = true; | ||
2864 | } | ||
2865 | } | ||
2866 | } | ||
2867 | |||
2868 | public override bool FloatOnWater | ||
2869 | { | ||
2870 | set { | ||
2871 | m_taintCollidesWater = value; | ||
2872 | _parent_scene.AddPhysicsActorTaint(this); | ||
2873 | } | ||
2874 | } | ||
2875 | |||
2876 | public override void SetMomentum(Vector3 momentum) | ||
2877 | { | ||
2878 | } | ||
2879 | |||
2880 | public override Vector3 PIDTarget | ||
2881 | { | ||
2882 | set | ||
2883 | { | ||
2884 | if (value.IsFinite()) | ||
2885 | { | ||
2886 | m_PIDTarget = value; | ||
2887 | } | ||
2888 | else | ||
2889 | m_log.Warn("[PHYSICS]: Got NaN PIDTarget from Scene on Object"); | ||
2890 | } | ||
2891 | } | ||
2892 | public override bool PIDActive { set { m_usePID = value; } } | ||
2893 | public override float PIDTau { set { m_PIDTau = value; } } | ||
2894 | |||
2895 | // For RotLookAt | ||
2896 | public override Quaternion APIDTarget { set { m_APIDTarget = value; } } | ||
2897 | public override bool APIDActive { set { m_useAPID = value; } } | ||
2898 | public override float APIDStrength { set { m_APIDStrength = value; } } | ||
2899 | public override float APIDDamping { set { m_APIDDamping = value; } } | ||
2900 | |||
2901 | public override float PIDHoverHeight { set { m_PIDHoverHeight = value; ; } } | ||
2902 | public override bool PIDHoverActive { set { m_useHoverPID = value; } } | ||
2903 | public override PIDHoverType PIDHoverType { set { m_PIDHoverType = value; } } | ||
2904 | public override float PIDHoverTau { set { m_PIDHoverTau = value; } } | ||
2905 | |||
2906 | private void createAMotor(Vector3 axis) | ||
2907 | { | ||
2908 | if (Body == IntPtr.Zero) | ||
2909 | return; | ||
2910 | |||
2911 | if (Amotor != IntPtr.Zero) | ||
2912 | { | ||
2913 | d.JointDestroy(Amotor); | ||
2914 | Amotor = IntPtr.Zero; | ||
2915 | } | ||
2916 | |||
2917 | float axisnum = 3; | ||
2918 | |||
2919 | axisnum = (axisnum - (axis.X + axis.Y + axis.Z)); | ||
2920 | |||
2921 | // PhysicsVector totalSize = new PhysicsVector(_size.X, _size.Y, _size.Z); | ||
2922 | |||
2923 | |||
2924 | // Inverse Inertia Matrix, set the X, Y, and/r Z inertia to 0 then invert it again. | ||
2925 | d.Mass objMass; | ||
2926 | d.MassSetZero(out objMass); | ||
2927 | DMassCopy(ref pMass, ref objMass); | ||
2928 | |||
2929 | //m_log.DebugFormat("1-{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, ", objMass.I.M00, objMass.I.M01, objMass.I.M02, objMass.I.M10, objMass.I.M11, objMass.I.M12, objMass.I.M20, objMass.I.M21, objMass.I.M22); | ||
2930 | |||
2931 | Matrix4 dMassMat = FromDMass(objMass); | ||
2932 | |||
2933 | Matrix4 mathmat = Inverse(dMassMat); | ||
2934 | |||
2935 | /* | ||
2936 | //m_log.DebugFormat("2-{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, ", mathmat[0, 0], mathmat[0, 1], mathmat[0, 2], mathmat[1, 0], mathmat[1, 1], mathmat[1, 2], mathmat[2, 0], mathmat[2, 1], mathmat[2, 2]); | ||
2937 | |||
2938 | mathmat = Inverse(mathmat); | ||
2939 | |||
2940 | |||
2941 | objMass = FromMatrix4(mathmat, ref objMass); | ||
2942 | //m_log.DebugFormat("3-{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, ", objMass.I.M00, objMass.I.M01, objMass.I.M02, objMass.I.M10, objMass.I.M11, objMass.I.M12, objMass.I.M20, objMass.I.M21, objMass.I.M22); | ||
2943 | |||
2944 | mathmat = Inverse(mathmat); | ||
2945 | */ | ||
2946 | if (axis.X == 0) | ||
2947 | { | ||
2948 | mathmat.M33 = 50.0000001f; | ||
2949 | //objMass.I.M22 = 0; | ||
2950 | } | ||
2951 | if (axis.Y == 0) | ||
2952 | { | ||
2953 | mathmat.M22 = 50.0000001f; | ||
2954 | //objMass.I.M11 = 0; | ||
2955 | } | ||
2956 | if (axis.Z == 0) | ||
2957 | { | ||
2958 | mathmat.M11 = 50.0000001f; | ||
2959 | //objMass.I.M00 = 0; | ||
2960 | } | ||
2961 | |||
2962 | |||
2963 | |||
2964 | mathmat = Inverse(mathmat); | ||
2965 | objMass = FromMatrix4(mathmat, ref objMass); | ||
2966 | //m_log.DebugFormat("4-{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, ", objMass.I.M00, objMass.I.M01, objMass.I.M02, objMass.I.M10, objMass.I.M11, objMass.I.M12, objMass.I.M20, objMass.I.M21, objMass.I.M22); | ||
2967 | |||
2968 | //return; | ||
2969 | if (d.MassCheck(ref objMass)) | ||
2970 | { | ||
2971 | d.BodySetMass(Body, ref objMass); | ||
2972 | } | ||
2973 | else | ||
2974 | { | ||
2975 | //m_log.Debug("[PHYSICS]: Mass invalid, ignoring"); | ||
2976 | } | ||
2977 | |||
2978 | if (axisnum <= 0) | ||
2979 | return; | ||
2980 | // int dAMotorEuler = 1; | ||
2981 | |||
2982 | Amotor = d.JointCreateAMotor(_parent_scene.world, IntPtr.Zero); | ||
2983 | d.JointAttach(Amotor, Body, IntPtr.Zero); | ||
2984 | d.JointSetAMotorMode(Amotor, 0); | ||
2985 | |||
2986 | d.JointSetAMotorNumAxes(Amotor,(int)axisnum); | ||
2987 | int i = 0; | ||
2988 | |||
2989 | if (axis.X == 0) | ||
2990 | { | ||
2991 | d.JointSetAMotorAxis(Amotor, i, 0, 1, 0, 0); | ||
2992 | i++; | ||
2993 | } | ||
2994 | |||
2995 | if (axis.Y == 0) | ||
2996 | { | ||
2997 | d.JointSetAMotorAxis(Amotor, i, 0, 0, 1, 0); | ||
2998 | i++; | ||
2999 | } | ||
3000 | |||
3001 | if (axis.Z == 0) | ||
3002 | { | ||
3003 | d.JointSetAMotorAxis(Amotor, i, 0, 0, 0, 1); | ||
3004 | i++; | ||
3005 | } | ||
3006 | |||
3007 | for (int j = 0; j < (int)axisnum; j++) | ||
3008 | { | ||
3009 | //d.JointSetAMotorAngle(Amotor, j, 0); | ||
3010 | } | ||
3011 | |||
3012 | //d.JointSetAMotorAngle(Amotor, 1, 0); | ||
3013 | //d.JointSetAMotorAngle(Amotor, 2, 0); | ||
3014 | |||
3015 | // These lowstops and high stops are effectively (no wiggle room) | ||
3016 | d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, -0f); | ||
3017 | d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, -0f); | ||
3018 | d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, -0f); | ||
3019 | d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, 0f); | ||
3020 | d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0f); | ||
3021 | d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, 0f); | ||
3022 | //d.JointSetAMotorParam(Amotor, (int) dParam.Vel, 9000f); | ||
3023 | d.JointSetAMotorParam(Amotor, (int)dParam.FudgeFactor, 0f); | ||
3024 | d.JointSetAMotorParam(Amotor, (int)dParam.FMax, Mass * 50f);// | ||
3025 | |||
3026 | } | ||
3027 | |||
3028 | public Matrix4 FromDMass(d.Mass pMass) | ||
3029 | { | ||
3030 | Matrix4 obj; | ||
3031 | obj.M11 = pMass.I.M00; | ||
3032 | obj.M12 = pMass.I.M01; | ||
3033 | obj.M13 = pMass.I.M02; | ||
3034 | obj.M14 = 0; | ||
3035 | obj.M21 = pMass.I.M10; | ||
3036 | obj.M22 = pMass.I.M11; | ||
3037 | obj.M23 = pMass.I.M12; | ||
3038 | obj.M24 = 0; | ||
3039 | obj.M31 = pMass.I.M20; | ||
3040 | obj.M32 = pMass.I.M21; | ||
3041 | obj.M33 = pMass.I.M22; | ||
3042 | obj.M34 = 0; | ||
3043 | obj.M41 = 0; | ||
3044 | obj.M42 = 0; | ||
3045 | obj.M43 = 0; | ||
3046 | obj.M44 = 1; | ||
3047 | return obj; | ||
3048 | } | ||
3049 | |||
3050 | public d.Mass FromMatrix4(Matrix4 pMat, ref d.Mass obj) | ||
3051 | { | ||
3052 | obj.I.M00 = pMat[0, 0]; | ||
3053 | obj.I.M01 = pMat[0, 1]; | ||
3054 | obj.I.M02 = pMat[0, 2]; | ||
3055 | obj.I.M10 = pMat[1, 0]; | ||
3056 | obj.I.M11 = pMat[1, 1]; | ||
3057 | obj.I.M12 = pMat[1, 2]; | ||
3058 | obj.I.M20 = pMat[2, 0]; | ||
3059 | obj.I.M21 = pMat[2, 1]; | ||
3060 | obj.I.M22 = pMat[2, 2]; | ||
3061 | return obj; | ||
3062 | } | ||
3063 | |||
3064 | public override void SubscribeEvents(int ms) | ||
3065 | { | ||
3066 | m_eventsubscription = ms; | ||
3067 | _parent_scene.addCollisionEventReporting(this); | ||
3068 | } | ||
3069 | |||
3070 | public override void UnSubscribeEvents() | ||
3071 | { | ||
3072 | _parent_scene.remCollisionEventReporting(this); | ||
3073 | m_eventsubscription = 0; | ||
3074 | } | ||
3075 | |||
3076 | public void AddCollisionEvent(uint CollidedWith, ContactPoint contact) | ||
3077 | { | ||
3078 | if (CollisionEventsThisFrame == null) | ||
3079 | CollisionEventsThisFrame = new CollisionEventUpdate(); | ||
3080 | CollisionEventsThisFrame.addCollider(CollidedWith, contact); | ||
3081 | } | ||
3082 | |||
3083 | public void SendCollisions() | ||
3084 | { | ||
3085 | if (CollisionEventsThisFrame == null) | ||
3086 | return; | ||
3087 | |||
3088 | base.SendCollisionUpdate(CollisionEventsThisFrame); | ||
3089 | |||
3090 | if (CollisionEventsThisFrame.m_objCollisionList.Count == 0) | ||
3091 | CollisionEventsThisFrame = null; | ||
3092 | else | ||
3093 | CollisionEventsThisFrame = new CollisionEventUpdate(); | ||
3094 | } | ||
3095 | |||
3096 | public override bool SubscribedEvents() | ||
3097 | { | ||
3098 | if (m_eventsubscription > 0) | ||
3099 | return true; | ||
3100 | return false; | ||
3101 | } | ||
3102 | |||
3103 | public static Matrix4 Inverse(Matrix4 pMat) | ||
3104 | { | ||
3105 | if (determinant3x3(pMat) == 0) | ||
3106 | { | ||
3107 | return Matrix4.Identity; // should probably throw an error. singluar matrix inverse not possible | ||
3108 | } | ||
3109 | |||
3110 | |||
3111 | |||
3112 | return (Adjoint(pMat) / determinant3x3(pMat)); | ||
3113 | } | ||
3114 | |||
3115 | public static Matrix4 Adjoint(Matrix4 pMat) | ||
3116 | { | ||
3117 | Matrix4 adjointMatrix = new Matrix4(); | ||
3118 | for (int i=0; i<4; i++) | ||
3119 | { | ||
3120 | for (int j=0; j<4; j++) | ||
3121 | { | ||
3122 | Matrix4SetValue(ref adjointMatrix, i, j, (float)(Math.Pow(-1, i + j) * (determinant3x3(Minor(pMat, i, j))))); | ||
3123 | } | ||
3124 | } | ||
3125 | |||
3126 | adjointMatrix = Transpose(adjointMatrix); | ||
3127 | return adjointMatrix; | ||
3128 | } | ||
3129 | |||
3130 | public static Matrix4 Minor(Matrix4 matrix, int iRow, int iCol) | ||
3131 | { | ||
3132 | Matrix4 minor = new Matrix4(); | ||
3133 | int m = 0, n = 0; | ||
3134 | for (int i = 0; i < 4; i++) | ||
3135 | { | ||
3136 | if (i == iRow) | ||
3137 | continue; | ||
3138 | n = 0; | ||
3139 | for (int j = 0; j < 4; j++) | ||
3140 | { | ||
3141 | if (j == iCol) | ||
3142 | continue; | ||
3143 | Matrix4SetValue(ref minor, m,n, matrix[i, j]); | ||
3144 | n++; | ||
3145 | } | ||
3146 | m++; | ||
3147 | } | ||
3148 | return minor; | ||
3149 | } | ||
3150 | |||
3151 | public static Matrix4 Transpose(Matrix4 pMat) | ||
3152 | { | ||
3153 | Matrix4 transposeMatrix = new Matrix4(); | ||
3154 | for (int i = 0; i < 4; i++) | ||
3155 | for (int j = 0; j < 4; j++) | ||
3156 | Matrix4SetValue(ref transposeMatrix, i, j, pMat[j, i]); | ||
3157 | return transposeMatrix; | ||
3158 | } | ||
3159 | |||
3160 | public static void Matrix4SetValue(ref Matrix4 pMat, int r, int c, float val) | ||
3161 | { | ||
3162 | switch (r) | ||
3163 | { | ||
3164 | case 0: | ||
3165 | switch (c) | ||
3166 | { | ||
3167 | case 0: | ||
3168 | pMat.M11 = val; | ||
3169 | break; | ||
3170 | case 1: | ||
3171 | pMat.M12 = val; | ||
3172 | break; | ||
3173 | case 2: | ||
3174 | pMat.M13 = val; | ||
3175 | break; | ||
3176 | case 3: | ||
3177 | pMat.M14 = val; | ||
3178 | break; | ||
3179 | } | ||
3180 | |||
3181 | break; | ||
3182 | case 1: | ||
3183 | switch (c) | ||
3184 | { | ||
3185 | case 0: | ||
3186 | pMat.M21 = val; | ||
3187 | break; | ||
3188 | case 1: | ||
3189 | pMat.M22 = val; | ||
3190 | break; | ||
3191 | case 2: | ||
3192 | pMat.M23 = val; | ||
3193 | break; | ||
3194 | case 3: | ||
3195 | pMat.M24 = val; | ||
3196 | break; | ||
3197 | } | ||
3198 | |||
3199 | break; | ||
3200 | case 2: | ||
3201 | switch (c) | ||
3202 | { | ||
3203 | case 0: | ||
3204 | pMat.M31 = val; | ||
3205 | break; | ||
3206 | case 1: | ||
3207 | pMat.M32 = val; | ||
3208 | break; | ||
3209 | case 2: | ||
3210 | pMat.M33 = val; | ||
3211 | break; | ||
3212 | case 3: | ||
3213 | pMat.M34 = val; | ||
3214 | break; | ||
3215 | } | ||
3216 | |||
3217 | break; | ||
3218 | case 3: | ||
3219 | switch (c) | ||
3220 | { | ||
3221 | case 0: | ||
3222 | pMat.M41 = val; | ||
3223 | break; | ||
3224 | case 1: | ||
3225 | pMat.M42 = val; | ||
3226 | break; | ||
3227 | case 2: | ||
3228 | pMat.M43 = val; | ||
3229 | break; | ||
3230 | case 3: | ||
3231 | pMat.M44 = val; | ||
3232 | break; | ||
3233 | } | ||
3234 | |||
3235 | break; | ||
3236 | } | ||
3237 | } | ||
3238 | private static float determinant3x3(Matrix4 pMat) | ||
3239 | { | ||
3240 | float det = 0; | ||
3241 | float diag1 = pMat[0, 0]*pMat[1, 1]*pMat[2, 2]; | ||
3242 | float diag2 = pMat[0, 1]*pMat[2, 1]*pMat[2, 0]; | ||
3243 | float diag3 = pMat[0, 2]*pMat[1, 0]*pMat[2, 1]; | ||
3244 | float diag4 = pMat[2, 0]*pMat[1, 1]*pMat[0, 2]; | ||
3245 | float diag5 = pMat[2, 1]*pMat[1, 2]*pMat[0, 0]; | ||
3246 | float diag6 = pMat[2, 2]*pMat[1, 0]*pMat[0, 1]; | ||
3247 | |||
3248 | det = diag1 + diag2 + diag3 - (diag4 + diag5 + diag6); | ||
3249 | return det; | ||
3250 | |||
3251 | } | ||
3252 | |||
3253 | private static void DMassCopy(ref d.Mass src, ref d.Mass dst) | ||
3254 | { | ||
3255 | dst.c.W = src.c.W; | ||
3256 | dst.c.X = src.c.X; | ||
3257 | dst.c.Y = src.c.Y; | ||
3258 | dst.c.Z = src.c.Z; | ||
3259 | dst.mass = src.mass; | ||
3260 | dst.I.M00 = src.I.M00; | ||
3261 | dst.I.M01 = src.I.M01; | ||
3262 | dst.I.M02 = src.I.M02; | ||
3263 | dst.I.M10 = src.I.M10; | ||
3264 | dst.I.M11 = src.I.M11; | ||
3265 | dst.I.M12 = src.I.M12; | ||
3266 | dst.I.M20 = src.I.M20; | ||
3267 | dst.I.M21 = src.I.M21; | ||
3268 | dst.I.M22 = src.I.M22; | ||
3269 | } | ||
3270 | |||
3271 | public override void SetMaterial(int pMaterial) | ||
3272 | { | ||
3273 | m_material = pMaterial; | ||
3274 | } | ||
3275 | |||
3276 | } | ||
3277 | } | ||
diff --git a/OpenSim/Region/Physics/ChOdePlugin/ODERayCastRequestManager.cs b/OpenSim/Region/Physics/ChOdePlugin/ODERayCastRequestManager.cs new file mode 100644 index 0000000..7314107 --- /dev/null +++ b/OpenSim/Region/Physics/ChOdePlugin/ODERayCastRequestManager.cs | |||
@@ -0,0 +1,375 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Reflection; | ||
31 | using System.Runtime.InteropServices; | ||
32 | using System.Text; | ||
33 | using OpenMetaverse; | ||
34 | using OpenSim.Region.Physics.Manager; | ||
35 | using Ode.NET; | ||
36 | using log4net; | ||
37 | |||
38 | namespace OpenSim.Region.Physics.OdePlugin | ||
39 | { | ||
40 | /// <summary> | ||
41 | /// Processes raycast requests as ODE is in a state to be able to do them. | ||
42 | /// This ensures that it's thread safe and there will be no conflicts. | ||
43 | /// Requests get returned by a different thread then they were requested by. | ||
44 | /// </summary> | ||
45 | public class ODERayCastRequestManager | ||
46 | { | ||
47 | /// <summary> | ||
48 | /// Pending Raycast Requests | ||
49 | /// </summary> | ||
50 | protected List<ODERayCastRequest> m_PendingRequests = new List<ODERayCastRequest>(); | ||
51 | |||
52 | /// <summary> | ||
53 | /// Scene that created this object. | ||
54 | /// </summary> | ||
55 | private OdeScene m_scene; | ||
56 | |||
57 | /// <summary> | ||
58 | /// ODE contact array to be filled by the collision testing | ||
59 | /// </summary> | ||
60 | d.ContactGeom[] contacts = new d.ContactGeom[5]; | ||
61 | |||
62 | /// <summary> | ||
63 | /// ODE near callback delegate | ||
64 | /// </summary> | ||
65 | private d.NearCallback nearCallback; | ||
66 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
67 | private List<ContactResult> m_contactResults = new List<ContactResult>(); | ||
68 | |||
69 | |||
70 | public ODERayCastRequestManager(OdeScene pScene) | ||
71 | { | ||
72 | m_scene = pScene; | ||
73 | nearCallback = near; | ||
74 | |||
75 | } | ||
76 | |||
77 | /// <summary> | ||
78 | /// Queues a raycast | ||
79 | /// </summary> | ||
80 | /// <param name="position">Origin of Ray</param> | ||
81 | /// <param name="direction">Ray normal</param> | ||
82 | /// <param name="length">Ray length</param> | ||
83 | /// <param name="retMethod">Return method to send the results</param> | ||
84 | public void QueueRequest(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod) | ||
85 | { | ||
86 | lock (m_PendingRequests) | ||
87 | { | ||
88 | ODERayCastRequest req = new ODERayCastRequest(); | ||
89 | req.callbackMethod = retMethod; | ||
90 | req.length = length; | ||
91 | req.Normal = direction; | ||
92 | req.Origin = position; | ||
93 | |||
94 | m_PendingRequests.Add(req); | ||
95 | } | ||
96 | } | ||
97 | |||
98 | /// <summary> | ||
99 | /// Process all queued raycast requests | ||
100 | /// </summary> | ||
101 | /// <returns>Time in MS the raycasts took to process.</returns> | ||
102 | public int ProcessQueuedRequests() | ||
103 | { | ||
104 | int time = System.Environment.TickCount; | ||
105 | lock (m_PendingRequests) | ||
106 | { | ||
107 | if (m_PendingRequests.Count > 0) | ||
108 | { | ||
109 | ODERayCastRequest[] reqs = m_PendingRequests.ToArray(); | ||
110 | for (int i = 0; i < reqs.Length; i++) | ||
111 | { | ||
112 | if (reqs[i].callbackMethod != null) // quick optimization here, don't raycast | ||
113 | RayCast(reqs[i]); // if there isn't anyone to send results | ||
114 | } | ||
115 | /* | ||
116 | foreach (ODERayCastRequest req in m_PendingRequests) | ||
117 | { | ||
118 | if (req.callbackMethod != null) // quick optimization here, don't raycast | ||
119 | RayCast(req); // if there isn't anyone to send results to | ||
120 | |||
121 | } | ||
122 | */ | ||
123 | m_PendingRequests.Clear(); | ||
124 | } | ||
125 | } | ||
126 | |||
127 | lock (m_contactResults) | ||
128 | m_contactResults.Clear(); | ||
129 | |||
130 | return System.Environment.TickCount - time; | ||
131 | } | ||
132 | |||
133 | /// <summary> | ||
134 | /// Method that actually initiates the raycast | ||
135 | /// </summary> | ||
136 | /// <param name="req"></param> | ||
137 | private void RayCast(ODERayCastRequest req) | ||
138 | { | ||
139 | // Create the ray | ||
140 | IntPtr ray = d.CreateRay(m_scene.space, req.length); | ||
141 | d.GeomRaySet(ray, req.Origin.X, req.Origin.Y, req.Origin.Z, req.Normal.X, req.Normal.Y, req.Normal.Z); | ||
142 | |||
143 | // Collide test | ||
144 | d.SpaceCollide2(m_scene.space, ray, IntPtr.Zero, nearCallback); | ||
145 | |||
146 | // Remove Ray | ||
147 | d.GeomDestroy(ray); | ||
148 | |||
149 | |||
150 | // Define default results | ||
151 | bool hitYN = false; | ||
152 | uint hitConsumerID = 0; | ||
153 | float distance = 999999999999f; | ||
154 | Vector3 closestcontact = new Vector3(99999f, 99999f, 99999f); | ||
155 | Vector3 snormal = Vector3.Zero; | ||
156 | |||
157 | // Find closest contact and object. | ||
158 | lock (m_contactResults) | ||
159 | { | ||
160 | foreach (ContactResult cResult in m_contactResults) | ||
161 | { | ||
162 | if (Vector3.Distance(req.Origin, cResult.Pos) < Vector3.Distance(req.Origin, closestcontact)) | ||
163 | { | ||
164 | closestcontact = cResult.Pos; | ||
165 | hitConsumerID = cResult.ConsumerID; | ||
166 | distance = cResult.Depth; | ||
167 | hitYN = true; | ||
168 | snormal = cResult.Normal; | ||
169 | } | ||
170 | } | ||
171 | |||
172 | m_contactResults.Clear(); | ||
173 | } | ||
174 | |||
175 | // Return results | ||
176 | if (req.callbackMethod != null) | ||
177 | req.callbackMethod(hitYN, closestcontact, hitConsumerID, distance, snormal); | ||
178 | } | ||
179 | |||
180 | // This is the standard Near. Uses space AABBs to speed up detection. | ||
181 | private void near(IntPtr space, IntPtr g1, IntPtr g2) | ||
182 | { | ||
183 | |||
184 | //Don't test against heightfield Geom, or you'll be sorry! | ||
185 | |||
186 | /* | ||
187 | terminate called after throwing an instance of 'std::bad_alloc' | ||
188 | what(): std::bad_alloc | ||
189 | Stacktrace: | ||
190 | |||
191 | at (wrapper managed-to-native) Ode.NET.d.Collide (intptr,intptr,int,Ode.NET.d/ContactGeom[],int) <0x00004> | ||
192 | at (wrapper managed-to-native) Ode.NET.d.Collide (intptr,intptr,int,Ode.NET.d/ContactGeom[],int) <0xffffffff> | ||
193 | at OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.near (intptr,intptr,intptr) <0x00280> | ||
194 | at (wrapper native-to-managed) OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.near (intptr,intptr,intptr) <0xfff | ||
195 | fffff> | ||
196 | at (wrapper managed-to-native) Ode.NET.d.SpaceCollide2 (intptr,intptr,intptr,Ode.NET.d/NearCallback) <0x00004> | ||
197 | at (wrapper managed-to-native) Ode.NET.d.SpaceCollide2 (intptr,intptr,intptr,Ode.NET.d/NearCallback) <0xffffffff> | ||
198 | at OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.RayCast (OpenSim.Region.Physics.OdePlugin.ODERayCastRequest) < | ||
199 | 0x00114> | ||
200 | at OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.ProcessQueuedRequests () <0x000eb> | ||
201 | at OpenSim.Region.Physics.OdePlugin.OdeScene.Simulate (single) <0x017e6> | ||
202 | at OpenSim.Region.Framework.Scenes.SceneGraph.UpdatePhysics (double) <0x00042> | ||
203 | at OpenSim.Region.Framework.Scenes.Scene.Update () <0x0039e> | ||
204 | at OpenSim.Region.Framework.Scenes.Scene.Heartbeat (object) <0x00019> | ||
205 | at (wrapper runtime-invoke) object.runtime_invoke_void__this___object (object,intptr,intptr,intptr) <0xffffffff> | ||
206 | |||
207 | Native stacktrace: | ||
208 | |||
209 | mono [0x80d2a42] | ||
210 | [0xb7f5840c] | ||
211 | /lib/i686/cmov/libc.so.6(abort+0x188) [0xb7d1a018] | ||
212 | /usr/lib/libstdc++.so.6(_ZN9__gnu_cxx27__verbose_terminate_handlerEv+0x158) [0xb45fc988] | ||
213 | /usr/lib/libstdc++.so.6 [0xb45fa865] | ||
214 | /usr/lib/libstdc++.so.6 [0xb45fa8a2] | ||
215 | /usr/lib/libstdc++.so.6 [0xb45fa9da] | ||
216 | /usr/lib/libstdc++.so.6(_Znwj+0x83) [0xb45fb033] | ||
217 | /usr/lib/libstdc++.so.6(_Znaj+0x1d) [0xb45fb11d] | ||
218 | libode.so(_ZN13dxHeightfield23dCollideHeightfieldZoneEiiiiP6dxGeomiiP12dContactGeomi+0xd04) [0xb46678e4] | ||
219 | libode.so(_Z19dCollideHeightfieldP6dxGeomS0_iP12dContactGeomi+0x54b) [0xb466832b] | ||
220 | libode.so(dCollide+0x102) [0xb46571b2] | ||
221 | [0x95cfdec9] | ||
222 | [0x8ea07fe1] | ||
223 | [0xab260146] | ||
224 | libode.so [0xb465a5c4] | ||
225 | libode.so(_ZN11dxHashSpace8collide2EPvP6dxGeomPFvS0_S2_S2_E+0x75) [0xb465bcf5] | ||
226 | libode.so(dSpaceCollide2+0x177) [0xb465ac67] | ||
227 | [0x95cf978e] | ||
228 | [0x8ea07945] | ||
229 | [0x95cf2bbc] | ||
230 | [0xab2787e7] | ||
231 | [0xab419fb3] | ||
232 | [0xab416657] | ||
233 | [0xab415bda] | ||
234 | [0xb609b08e] | ||
235 | mono(mono_runtime_delegate_invoke+0x34) [0x8192534] | ||
236 | mono [0x81a2f0f] | ||
237 | mono [0x81d28b6] | ||
238 | mono [0x81ea2c6] | ||
239 | /lib/i686/cmov/libpthread.so.0 [0xb7e744c0] | ||
240 | /lib/i686/cmov/libc.so.6(clone+0x5e) [0xb7dcd6de] | ||
241 | */ | ||
242 | |||
243 | // Exclude heightfield geom | ||
244 | |||
245 | if (g1 == IntPtr.Zero || g2 == IntPtr.Zero) | ||
246 | return; | ||
247 | if (d.GeomGetClass(g1) == d.GeomClassID.HeightfieldClass || d.GeomGetClass(g2) == d.GeomClassID.HeightfieldClass) | ||
248 | return; | ||
249 | |||
250 | // Raytest against AABBs of spaces first, then dig into the spaces it hits for actual geoms. | ||
251 | if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2)) | ||
252 | { | ||
253 | if (g1 == IntPtr.Zero || g2 == IntPtr.Zero) | ||
254 | return; | ||
255 | |||
256 | // Separating static prim geometry spaces. | ||
257 | // We'll be calling near recursivly if one | ||
258 | // of them is a space to find all of the | ||
259 | // contact points in the space | ||
260 | try | ||
261 | { | ||
262 | d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback); | ||
263 | } | ||
264 | catch (AccessViolationException) | ||
265 | { | ||
266 | m_log.Warn("[PHYSICS]: Unable to collide test a space"); | ||
267 | return; | ||
268 | } | ||
269 | //Colliding a space or a geom with a space or a geom. so drill down | ||
270 | |||
271 | //Collide all geoms in each space.. | ||
272 | //if (d.GeomIsSpace(g1)) d.SpaceCollide(g1, IntPtr.Zero, nearCallback); | ||
273 | //if (d.GeomIsSpace(g2)) d.SpaceCollide(g2, IntPtr.Zero, nearCallback); | ||
274 | return; | ||
275 | } | ||
276 | |||
277 | if (g1 == IntPtr.Zero || g2 == IntPtr.Zero) | ||
278 | return; | ||
279 | |||
280 | int count = 0; | ||
281 | try | ||
282 | { | ||
283 | |||
284 | if (g1 == g2) | ||
285 | return; // Can't collide with yourself | ||
286 | |||
287 | lock (contacts) | ||
288 | { | ||
289 | count = d.Collide(g1, g2, contacts.GetLength(0), contacts, d.ContactGeom.SizeOf); | ||
290 | } | ||
291 | } | ||
292 | catch (SEHException) | ||
293 | { | ||
294 | m_log.Error("[PHYSICS]: The Operating system shut down ODE because of corrupt memory. This could be a result of really irregular terrain. If this repeats continuously, restart using Basic Physics and terrain fill your terrain. Restarting the sim."); | ||
295 | } | ||
296 | catch (Exception e) | ||
297 | { | ||
298 | m_log.WarnFormat("[PHYSICS]: Unable to collide test an object: {0}", e.Message); | ||
299 | return; | ||
300 | } | ||
301 | |||
302 | PhysicsActor p1 = null; | ||
303 | PhysicsActor p2 = null; | ||
304 | |||
305 | if (g1 != IntPtr.Zero) | ||
306 | m_scene.actor_name_map.TryGetValue(g1, out p1); | ||
307 | |||
308 | if (g2 != IntPtr.Zero) | ||
309 | m_scene.actor_name_map.TryGetValue(g1, out p2); | ||
310 | |||
311 | // Loop over contacts, build results. | ||
312 | for (int i = 0; i < count; i++) | ||
313 | { | ||
314 | if (p1 != null) { | ||
315 | if (p1 is OdePrim) | ||
316 | { | ||
317 | ContactResult collisionresult = new ContactResult(); | ||
318 | |||
319 | collisionresult.ConsumerID = ((OdePrim)p1).m_localID; | ||
320 | collisionresult.Pos = new Vector3(contacts[i].pos.X, contacts[i].pos.Y, contacts[i].pos.Z); | ||
321 | collisionresult.Depth = contacts[i].depth; | ||
322 | collisionresult.Normal = new Vector3(contacts[i].normal.X, contacts[i].normal.Y, | ||
323 | contacts[i].normal.Z); | ||
324 | lock (m_contactResults) | ||
325 | m_contactResults.Add(collisionresult); | ||
326 | } | ||
327 | } | ||
328 | |||
329 | if (p2 != null) | ||
330 | { | ||
331 | if (p2 is OdePrim) | ||
332 | { | ||
333 | ContactResult collisionresult = new ContactResult(); | ||
334 | |||
335 | collisionresult.ConsumerID = ((OdePrim)p2).m_localID; | ||
336 | collisionresult.Pos = new Vector3(contacts[i].pos.X, contacts[i].pos.Y, contacts[i].pos.Z); | ||
337 | collisionresult.Depth = contacts[i].depth; | ||
338 | collisionresult.Normal = new Vector3(contacts[i].normal.X, contacts[i].normal.Y, | ||
339 | contacts[i].normal.Z); | ||
340 | |||
341 | lock (m_contactResults) | ||
342 | m_contactResults.Add(collisionresult); | ||
343 | } | ||
344 | } | ||
345 | |||
346 | |||
347 | } | ||
348 | |||
349 | } | ||
350 | |||
351 | /// <summary> | ||
352 | /// Dereference the creator scene so that it can be garbage collected if needed. | ||
353 | /// </summary> | ||
354 | internal void Dispose() | ||
355 | { | ||
356 | m_scene = null; | ||
357 | } | ||
358 | } | ||
359 | |||
360 | public struct ODERayCastRequest | ||
361 | { | ||
362 | public Vector3 Origin; | ||
363 | public Vector3 Normal; | ||
364 | public float length; | ||
365 | public RaycastCallback callbackMethod; | ||
366 | } | ||
367 | |||
368 | public struct ContactResult | ||
369 | { | ||
370 | public Vector3 Pos; | ||
371 | public float Depth; | ||
372 | public uint ConsumerID; | ||
373 | public Vector3 Normal; | ||
374 | } | ||
375 | } | ||
diff --git a/OpenSim/Region/Physics/ChOdePlugin/OdePhysicsJoint.cs b/OpenSim/Region/Physics/ChOdePlugin/OdePhysicsJoint.cs new file mode 100644 index 0000000..b4a3c48 --- /dev/null +++ b/OpenSim/Region/Physics/ChOdePlugin/OdePhysicsJoint.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 | */ | ||
27 | |||
28 | using System; | ||
29 | using OpenMetaverse; | ||
30 | using Ode.NET; | ||
31 | using OpenSim.Framework; | ||
32 | using OpenSim.Region.Physics.Manager; | ||
33 | using OpenSim.Region.Physics.OdePlugin; | ||
34 | |||
35 | namespace OpenSim.Region.Physics.OdePlugin | ||
36 | { | ||
37 | class OdePhysicsJoint : PhysicsJoint | ||
38 | { | ||
39 | public override bool IsInPhysicsEngine | ||
40 | { | ||
41 | get | ||
42 | { | ||
43 | return (jointID != IntPtr.Zero); | ||
44 | } | ||
45 | } | ||
46 | public IntPtr jointID; | ||
47 | } | ||
48 | } | ||
diff --git a/OpenSim/Region/Physics/ChOdePlugin/OdePlugin.cs b/OpenSim/Region/Physics/ChOdePlugin/OdePlugin.cs new file mode 100644 index 0000000..60786d4 --- /dev/null +++ b/OpenSim/Region/Physics/ChOdePlugin/OdePlugin.cs | |||
@@ -0,0 +1,3874 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | //#define USE_DRAWSTUFF | ||
29 | |||
30 | using System; | ||
31 | using System.Collections.Generic; | ||
32 | using System.Reflection; | ||
33 | using System.Runtime.InteropServices; | ||
34 | using System.Threading; | ||
35 | using System.IO; | ||
36 | using System.Diagnostics; | ||
37 | using log4net; | ||
38 | using Nini.Config; | ||
39 | using Ode.NET; | ||
40 | #if USE_DRAWSTUFF | ||
41 | using Drawstuff.NET; | ||
42 | #endif | ||
43 | using OpenSim.Framework; | ||
44 | using OpenSim.Region.Physics.Manager; | ||
45 | using OpenMetaverse; | ||
46 | |||
47 | //using OpenSim.Region.Physics.OdePlugin.Meshing; | ||
48 | |||
49 | namespace OpenSim.Region.Physics.OdePlugin | ||
50 | { | ||
51 | /// <summary> | ||
52 | /// ODE plugin | ||
53 | /// </summary> | ||
54 | public class OdePlugin : IPhysicsPlugin | ||
55 | { | ||
56 | //private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); | ||
57 | |||
58 | private CollisionLocker ode; | ||
59 | private OdeScene _mScene; | ||
60 | |||
61 | public OdePlugin() | ||
62 | { | ||
63 | ode = new CollisionLocker(); | ||
64 | } | ||
65 | |||
66 | public bool Init() | ||
67 | { | ||
68 | return true; | ||
69 | } | ||
70 | |||
71 | public PhysicsScene GetScene(String sceneIdentifier) | ||
72 | { | ||
73 | if (_mScene == null) | ||
74 | { | ||
75 | // Initializing ODE only when a scene is created allows alternative ODE plugins to co-habit (according to | ||
76 | // http://opensimulator.org/mantis/view.php?id=2750). | ||
77 | d.InitODE(); | ||
78 | |||
79 | _mScene = new OdeScene(ode, sceneIdentifier); | ||
80 | } | ||
81 | return (_mScene); | ||
82 | } | ||
83 | |||
84 | public string GetName() | ||
85 | { | ||
86 | return ("ChODE"); | ||
87 | } | ||
88 | |||
89 | public void Dispose() | ||
90 | { | ||
91 | } | ||
92 | } | ||
93 | |||
94 | public enum StatusIndicators : int | ||
95 | { | ||
96 | Generic = 0, | ||
97 | Start = 1, | ||
98 | End = 2 | ||
99 | } | ||
100 | |||
101 | public struct sCollisionData | ||
102 | { | ||
103 | public uint ColliderLocalId; | ||
104 | public uint CollidedWithLocalId; | ||
105 | public int NumberOfCollisions; | ||
106 | public int CollisionType; | ||
107 | public int StatusIndicator; | ||
108 | public int lastframe; | ||
109 | } | ||
110 | |||
111 | [Flags] | ||
112 | public enum CollisionCategories : int | ||
113 | { | ||
114 | Disabled = 0, | ||
115 | Geom = 0x00000001, | ||
116 | Body = 0x00000002, | ||
117 | Space = 0x00000004, | ||
118 | Character = 0x00000008, | ||
119 | Land = 0x00000010, | ||
120 | Water = 0x00000020, | ||
121 | Wind = 0x00000040, | ||
122 | Sensor = 0x00000080, | ||
123 | Selected = 0x00000100 | ||
124 | } | ||
125 | |||
126 | /// <summary> | ||
127 | /// Material type for a primitive | ||
128 | /// </summary> | ||
129 | public enum Material : int | ||
130 | { | ||
131 | /// <summary></summary> | ||
132 | Stone = 0, | ||
133 | /// <summary></summary> | ||
134 | Metal = 1, | ||
135 | /// <summary></summary> | ||
136 | Glass = 2, | ||
137 | /// <summary></summary> | ||
138 | Wood = 3, | ||
139 | /// <summary></summary> | ||
140 | Flesh = 4, | ||
141 | /// <summary></summary> | ||
142 | Plastic = 5, | ||
143 | /// <summary></summary> | ||
144 | Rubber = 6 | ||
145 | |||
146 | } | ||
147 | |||
148 | public sealed class OdeScene : PhysicsScene | ||
149 | { | ||
150 | private readonly ILog m_log; | ||
151 | // private Dictionary<string, sCollisionData> m_storedCollisions = new Dictionary<string, sCollisionData>(); | ||
152 | |||
153 | CollisionLocker ode; | ||
154 | |||
155 | private Random fluidRandomizer = new Random(Environment.TickCount); | ||
156 | |||
157 | private const uint m_regionWidth = Constants.RegionSize; | ||
158 | private const uint m_regionHeight = Constants.RegionSize; | ||
159 | |||
160 | private float ODE_STEPSIZE = 0.020f; | ||
161 | private float metersInSpace = 29.9f; | ||
162 | private float m_timeDilation = 1.0f; | ||
163 | |||
164 | public float gravityx = 0f; | ||
165 | public float gravityy = 0f; | ||
166 | public float gravityz = -9.8f; | ||
167 | |||
168 | private float contactsurfacelayer = 0.001f; | ||
169 | |||
170 | private int worldHashspaceLow = -4; | ||
171 | private int worldHashspaceHigh = 128; | ||
172 | |||
173 | private int smallHashspaceLow = -4; | ||
174 | private int smallHashspaceHigh = 66; | ||
175 | |||
176 | private float waterlevel = 0f; | ||
177 | private int framecount = 0; | ||
178 | //private int m_returncollisions = 10; | ||
179 | |||
180 | private readonly IntPtr contactgroup; | ||
181 | |||
182 | internal IntPtr LandGeom; | ||
183 | internal IntPtr WaterGeom; | ||
184 | |||
185 | private float nmTerrainContactFriction = 255.0f; | ||
186 | private float nmTerrainContactBounce = 0.1f; | ||
187 | private float nmTerrainContactERP = 0.1025f; | ||
188 | |||
189 | private float mTerrainContactFriction = 75f; | ||
190 | private float mTerrainContactBounce = 0.1f; | ||
191 | private float mTerrainContactERP = 0.05025f; | ||
192 | |||
193 | private float nmAvatarObjectContactFriction = 250f; | ||
194 | private float nmAvatarObjectContactBounce = 0.1f; | ||
195 | |||
196 | private float mAvatarObjectContactFriction = 75f; | ||
197 | private float mAvatarObjectContactBounce = 0.1f; | ||
198 | |||
199 | private float avPIDD = 3200f; | ||
200 | private float avPIDP = 1400f; | ||
201 | private float avCapRadius = 0.37f; | ||
202 | private float avStandupTensor = 2000000f; | ||
203 | private bool avCapsuleTilted = true; // true = old compatibility mode with leaning capsule; false = new corrected mode | ||
204 | public bool IsAvCapsuleTilted { get { return avCapsuleTilted; } set { avCapsuleTilted = value; } } | ||
205 | private float avDensity = 80f; | ||
206 | private float avHeightFudgeFactor = 0.52f; | ||
207 | private float avMovementDivisorWalk = 1.3f; | ||
208 | private float avMovementDivisorRun = 0.8f; | ||
209 | private float minimumGroundFlightOffset = 3f; | ||
210 | public float maximumMassObject = 10000.01f; | ||
211 | |||
212 | public bool meshSculptedPrim = true; | ||
213 | public bool forceSimplePrimMeshing = false; | ||
214 | |||
215 | public float meshSculptLOD = 32; | ||
216 | public float MeshSculptphysicalLOD = 16; | ||
217 | |||
218 | public float geomDefaultDensity = 10.000006836f; | ||
219 | |||
220 | public int geomContactPointsStartthrottle = 3; | ||
221 | public int geomUpdatesPerThrottledUpdate = 15; | ||
222 | |||
223 | public float bodyPIDD = 35f; | ||
224 | public float bodyPIDG = 25; | ||
225 | |||
226 | public int geomCrossingFailuresBeforeOutofbounds = 5; | ||
227 | |||
228 | public float bodyMotorJointMaxforceTensor = 2; | ||
229 | |||
230 | public int bodyFramesAutoDisable = 20; | ||
231 | |||
232 | protected DateTime m_lastframe = DateTime.UtcNow; | ||
233 | |||
234 | private float[] _watermap; | ||
235 | private bool m_filterCollisions = true; | ||
236 | |||
237 | private d.NearCallback nearCallback; | ||
238 | public d.TriCallback triCallback; | ||
239 | public d.TriArrayCallback triArrayCallback; | ||
240 | private readonly HashSet<OdeCharacter> _characters = new HashSet<OdeCharacter>(); | ||
241 | private readonly HashSet<OdePrim> _prims = new HashSet<OdePrim>(); | ||
242 | private readonly HashSet<OdePrim> _activeprims = new HashSet<OdePrim>(); | ||
243 | private readonly HashSet<OdePrim> _taintedPrimH = new HashSet<OdePrim>(); | ||
244 | private readonly Object _taintedPrimLock = new Object(); | ||
245 | private readonly List<OdePrim> _taintedPrimL = new List<OdePrim>(); | ||
246 | private readonly HashSet<OdeCharacter> _taintedActors = new HashSet<OdeCharacter>(); | ||
247 | private readonly List<d.ContactGeom> _perloopContact = new List<d.ContactGeom>(); | ||
248 | private readonly List<PhysicsActor> _collisionEventPrim = new List<PhysicsActor>(); | ||
249 | private readonly HashSet<OdeCharacter> _badCharacter = new HashSet<OdeCharacter>(); | ||
250 | public Dictionary<IntPtr, String> geom_name_map = new Dictionary<IntPtr, String>(); | ||
251 | public Dictionary<IntPtr, PhysicsActor> actor_name_map = new Dictionary<IntPtr, PhysicsActor>(); | ||
252 | private bool m_NINJA_physics_joints_enabled = false; | ||
253 | //private Dictionary<String, IntPtr> jointpart_name_map = new Dictionary<String,IntPtr>(); | ||
254 | private readonly Dictionary<String, List<PhysicsJoint>> joints_connecting_actor = new Dictionary<String, List<PhysicsJoint>>(); | ||
255 | private d.ContactGeom[] contacts; | ||
256 | private readonly List<PhysicsJoint> requestedJointsToBeCreated = new List<PhysicsJoint>(); // lock only briefly. accessed by external code (to request new joints) and by OdeScene.Simulate() to move those joints into pending/active | ||
257 | private readonly List<PhysicsJoint> pendingJoints = new List<PhysicsJoint>(); // can lock for longer. accessed only by OdeScene. | ||
258 | private readonly List<PhysicsJoint> activeJoints = new List<PhysicsJoint>(); // can lock for longer. accessed only by OdeScene. | ||
259 | private readonly List<string> requestedJointsToBeDeleted = new List<string>(); // lock only briefly. accessed by external code (to request deletion of joints) and by OdeScene.Simulate() to move those joints out of pending/active | ||
260 | private Object externalJointRequestsLock = new Object(); | ||
261 | private readonly Dictionary<String, PhysicsJoint> SOPName_to_activeJoint = new Dictionary<String, PhysicsJoint>(); | ||
262 | private readonly Dictionary<String, PhysicsJoint> SOPName_to_pendingJoint = new Dictionary<String, PhysicsJoint>(); | ||
263 | private readonly DoubleDictionary<Vector3, IntPtr, IntPtr> RegionTerrain = new DoubleDictionary<Vector3, IntPtr, IntPtr>(); | ||
264 | private readonly Dictionary<IntPtr,float[]> TerrainHeightFieldHeights = new Dictionary<IntPtr, float[]>(); | ||
265 | |||
266 | private d.Contact contact; | ||
267 | private d.Contact TerrainContact; | ||
268 | private d.Contact AvatarMovementprimContact; | ||
269 | private d.Contact AvatarMovementTerrainContact; | ||
270 | private d.Contact WaterContact; | ||
271 | private d.Contact[,] m_materialContacts; | ||
272 | |||
273 | //Ckrinke: Comment out until used. We declare it, initialize it, but do not use it | ||
274 | //Ckrinke private int m_randomizeWater = 200; | ||
275 | private int m_physicsiterations = 10; | ||
276 | private const float m_SkipFramesAtms = 0.40f; // Drop frames gracefully at a 400 ms lag | ||
277 | private readonly PhysicsActor PANull = new NullPhysicsActor(); | ||
278 | private float step_time = 0.0f; | ||
279 | //Ckrinke: Comment out until used. We declare it, initialize it, but do not use it | ||
280 | //Ckrinke private int ms = 0; | ||
281 | public IntPtr world; | ||
282 | //private bool returncollisions = false; | ||
283 | // private uint obj1LocalID = 0; | ||
284 | private uint obj2LocalID = 0; | ||
285 | //private int ctype = 0; | ||
286 | private OdeCharacter cc1; | ||
287 | private OdePrim cp1; | ||
288 | private OdeCharacter cc2; | ||
289 | private OdePrim cp2; | ||
290 | //private int cStartStop = 0; | ||
291 | //private string cDictKey = ""; | ||
292 | |||
293 | public IntPtr space; | ||
294 | |||
295 | //private IntPtr tmpSpace; | ||
296 | // split static geometry collision handling into spaces of 30 meters | ||
297 | public IntPtr[,] staticPrimspace; | ||
298 | |||
299 | public Object OdeLock; | ||
300 | |||
301 | public IMesher mesher; | ||
302 | |||
303 | private IConfigSource m_config; | ||
304 | |||
305 | public bool physics_logging = false; | ||
306 | public int physics_logging_interval = 0; | ||
307 | public bool physics_logging_append_existing_logfile = false; | ||
308 | |||
309 | public d.Vector3 xyz = new d.Vector3(128.1640f, 128.3079f, 25.7600f); | ||
310 | public d.Vector3 hpr = new d.Vector3(125.5000f, -17.0000f, 0.0000f); | ||
311 | |||
312 | // TODO: unused: private uint heightmapWidth = m_regionWidth + 1; | ||
313 | // TODO: unused: private uint heightmapHeight = m_regionHeight + 1; | ||
314 | // TODO: unused: private uint heightmapWidthSamples; | ||
315 | // TODO: unused: private uint heightmapHeightSamples; | ||
316 | |||
317 | private volatile int m_global_contactcount = 0; | ||
318 | |||
319 | private Vector3 m_worldOffset = Vector3.Zero; | ||
320 | public Vector2 WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize); | ||
321 | private PhysicsScene m_parentScene = null; | ||
322 | |||
323 | private ODERayCastRequestManager m_rayCastManager; | ||
324 | |||
325 | /// <summary> | ||
326 | /// Initiailizes the scene | ||
327 | /// Sets many properties that ODE requires to be stable | ||
328 | /// These settings need to be tweaked 'exactly' right or weird stuff happens. | ||
329 | /// </summary> | ||
330 | public OdeScene(CollisionLocker dode, string sceneIdentifier) | ||
331 | { | ||
332 | m_log | ||
333 | = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType.ToString() + "." + sceneIdentifier); | ||
334 | |||
335 | OdeLock = new Object(); | ||
336 | ode = dode; | ||
337 | nearCallback = near; | ||
338 | triCallback = TriCallback; | ||
339 | triArrayCallback = TriArrayCallback; | ||
340 | m_rayCastManager = new ODERayCastRequestManager(this); | ||
341 | lock (OdeLock) | ||
342 | { | ||
343 | // Create the world and the first space | ||
344 | world = d.WorldCreate(); | ||
345 | space = d.HashSpaceCreate(IntPtr.Zero); | ||
346 | |||
347 | |||
348 | contactgroup = d.JointGroupCreate(0); | ||
349 | //contactgroup | ||
350 | |||
351 | d.WorldSetAutoDisableFlag(world, false); | ||
352 | #if USE_DRAWSTUFF | ||
353 | |||
354 | Thread viewthread = new Thread(new ParameterizedThreadStart(startvisualization)); | ||
355 | viewthread.Start(); | ||
356 | #endif | ||
357 | } | ||
358 | |||
359 | |||
360 | _watermap = new float[258 * 258]; | ||
361 | |||
362 | // Zero out the prim spaces array (we split our space into smaller spaces so | ||
363 | // we can hit test less. | ||
364 | } | ||
365 | |||
366 | #if USE_DRAWSTUFF | ||
367 | public void startvisualization(object o) | ||
368 | { | ||
369 | ds.Functions fn; | ||
370 | fn.version = ds.VERSION; | ||
371 | fn.start = new ds.CallbackFunction(start); | ||
372 | fn.step = new ds.CallbackFunction(step); | ||
373 | fn.command = new ds.CallbackFunction(command); | ||
374 | fn.stop = null; | ||
375 | fn.path_to_textures = "./textures"; | ||
376 | string[] args = new string[0]; | ||
377 | ds.SimulationLoop(args.Length, args, 352, 288, ref fn); | ||
378 | } | ||
379 | #endif | ||
380 | |||
381 | // Initialize the mesh plugin | ||
382 | public override void Initialise(IMesher meshmerizer, IConfigSource config) | ||
383 | { | ||
384 | mesher = meshmerizer; | ||
385 | m_config = config; | ||
386 | // Defaults | ||
387 | |||
388 | if (Environment.OSVersion.Platform == PlatformID.Unix) | ||
389 | { | ||
390 | avPIDD = 3200.0f; | ||
391 | avPIDP = 1400.0f; | ||
392 | avStandupTensor = 2000000f; | ||
393 | } | ||
394 | else | ||
395 | { | ||
396 | avPIDD = 2200.0f; | ||
397 | avPIDP = 900.0f; | ||
398 | avStandupTensor = 550000f; | ||
399 | } | ||
400 | |||
401 | int contactsPerCollision = 80; | ||
402 | |||
403 | if (m_config != null) | ||
404 | { | ||
405 | IConfig physicsconfig = m_config.Configs["ODEPhysicsSettings"]; | ||
406 | if (physicsconfig != null) | ||
407 | { | ||
408 | gravityx = physicsconfig.GetFloat("world_gravityx", 0f); | ||
409 | gravityy = physicsconfig.GetFloat("world_gravityy", 0f); | ||
410 | gravityz = physicsconfig.GetFloat("world_gravityz", -9.8f); | ||
411 | |||
412 | worldHashspaceLow = physicsconfig.GetInt("world_hashspace_size_low", -4); | ||
413 | worldHashspaceHigh = physicsconfig.GetInt("world_hashspace_size_high", 128); | ||
414 | |||
415 | metersInSpace = physicsconfig.GetFloat("meters_in_small_space", 29.9f); | ||
416 | smallHashspaceLow = physicsconfig.GetInt("small_hashspace_size_low", -4); | ||
417 | smallHashspaceHigh = physicsconfig.GetInt("small_hashspace_size_high", 66); | ||
418 | |||
419 | contactsurfacelayer = physicsconfig.GetFloat("world_contact_surface_layer", 0.001f); | ||
420 | |||
421 | nmTerrainContactFriction = physicsconfig.GetFloat("nm_terraincontact_friction", 255.0f); | ||
422 | nmTerrainContactBounce = physicsconfig.GetFloat("nm_terraincontact_bounce", 0.1f); | ||
423 | nmTerrainContactERP = physicsconfig.GetFloat("nm_terraincontact_erp", 0.1025f); | ||
424 | |||
425 | mTerrainContactFriction = physicsconfig.GetFloat("m_terraincontact_friction", 75f); | ||
426 | mTerrainContactBounce = physicsconfig.GetFloat("m_terraincontact_bounce", 0.05f); | ||
427 | mTerrainContactERP = physicsconfig.GetFloat("m_terraincontact_erp", 0.05025f); | ||
428 | |||
429 | nmAvatarObjectContactFriction = physicsconfig.GetFloat("objectcontact_friction", 250f); | ||
430 | nmAvatarObjectContactBounce = physicsconfig.GetFloat("objectcontact_bounce", 0.2f); | ||
431 | |||
432 | mAvatarObjectContactFriction = physicsconfig.GetFloat("m_avatarobjectcontact_friction", 75f); | ||
433 | mAvatarObjectContactBounce = physicsconfig.GetFloat("m_avatarobjectcontact_bounce", 0.1f); | ||
434 | |||
435 | ODE_STEPSIZE = physicsconfig.GetFloat("world_stepsize", 0.020f); | ||
436 | m_physicsiterations = physicsconfig.GetInt("world_internal_steps_without_collisions", 10); | ||
437 | |||
438 | avDensity = physicsconfig.GetFloat("av_density", 80f); | ||
439 | avHeightFudgeFactor = physicsconfig.GetFloat("av_height_fudge_factor", 0.52f); | ||
440 | avMovementDivisorWalk = physicsconfig.GetFloat("av_movement_divisor_walk", 1.3f); | ||
441 | avMovementDivisorRun = physicsconfig.GetFloat("av_movement_divisor_run", 0.8f); | ||
442 | avCapRadius = physicsconfig.GetFloat("av_capsule_radius", 0.37f); | ||
443 | avCapsuleTilted = physicsconfig.GetBoolean("av_capsule_tilted", false); | ||
444 | |||
445 | contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", 80); | ||
446 | |||
447 | geomContactPointsStartthrottle = physicsconfig.GetInt("geom_contactpoints_start_throttling", 3); | ||
448 | geomUpdatesPerThrottledUpdate = physicsconfig.GetInt("geom_updates_before_throttled_update", 15); | ||
449 | geomCrossingFailuresBeforeOutofbounds = physicsconfig.GetInt("geom_crossing_failures_before_outofbounds", 5); | ||
450 | |||
451 | geomDefaultDensity = physicsconfig.GetFloat("geometry_default_density", 10.000006836f); | ||
452 | bodyFramesAutoDisable = physicsconfig.GetInt("body_frames_auto_disable", 20); | ||
453 | |||
454 | bodyPIDD = physicsconfig.GetFloat("body_pid_derivative", 35f); | ||
455 | bodyPIDG = physicsconfig.GetFloat("body_pid_gain", 25f); | ||
456 | |||
457 | forceSimplePrimMeshing = physicsconfig.GetBoolean("force_simple_prim_meshing", forceSimplePrimMeshing); | ||
458 | meshSculptedPrim = physicsconfig.GetBoolean("mesh_sculpted_prim", true); | ||
459 | meshSculptLOD = physicsconfig.GetFloat("mesh_lod", 32f); | ||
460 | MeshSculptphysicalLOD = physicsconfig.GetFloat("mesh_physical_lod", 16f); | ||
461 | m_filterCollisions = physicsconfig.GetBoolean("filter_collisions", false); | ||
462 | |||
463 | if (Environment.OSVersion.Platform == PlatformID.Unix) | ||
464 | { | ||
465 | avPIDD = physicsconfig.GetFloat("av_pid_derivative_linux", 2200.0f); | ||
466 | avPIDP = physicsconfig.GetFloat("av_pid_proportional_linux", 900.0f); | ||
467 | avStandupTensor = physicsconfig.GetFloat("av_capsule_standup_tensor_linux", 550000f); | ||
468 | bodyMotorJointMaxforceTensor = physicsconfig.GetFloat("body_motor_joint_maxforce_tensor_linux", 5f); | ||
469 | } | ||
470 | else | ||
471 | { | ||
472 | avPIDD = physicsconfig.GetFloat("av_pid_derivative_win", 2200.0f); | ||
473 | avPIDP = physicsconfig.GetFloat("av_pid_proportional_win", 900.0f); | ||
474 | avStandupTensor = physicsconfig.GetFloat("av_capsule_standup_tensor_win", 550000f); | ||
475 | bodyMotorJointMaxforceTensor = physicsconfig.GetFloat("body_motor_joint_maxforce_tensor_win", 5f); | ||
476 | } | ||
477 | |||
478 | physics_logging = physicsconfig.GetBoolean("physics_logging", false); | ||
479 | physics_logging_interval = physicsconfig.GetInt("physics_logging_interval", 0); | ||
480 | physics_logging_append_existing_logfile = physicsconfig.GetBoolean("physics_logging_append_existing_logfile", false); | ||
481 | |||
482 | m_NINJA_physics_joints_enabled = physicsconfig.GetBoolean("use_NINJA_physics_joints", false); | ||
483 | minimumGroundFlightOffset = physicsconfig.GetFloat("minimum_ground_flight_offset", 3f); | ||
484 | maximumMassObject = physicsconfig.GetFloat("maximum_mass_object", 10000.01f); | ||
485 | } | ||
486 | } | ||
487 | |||
488 | contacts = new d.ContactGeom[contactsPerCollision]; | ||
489 | |||
490 | staticPrimspace = new IntPtr[(int)(300 / metersInSpace), (int)(300 / metersInSpace)]; | ||
491 | |||
492 | // Centeral contact friction and bounce | ||
493 | // ckrinke 11/10/08 Enabling soft_erp but not soft_cfm until I figure out why | ||
494 | // an avatar falls through in Z but not in X or Y when walking on a prim. | ||
495 | contact.surface.mode |= d.ContactFlags.SoftERP; | ||
496 | contact.surface.mu = nmAvatarObjectContactFriction; | ||
497 | contact.surface.bounce = nmAvatarObjectContactBounce; | ||
498 | contact.surface.soft_cfm = 0.010f; | ||
499 | contact.surface.soft_erp = 0.010f; | ||
500 | |||
501 | // Terrain contact friction and Bounce | ||
502 | // This is the *non* moving version. Use this when an avatar | ||
503 | // isn't moving to keep it in place better | ||
504 | TerrainContact.surface.mode |= d.ContactFlags.SoftERP; | ||
505 | TerrainContact.surface.mu = nmTerrainContactFriction; | ||
506 | TerrainContact.surface.bounce = nmTerrainContactBounce; | ||
507 | TerrainContact.surface.soft_erp = nmTerrainContactERP; | ||
508 | |||
509 | WaterContact.surface.mode |= (d.ContactFlags.SoftERP | d.ContactFlags.SoftCFM); | ||
510 | WaterContact.surface.mu = 0f; // No friction | ||
511 | WaterContact.surface.bounce = 0.0f; // No bounce | ||
512 | WaterContact.surface.soft_cfm = 0.010f; | ||
513 | WaterContact.surface.soft_erp = 0.010f; | ||
514 | |||
515 | // Prim contact friction and bounce | ||
516 | // THis is the *non* moving version of friction and bounce | ||
517 | // Use this when an avatar comes in contact with a prim | ||
518 | // and is moving | ||
519 | AvatarMovementprimContact.surface.mu = mAvatarObjectContactFriction; | ||
520 | AvatarMovementprimContact.surface.bounce = mAvatarObjectContactBounce; | ||
521 | |||
522 | // Terrain contact friction bounce and various error correcting calculations | ||
523 | // Use this when an avatar is in contact with the terrain and moving. | ||
524 | AvatarMovementTerrainContact.surface.mode |= d.ContactFlags.SoftERP; | ||
525 | AvatarMovementTerrainContact.surface.mu = mTerrainContactFriction; | ||
526 | AvatarMovementTerrainContact.surface.bounce = mTerrainContactBounce; | ||
527 | AvatarMovementTerrainContact.surface.soft_erp = mTerrainContactERP; | ||
528 | |||
529 | |||
530 | /* | ||
531 | <summary></summary> | ||
532 | Stone = 0, | ||
533 | /// <summary></summary> | ||
534 | Metal = 1, | ||
535 | /// <summary></summary> | ||
536 | Glass = 2, | ||
537 | /// <summary></summary> | ||
538 | Wood = 3, | ||
539 | /// <summary></summary> | ||
540 | Flesh = 4, | ||
541 | /// <summary></summary> | ||
542 | Plastic = 5, | ||
543 | /// <summary></summary> | ||
544 | Rubber = 6 | ||
545 | */ | ||
546 | |||
547 | m_materialContacts = new d.Contact[7,2]; | ||
548 | |||
549 | m_materialContacts[(int)Material.Stone, 0] = new d.Contact(); | ||
550 | m_materialContacts[(int)Material.Stone, 0].surface.mode |= d.ContactFlags.SoftERP; | ||
551 | m_materialContacts[(int)Material.Stone, 0].surface.mu = nmAvatarObjectContactFriction; | ||
552 | m_materialContacts[(int)Material.Stone, 0].surface.bounce = nmAvatarObjectContactBounce; | ||
553 | m_materialContacts[(int)Material.Stone, 0].surface.soft_cfm = 0.010f; | ||
554 | m_materialContacts[(int)Material.Stone, 0].surface.soft_erp = 0.010f; | ||
555 | |||
556 | m_materialContacts[(int)Material.Stone, 1] = new d.Contact(); | ||
557 | m_materialContacts[(int)Material.Stone, 1].surface.mode |= d.ContactFlags.SoftERP; | ||
558 | m_materialContacts[(int)Material.Stone, 1].surface.mu = mAvatarObjectContactFriction; | ||
559 | m_materialContacts[(int)Material.Stone, 1].surface.bounce = mAvatarObjectContactBounce; | ||
560 | m_materialContacts[(int)Material.Stone, 1].surface.soft_cfm = 0.010f; | ||
561 | m_materialContacts[(int)Material.Stone, 1].surface.soft_erp = 0.010f; | ||
562 | |||
563 | m_materialContacts[(int)Material.Metal, 0] = new d.Contact(); | ||
564 | m_materialContacts[(int)Material.Metal, 0].surface.mode |= d.ContactFlags.SoftERP; | ||
565 | m_materialContacts[(int)Material.Metal, 0].surface.mu = nmAvatarObjectContactFriction; | ||
566 | m_materialContacts[(int)Material.Metal, 0].surface.bounce = nmAvatarObjectContactBounce; | ||
567 | m_materialContacts[(int)Material.Metal, 0].surface.soft_cfm = 0.010f; | ||
568 | m_materialContacts[(int)Material.Metal, 0].surface.soft_erp = 0.010f; | ||
569 | |||
570 | m_materialContacts[(int)Material.Metal, 1] = new d.Contact(); | ||
571 | m_materialContacts[(int)Material.Metal, 1].surface.mode |= d.ContactFlags.SoftERP; | ||
572 | m_materialContacts[(int)Material.Metal, 1].surface.mu = mAvatarObjectContactFriction; | ||
573 | m_materialContacts[(int)Material.Metal, 1].surface.bounce = mAvatarObjectContactBounce; | ||
574 | m_materialContacts[(int)Material.Metal, 1].surface.soft_cfm = 0.010f; | ||
575 | m_materialContacts[(int)Material.Metal, 1].surface.soft_erp = 0.010f; | ||
576 | |||
577 | m_materialContacts[(int)Material.Glass, 0] = new d.Contact(); | ||
578 | m_materialContacts[(int)Material.Glass, 0].surface.mode |= d.ContactFlags.SoftERP; | ||
579 | m_materialContacts[(int)Material.Glass, 0].surface.mu = 1f; | ||
580 | m_materialContacts[(int)Material.Glass, 0].surface.bounce = 0.5f; | ||
581 | m_materialContacts[(int)Material.Glass, 0].surface.soft_cfm = 0.010f; | ||
582 | m_materialContacts[(int)Material.Glass, 0].surface.soft_erp = 0.010f; | ||
583 | |||
584 | /* | ||
585 | private float nmAvatarObjectContactFriction = 250f; | ||
586 | private float nmAvatarObjectContactBounce = 0.1f; | ||
587 | |||
588 | private float mAvatarObjectContactFriction = 75f; | ||
589 | private float mAvatarObjectContactBounce = 0.1f; | ||
590 | */ | ||
591 | m_materialContacts[(int)Material.Glass, 1] = new d.Contact(); | ||
592 | m_materialContacts[(int)Material.Glass, 1].surface.mode |= d.ContactFlags.SoftERP; | ||
593 | m_materialContacts[(int)Material.Glass, 1].surface.mu = 1f; | ||
594 | m_materialContacts[(int)Material.Glass, 1].surface.bounce = 0.5f; | ||
595 | m_materialContacts[(int)Material.Glass, 1].surface.soft_cfm = 0.010f; | ||
596 | m_materialContacts[(int)Material.Glass, 1].surface.soft_erp = 0.010f; | ||
597 | |||
598 | m_materialContacts[(int)Material.Wood, 0] = new d.Contact(); | ||
599 | m_materialContacts[(int)Material.Wood, 0].surface.mode |= d.ContactFlags.SoftERP; | ||
600 | m_materialContacts[(int)Material.Wood, 0].surface.mu = nmAvatarObjectContactFriction; | ||
601 | m_materialContacts[(int)Material.Wood, 0].surface.bounce = nmAvatarObjectContactBounce; | ||
602 | m_materialContacts[(int)Material.Wood, 0].surface.soft_cfm = 0.010f; | ||
603 | m_materialContacts[(int)Material.Wood, 0].surface.soft_erp = 0.010f; | ||
604 | |||
605 | m_materialContacts[(int)Material.Wood, 1] = new d.Contact(); | ||
606 | m_materialContacts[(int)Material.Wood, 1].surface.mode |= d.ContactFlags.SoftERP; | ||
607 | m_materialContacts[(int)Material.Wood, 1].surface.mu = mAvatarObjectContactFriction; | ||
608 | m_materialContacts[(int)Material.Wood, 1].surface.bounce = mAvatarObjectContactBounce; | ||
609 | m_materialContacts[(int)Material.Wood, 1].surface.soft_cfm = 0.010f; | ||
610 | m_materialContacts[(int)Material.Wood, 1].surface.soft_erp = 0.010f; | ||
611 | |||
612 | m_materialContacts[(int)Material.Flesh, 0] = new d.Contact(); | ||
613 | m_materialContacts[(int)Material.Flesh, 0].surface.mode |= d.ContactFlags.SoftERP; | ||
614 | m_materialContacts[(int)Material.Flesh, 0].surface.mu = nmAvatarObjectContactFriction; | ||
615 | m_materialContacts[(int)Material.Flesh, 0].surface.bounce = nmAvatarObjectContactBounce; | ||
616 | m_materialContacts[(int)Material.Flesh, 0].surface.soft_cfm = 0.010f; | ||
617 | m_materialContacts[(int)Material.Flesh, 0].surface.soft_erp = 0.010f; | ||
618 | |||
619 | m_materialContacts[(int)Material.Flesh, 1] = new d.Contact(); | ||
620 | m_materialContacts[(int)Material.Flesh, 1].surface.mode |= d.ContactFlags.SoftERP; | ||
621 | m_materialContacts[(int)Material.Flesh, 1].surface.mu = mAvatarObjectContactFriction; | ||
622 | m_materialContacts[(int)Material.Flesh, 1].surface.bounce = mAvatarObjectContactBounce; | ||
623 | m_materialContacts[(int)Material.Flesh, 1].surface.soft_cfm = 0.010f; | ||
624 | m_materialContacts[(int)Material.Flesh, 1].surface.soft_erp = 0.010f; | ||
625 | |||
626 | m_materialContacts[(int)Material.Plastic, 0] = new d.Contact(); | ||
627 | m_materialContacts[(int)Material.Plastic, 0].surface.mode |= d.ContactFlags.SoftERP; | ||
628 | m_materialContacts[(int)Material.Plastic, 0].surface.mu = nmAvatarObjectContactFriction; | ||
629 | m_materialContacts[(int)Material.Plastic, 0].surface.bounce = nmAvatarObjectContactBounce; | ||
630 | m_materialContacts[(int)Material.Plastic, 0].surface.soft_cfm = 0.010f; | ||
631 | m_materialContacts[(int)Material.Plastic, 0].surface.soft_erp = 0.010f; | ||
632 | |||
633 | m_materialContacts[(int)Material.Plastic, 1] = new d.Contact(); | ||
634 | m_materialContacts[(int)Material.Plastic, 1].surface.mode |= d.ContactFlags.SoftERP; | ||
635 | m_materialContacts[(int)Material.Plastic, 1].surface.mu = mAvatarObjectContactFriction; | ||
636 | m_materialContacts[(int)Material.Plastic, 1].surface.bounce = mAvatarObjectContactBounce; | ||
637 | m_materialContacts[(int)Material.Plastic, 1].surface.soft_cfm = 0.010f; | ||
638 | m_materialContacts[(int)Material.Plastic, 1].surface.soft_erp = 0.010f; | ||
639 | |||
640 | m_materialContacts[(int)Material.Rubber, 0] = new d.Contact(); | ||
641 | m_materialContacts[(int)Material.Rubber, 0].surface.mode |= d.ContactFlags.SoftERP; | ||
642 | m_materialContacts[(int)Material.Rubber, 0].surface.mu = nmAvatarObjectContactFriction; | ||
643 | m_materialContacts[(int)Material.Rubber, 0].surface.bounce = nmAvatarObjectContactBounce; | ||
644 | m_materialContacts[(int)Material.Rubber, 0].surface.soft_cfm = 0.010f; | ||
645 | m_materialContacts[(int)Material.Rubber, 0].surface.soft_erp = 0.010f; | ||
646 | |||
647 | m_materialContacts[(int)Material.Rubber, 1] = new d.Contact(); | ||
648 | m_materialContacts[(int)Material.Rubber, 1].surface.mode |= d.ContactFlags.SoftERP; | ||
649 | m_materialContacts[(int)Material.Rubber, 1].surface.mu = mAvatarObjectContactFriction; | ||
650 | m_materialContacts[(int)Material.Rubber, 1].surface.bounce = mAvatarObjectContactBounce; | ||
651 | m_materialContacts[(int)Material.Rubber, 1].surface.soft_cfm = 0.010f; | ||
652 | m_materialContacts[(int)Material.Rubber, 1].surface.soft_erp = 0.010f; | ||
653 | |||
654 | d.HashSpaceSetLevels(space, worldHashspaceLow, worldHashspaceHigh); | ||
655 | |||
656 | // Set the gravity,, don't disable things automatically (we set it explicitly on some things) | ||
657 | |||
658 | d.WorldSetGravity(world, gravityx, gravityy, gravityz); | ||
659 | d.WorldSetContactSurfaceLayer(world, contactsurfacelayer); | ||
660 | |||
661 | d.WorldSetLinearDamping(world, 256f); | ||
662 | d.WorldSetAngularDamping(world, 256f); | ||
663 | d.WorldSetAngularDampingThreshold(world, 256f); | ||
664 | d.WorldSetLinearDampingThreshold(world, 256f); | ||
665 | d.WorldSetMaxAngularSpeed(world, 256f); | ||
666 | |||
667 | // Set how many steps we go without running collision testing | ||
668 | // This is in addition to the step size. | ||
669 | // Essentially Steps * m_physicsiterations | ||
670 | d.WorldSetQuickStepNumIterations(world, m_physicsiterations); | ||
671 | //d.WorldSetContactMaxCorrectingVel(world, 1000.0f); | ||
672 | |||
673 | |||
674 | |||
675 | for (int i = 0; i < staticPrimspace.GetLength(0); i++) | ||
676 | { | ||
677 | for (int j = 0; j < staticPrimspace.GetLength(1); j++) | ||
678 | { | ||
679 | staticPrimspace[i, j] = IntPtr.Zero; | ||
680 | } | ||
681 | } | ||
682 | } | ||
683 | |||
684 | internal void waitForSpaceUnlock(IntPtr space) | ||
685 | { | ||
686 | //if (space != IntPtr.Zero) | ||
687 | //while (d.SpaceLockQuery(space)) { } // Wait and do nothing | ||
688 | } | ||
689 | |||
690 | /// <summary> | ||
691 | /// Debug space message for printing the space that a prim/avatar is in. | ||
692 | /// </summary> | ||
693 | /// <param name="pos"></param> | ||
694 | /// <returns>Returns which split up space the given position is in.</returns> | ||
695 | public string whichspaceamIin(Vector3 pos) | ||
696 | { | ||
697 | return calculateSpaceForGeom(pos).ToString(); | ||
698 | } | ||
699 | |||
700 | #region Collision Detection | ||
701 | |||
702 | /// <summary> | ||
703 | /// This is our near callback. A geometry is near a body | ||
704 | /// </summary> | ||
705 | /// <param name="space">The space that contains the geoms. Remember, spaces are also geoms</param> | ||
706 | /// <param name="g1">a geometry or space</param> | ||
707 | /// <param name="g2">another geometry or space</param> | ||
708 | private void near(IntPtr space, IntPtr g1, IntPtr g2) | ||
709 | { | ||
710 | // no lock here! It's invoked from within Simulate(), which is thread-locked | ||
711 | |||
712 | // Test if we're colliding a geom with a space. | ||
713 | // If so we have to drill down into the space recursively | ||
714 | |||
715 | if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2)) | ||
716 | { | ||
717 | if (g1 == IntPtr.Zero || g2 == IntPtr.Zero) | ||
718 | return; | ||
719 | |||
720 | // Separating static prim geometry spaces. | ||
721 | // We'll be calling near recursivly if one | ||
722 | // of them is a space to find all of the | ||
723 | // contact points in the space | ||
724 | try | ||
725 | { | ||
726 | d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback); | ||
727 | } | ||
728 | catch (AccessViolationException) | ||
729 | { | ||
730 | m_log.Warn("[PHYSICS]: Unable to collide test a space"); | ||
731 | return; | ||
732 | } | ||
733 | //Colliding a space or a geom with a space or a geom. so drill down | ||
734 | |||
735 | //Collide all geoms in each space.. | ||
736 | //if (d.GeomIsSpace(g1)) d.SpaceCollide(g1, IntPtr.Zero, nearCallback); | ||
737 | //if (d.GeomIsSpace(g2)) d.SpaceCollide(g2, IntPtr.Zero, nearCallback); | ||
738 | return; | ||
739 | } | ||
740 | |||
741 | if (g1 == IntPtr.Zero || g2 == IntPtr.Zero) | ||
742 | return; | ||
743 | |||
744 | IntPtr b1 = d.GeomGetBody(g1); | ||
745 | IntPtr b2 = d.GeomGetBody(g2); | ||
746 | |||
747 | // d.GeomClassID id = d.GeomGetClass(g1); | ||
748 | |||
749 | String name1 = null; | ||
750 | String name2 = null; | ||
751 | |||
752 | if (!geom_name_map.TryGetValue(g1, out name1)) | ||
753 | { | ||
754 | name1 = "null"; | ||
755 | } | ||
756 | if (!geom_name_map.TryGetValue(g2, out name2)) | ||
757 | { | ||
758 | name2 = "null"; | ||
759 | } | ||
760 | |||
761 | //if (id == d.GeomClassId.TriMeshClass) | ||
762 | //{ | ||
763 | // m_log.InfoFormat("near: A collision was detected between {1} and {2}", 0, name1, name2); | ||
764 | //m_log.Debug("near: A collision was detected between {1} and {2}", 0, name1, name2); | ||
765 | //} | ||
766 | |||
767 | // Figure out how many contact points we have | ||
768 | int count = 0; | ||
769 | try | ||
770 | { | ||
771 | // Colliding Geom To Geom | ||
772 | // This portion of the function 'was' blatantly ripped off from BoxStack.cs | ||
773 | |||
774 | if (g1 == g2) | ||
775 | return; // Can't collide with yourself | ||
776 | |||
777 | if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact)) | ||
778 | return; | ||
779 | |||
780 | lock (contacts) | ||
781 | { | ||
782 | count = d.Collide(g1, g2, contacts.Length, contacts, d.ContactGeom.SizeOf); | ||
783 | if (count > contacts.Length) | ||
784 | m_log.Error("[PHYSICS]: Got " + count + " contacts when we asked for a maximum of " + contacts.Length); | ||
785 | } | ||
786 | } | ||
787 | catch (SEHException) | ||
788 | { | ||
789 | m_log.Error("[PHYSICS]: The Operating system shut down ODE because of corrupt memory. This could be a result of really irregular terrain. If this repeats continuously, restart using Basic Physics and terrain fill your terrain. Restarting the sim."); | ||
790 | ode.drelease(world); | ||
791 | base.TriggerPhysicsBasedRestart(); | ||
792 | } | ||
793 | catch (Exception e) | ||
794 | { | ||
795 | m_log.WarnFormat("[PHYSICS]: Unable to collide test an object: {0}", e.Message); | ||
796 | return; | ||
797 | } | ||
798 | |||
799 | PhysicsActor p1; | ||
800 | PhysicsActor p2; | ||
801 | |||
802 | if (!actor_name_map.TryGetValue(g1, out p1)) | ||
803 | { | ||
804 | p1 = PANull; | ||
805 | } | ||
806 | |||
807 | if (!actor_name_map.TryGetValue(g2, out p2)) | ||
808 | { | ||
809 | p2 = PANull; | ||
810 | } | ||
811 | |||
812 | ContactPoint maxDepthContact = new ContactPoint(); | ||
813 | if (p1.CollisionScore + count >= float.MaxValue) | ||
814 | p1.CollisionScore = 0; | ||
815 | p1.CollisionScore += count; | ||
816 | |||
817 | if (p2.CollisionScore + count >= float.MaxValue) | ||
818 | p2.CollisionScore = 0; | ||
819 | p2.CollisionScore += count; | ||
820 | |||
821 | for (int i = 0; i < count; i++) | ||
822 | { | ||
823 | d.ContactGeom curContact = contacts[i]; | ||
824 | |||
825 | if (curContact.depth > maxDepthContact.PenetrationDepth) | ||
826 | { | ||
827 | maxDepthContact = new ContactPoint( | ||
828 | new Vector3(curContact.pos.X, curContact.pos.Y, curContact.pos.Z), | ||
829 | new Vector3(curContact.normal.X, curContact.normal.Y, curContact.normal.Z), | ||
830 | curContact.depth | ||
831 | ); | ||
832 | } | ||
833 | |||
834 | //m_log.Warn("[CCOUNT]: " + count); | ||
835 | IntPtr joint; | ||
836 | // If we're colliding with terrain, use 'TerrainContact' instead of contact. | ||
837 | // allows us to have different settings | ||
838 | |||
839 | // We only need to test p2 for 'jump crouch purposes' | ||
840 | if (p2 is OdeCharacter && p1.PhysicsActorType == (int)ActorTypes.Prim) | ||
841 | { | ||
842 | // Testing if the collision is at the feet of the avatar | ||
843 | |||
844 | //m_log.DebugFormat("[PHYSICS]: {0} - {1} - {2} - {3}", curContact.pos.Z, p2.Position.Z, (p2.Position.Z - curContact.pos.Z), (p2.Size.Z * 0.6f)); | ||
845 | if ((p2.Position.Z - curContact.pos.Z) > (p2.Size.Z * 0.6f)) | ||
846 | p2.IsColliding = true; | ||
847 | } | ||
848 | else | ||
849 | { | ||
850 | p2.IsColliding = true; | ||
851 | } | ||
852 | |||
853 | //if ((framecount % m_returncollisions) == 0) | ||
854 | |||
855 | switch (p1.PhysicsActorType) | ||
856 | { | ||
857 | case (int)ActorTypes.Agent: | ||
858 | p2.CollidingObj = true; | ||
859 | break; | ||
860 | case (int)ActorTypes.Prim: | ||
861 | if (p2.Velocity.LengthSquared() > 0.0f) | ||
862 | p2.CollidingObj = true; | ||
863 | break; | ||
864 | case (int)ActorTypes.Unknown: | ||
865 | p2.CollidingGround = true; | ||
866 | break; | ||
867 | default: | ||
868 | p2.CollidingGround = true; | ||
869 | break; | ||
870 | } | ||
871 | |||
872 | // we don't want prim or avatar to explode | ||
873 | |||
874 | #region InterPenetration Handling - Unintended physics explosions | ||
875 | # region disabled code1 | ||
876 | |||
877 | if (curContact.depth >= 0.08f) | ||
878 | { | ||
879 | //This is disabled at the moment only because it needs more tweaking | ||
880 | //It will eventually be uncommented | ||
881 | /* | ||
882 | if (contact.depth >= 1.00f) | ||
883 | { | ||
884 | //m_log.Debug("[PHYSICS]: " + contact.depth.ToString()); | ||
885 | } | ||
886 | |||
887 | //If you interpenetrate a prim with an agent | ||
888 | if ((p2.PhysicsActorType == (int) ActorTypes.Agent && | ||
889 | p1.PhysicsActorType == (int) ActorTypes.Prim) || | ||
890 | (p1.PhysicsActorType == (int) ActorTypes.Agent && | ||
891 | p2.PhysicsActorType == (int) ActorTypes.Prim)) | ||
892 | { | ||
893 | |||
894 | //contact.depth = contact.depth * 4.15f; | ||
895 | /* | ||
896 | if (p2.PhysicsActorType == (int) ActorTypes.Agent) | ||
897 | { | ||
898 | p2.CollidingObj = true; | ||
899 | contact.depth = 0.003f; | ||
900 | p2.Velocity = p2.Velocity + new PhysicsVector(0, 0, 2.5f); | ||
901 | OdeCharacter character = (OdeCharacter) p2; | ||
902 | character.SetPidStatus(true); | ||
903 | contact.pos = new d.Vector3(contact.pos.X + (p1.Size.X / 2), contact.pos.Y + (p1.Size.Y / 2), contact.pos.Z + (p1.Size.Z / 2)); | ||
904 | |||
905 | } | ||
906 | else | ||
907 | { | ||
908 | |||
909 | //contact.depth = 0.0000000f; | ||
910 | } | ||
911 | if (p1.PhysicsActorType == (int) ActorTypes.Agent) | ||
912 | { | ||
913 | |||
914 | p1.CollidingObj = true; | ||
915 | contact.depth = 0.003f; | ||
916 | p1.Velocity = p1.Velocity + new PhysicsVector(0, 0, 2.5f); | ||
917 | contact.pos = new d.Vector3(contact.pos.X + (p2.Size.X / 2), contact.pos.Y + (p2.Size.Y / 2), contact.pos.Z + (p2.Size.Z / 2)); | ||
918 | OdeCharacter character = (OdeCharacter)p1; | ||
919 | character.SetPidStatus(true); | ||
920 | } | ||
921 | else | ||
922 | { | ||
923 | |||
924 | //contact.depth = 0.0000000f; | ||
925 | } | ||
926 | |||
927 | |||
928 | |||
929 | } | ||
930 | */ | ||
931 | // If you interpenetrate a prim with another prim | ||
932 | /* | ||
933 | if (p1.PhysicsActorType == (int) ActorTypes.Prim && p2.PhysicsActorType == (int) ActorTypes.Prim) | ||
934 | { | ||
935 | #region disabledcode2 | ||
936 | //OdePrim op1 = (OdePrim)p1; | ||
937 | //OdePrim op2 = (OdePrim)p2; | ||
938 | //op1.m_collisionscore++; | ||
939 | //op2.m_collisionscore++; | ||
940 | |||
941 | //if (op1.m_collisionscore > 8000 || op2.m_collisionscore > 8000) | ||
942 | //{ | ||
943 | //op1.m_taintdisable = true; | ||
944 | //AddPhysicsActorTaint(p1); | ||
945 | //op2.m_taintdisable = true; | ||
946 | //AddPhysicsActorTaint(p2); | ||
947 | //} | ||
948 | |||
949 | //if (contact.depth >= 0.25f) | ||
950 | //{ | ||
951 | // Don't collide, one or both prim will expld. | ||
952 | |||
953 | //op1.m_interpenetrationcount++; | ||
954 | //op2.m_interpenetrationcount++; | ||
955 | //interpenetrations_before_disable = 200; | ||
956 | //if (op1.m_interpenetrationcount >= interpenetrations_before_disable) | ||
957 | //{ | ||
958 | //op1.m_taintdisable = true; | ||
959 | //AddPhysicsActorTaint(p1); | ||
960 | //} | ||
961 | //if (op2.m_interpenetrationcount >= interpenetrations_before_disable) | ||
962 | //{ | ||
963 | // op2.m_taintdisable = true; | ||
964 | //AddPhysicsActorTaint(p2); | ||
965 | //} | ||
966 | |||
967 | //contact.depth = contact.depth / 8f; | ||
968 | //contact.normal = new d.Vector3(0, 0, 1); | ||
969 | //} | ||
970 | //if (op1.m_disabled || op2.m_disabled) | ||
971 | //{ | ||
972 | //Manually disabled objects stay disabled | ||
973 | //contact.depth = 0f; | ||
974 | //} | ||
975 | #endregion | ||
976 | } | ||
977 | */ | ||
978 | #endregion | ||
979 | if (curContact.depth >= 1.00f) | ||
980 | { | ||
981 | //m_log.Info("[P]: " + contact.depth.ToString()); | ||
982 | if ((p2.PhysicsActorType == (int) ActorTypes.Agent && | ||
983 | p1.PhysicsActorType == (int) ActorTypes.Unknown) || | ||
984 | (p1.PhysicsActorType == (int) ActorTypes.Agent && | ||
985 | p2.PhysicsActorType == (int) ActorTypes.Unknown)) | ||
986 | { | ||
987 | if (p2.PhysicsActorType == (int) ActorTypes.Agent) | ||
988 | { | ||
989 | if (p2 is OdeCharacter) | ||
990 | { | ||
991 | OdeCharacter character = (OdeCharacter) p2; | ||
992 | |||
993 | //p2.CollidingObj = true; | ||
994 | curContact.depth = 0.00000003f; | ||
995 | p2.Velocity = p2.Velocity + new Vector3(0f, 0f, 0.5f); | ||
996 | curContact.pos = | ||
997 | new d.Vector3(curContact.pos.X + (p1.Size.X/2), | ||
998 | curContact.pos.Y + (p1.Size.Y/2), | ||
999 | curContact.pos.Z + (p1.Size.Z/2)); | ||
1000 | character.SetPidStatus(true); | ||
1001 | } | ||
1002 | } | ||
1003 | |||
1004 | |||
1005 | if (p1.PhysicsActorType == (int) ActorTypes.Agent) | ||
1006 | { | ||
1007 | if (p1 is OdeCharacter) | ||
1008 | { | ||
1009 | OdeCharacter character = (OdeCharacter) p1; | ||
1010 | |||
1011 | //p2.CollidingObj = true; | ||
1012 | curContact.depth = 0.00000003f; | ||
1013 | p1.Velocity = p1.Velocity + new Vector3(0f, 0f, 0.5f); | ||
1014 | curContact.pos = | ||
1015 | new d.Vector3(curContact.pos.X + (p1.Size.X/2), | ||
1016 | curContact.pos.Y + (p1.Size.Y/2), | ||
1017 | curContact.pos.Z + (p1.Size.Z/2)); | ||
1018 | character.SetPidStatus(true); | ||
1019 | } | ||
1020 | } | ||
1021 | } | ||
1022 | } | ||
1023 | } | ||
1024 | |||
1025 | #endregion | ||
1026 | |||
1027 | // Logic for collision handling | ||
1028 | // Note, that if *all* contacts are skipped (VolumeDetect) | ||
1029 | // The prim still detects (and forwards) collision events but | ||
1030 | // appears to be phantom for the world | ||
1031 | Boolean skipThisContact = false; | ||
1032 | |||
1033 | if ((p1 is OdePrim) && (((OdePrim)p1).m_isVolumeDetect)) | ||
1034 | skipThisContact = true; // No collision on volume detect prims | ||
1035 | |||
1036 | if (!skipThisContact && (p2 is OdePrim) && (((OdePrim)p2).m_isVolumeDetect)) | ||
1037 | skipThisContact = true; // No collision on volume detect prims | ||
1038 | |||
1039 | if (!skipThisContact && curContact.depth < 0f) | ||
1040 | skipThisContact = true; | ||
1041 | |||
1042 | if (!skipThisContact && checkDupe(curContact, p2.PhysicsActorType)) | ||
1043 | skipThisContact = true; | ||
1044 | |||
1045 | const int maxContactsbeforedeath = 4000; | ||
1046 | joint = IntPtr.Zero; | ||
1047 | |||
1048 | if (!skipThisContact) | ||
1049 | { | ||
1050 | // If we're colliding against terrain | ||
1051 | if (name1 == "Terrain" || name2 == "Terrain") | ||
1052 | { | ||
1053 | // If we're moving | ||
1054 | if ((p2.PhysicsActorType == (int) ActorTypes.Agent) && | ||
1055 | (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)) | ||
1056 | { | ||
1057 | // Use the movement terrain contact | ||
1058 | AvatarMovementTerrainContact.geom = curContact; | ||
1059 | _perloopContact.Add(curContact); | ||
1060 | if (m_global_contactcount < maxContactsbeforedeath) | ||
1061 | { | ||
1062 | joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementTerrainContact); | ||
1063 | m_global_contactcount++; | ||
1064 | } | ||
1065 | } | ||
1066 | else | ||
1067 | { | ||
1068 | if (p2.PhysicsActorType == (int)ActorTypes.Agent) | ||
1069 | { | ||
1070 | // Use the non moving terrain contact | ||
1071 | TerrainContact.geom = curContact; | ||
1072 | _perloopContact.Add(curContact); | ||
1073 | if (m_global_contactcount < maxContactsbeforedeath) | ||
1074 | { | ||
1075 | joint = d.JointCreateContact(world, contactgroup, ref TerrainContact); | ||
1076 | m_global_contactcount++; | ||
1077 | } | ||
1078 | } | ||
1079 | else | ||
1080 | { | ||
1081 | if (p2.PhysicsActorType == (int)ActorTypes.Prim && p1.PhysicsActorType == (int)ActorTypes.Prim) | ||
1082 | { | ||
1083 | // prim prim contact | ||
1084 | // int pj294950 = 0; | ||
1085 | int movintYN = 0; | ||
1086 | int material = (int) Material.Wood; | ||
1087 | // prim terrain contact | ||
1088 | if (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f) | ||
1089 | { | ||
1090 | movintYN = 1; | ||
1091 | } | ||
1092 | |||
1093 | if (p2 is OdePrim) | ||
1094 | material = ((OdePrim)p2).m_material; | ||
1095 | |||
1096 | //m_log.DebugFormat("Material: {0}", material); | ||
1097 | m_materialContacts[material, movintYN].geom = curContact; | ||
1098 | _perloopContact.Add(curContact); | ||
1099 | |||
1100 | if (m_global_contactcount < maxContactsbeforedeath) | ||
1101 | { | ||
1102 | joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]); | ||
1103 | m_global_contactcount++; | ||
1104 | |||
1105 | } | ||
1106 | |||
1107 | } | ||
1108 | else | ||
1109 | { | ||
1110 | |||
1111 | int movintYN = 0; | ||
1112 | // prim terrain contact | ||
1113 | if (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f) | ||
1114 | { | ||
1115 | movintYN = 1; | ||
1116 | } | ||
1117 | |||
1118 | int material = (int)Material.Wood; | ||
1119 | |||
1120 | if (p2 is OdePrim) | ||
1121 | material = ((OdePrim)p2).m_material; | ||
1122 | //m_log.DebugFormat("Material: {0}", material); | ||
1123 | m_materialContacts[material, movintYN].geom = curContact; | ||
1124 | _perloopContact.Add(curContact); | ||
1125 | |||
1126 | if (m_global_contactcount < maxContactsbeforedeath) | ||
1127 | { | ||
1128 | joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]); | ||
1129 | m_global_contactcount++; | ||
1130 | |||
1131 | } | ||
1132 | } | ||
1133 | } | ||
1134 | } | ||
1135 | //if (p2.PhysicsActorType == (int)ActorTypes.Prim) | ||
1136 | //{ | ||
1137 | //m_log.Debug("[PHYSICS]: prim contacting with ground"); | ||
1138 | //} | ||
1139 | } | ||
1140 | else if (name1 == "Water" || name2 == "Water") | ||
1141 | { | ||
1142 | /* | ||
1143 | if ((p2.PhysicsActorType == (int) ActorTypes.Prim)) | ||
1144 | { | ||
1145 | } | ||
1146 | else | ||
1147 | { | ||
1148 | } | ||
1149 | */ | ||
1150 | //WaterContact.surface.soft_cfm = 0.0000f; | ||
1151 | //WaterContact.surface.soft_erp = 0.00000f; | ||
1152 | if (curContact.depth > 0.1f) | ||
1153 | { | ||
1154 | curContact.depth *= 52; | ||
1155 | //contact.normal = new d.Vector3(0, 0, 1); | ||
1156 | //contact.pos = new d.Vector3(0, 0, contact.pos.Z - 5f); | ||
1157 | } | ||
1158 | WaterContact.geom = curContact; | ||
1159 | _perloopContact.Add(curContact); | ||
1160 | if (m_global_contactcount < maxContactsbeforedeath) | ||
1161 | { | ||
1162 | joint = d.JointCreateContact(world, contactgroup, ref WaterContact); | ||
1163 | m_global_contactcount++; | ||
1164 | } | ||
1165 | //m_log.Info("[PHYSICS]: Prim Water Contact" + contact.depth); | ||
1166 | } | ||
1167 | else | ||
1168 | { | ||
1169 | // we're colliding with prim or avatar | ||
1170 | // check if we're moving | ||
1171 | if ((p2.PhysicsActorType == (int)ActorTypes.Agent)) | ||
1172 | { | ||
1173 | if ((Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)) | ||
1174 | { | ||
1175 | // Use the Movement prim contact | ||
1176 | AvatarMovementprimContact.geom = curContact; | ||
1177 | _perloopContact.Add(curContact); | ||
1178 | if (m_global_contactcount < maxContactsbeforedeath) | ||
1179 | { | ||
1180 | joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementprimContact); | ||
1181 | m_global_contactcount++; | ||
1182 | } | ||
1183 | } | ||
1184 | else | ||
1185 | { | ||
1186 | // Use the non movement contact | ||
1187 | contact.geom = curContact; | ||
1188 | _perloopContact.Add(curContact); | ||
1189 | |||
1190 | if (m_global_contactcount < maxContactsbeforedeath) | ||
1191 | { | ||
1192 | joint = d.JointCreateContact(world, contactgroup, ref contact); | ||
1193 | m_global_contactcount++; | ||
1194 | } | ||
1195 | } | ||
1196 | } | ||
1197 | else if (p2.PhysicsActorType == (int)ActorTypes.Prim) | ||
1198 | { | ||
1199 | //p1.PhysicsActorType | ||
1200 | int material = (int)Material.Wood; | ||
1201 | |||
1202 | if (p2 is OdePrim) | ||
1203 | material = ((OdePrim)p2).m_material; | ||
1204 | |||
1205 | //m_log.DebugFormat("Material: {0}", material); | ||
1206 | m_materialContacts[material, 0].geom = curContact; | ||
1207 | _perloopContact.Add(curContact); | ||
1208 | |||
1209 | if (m_global_contactcount < maxContactsbeforedeath) | ||
1210 | { | ||
1211 | joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, 0]); | ||
1212 | m_global_contactcount++; | ||
1213 | |||
1214 | } | ||
1215 | } | ||
1216 | } | ||
1217 | |||
1218 | if (m_global_contactcount < maxContactsbeforedeath && joint != IntPtr.Zero) // stack collide! | ||
1219 | { | ||
1220 | d.JointAttach(joint, b1, b2); | ||
1221 | m_global_contactcount++; | ||
1222 | } | ||
1223 | |||
1224 | } | ||
1225 | collision_accounting_events(p1, p2, maxDepthContact); | ||
1226 | if (count > geomContactPointsStartthrottle) | ||
1227 | { | ||
1228 | // If there are more then 3 contact points, it's likely | ||
1229 | // that we've got a pile of objects, so ... | ||
1230 | // We don't want to send out hundreds of terse updates over and over again | ||
1231 | // so lets throttle them and send them again after it's somewhat sorted out. | ||
1232 | p2.ThrottleUpdates = true; | ||
1233 | } | ||
1234 | //m_log.Debug(count.ToString()); | ||
1235 | //m_log.Debug("near: A collision was detected between {1} and {2}", 0, name1, name2); | ||
1236 | } | ||
1237 | } | ||
1238 | |||
1239 | private bool checkDupe(d.ContactGeom contactGeom, int atype) | ||
1240 | { | ||
1241 | bool result = false; | ||
1242 | //return result; | ||
1243 | if (!m_filterCollisions) | ||
1244 | return false; | ||
1245 | |||
1246 | ActorTypes at = (ActorTypes)atype; | ||
1247 | lock (_perloopContact) | ||
1248 | { | ||
1249 | foreach (d.ContactGeom contact in _perloopContact) | ||
1250 | { | ||
1251 | //if ((contact.g1 == contactGeom.g1 && contact.g2 == contactGeom.g2)) | ||
1252 | //{ | ||
1253 | // || (contact.g2 == contactGeom.g1 && contact.g1 == contactGeom.g2) | ||
1254 | if (at == ActorTypes.Agent) | ||
1255 | { | ||
1256 | if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f) && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f) && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f)) && contactGeom.g1 != LandGeom && contactGeom.g2 != LandGeom) | ||
1257 | { | ||
1258 | |||
1259 | if (Math.Abs(contact.depth - contactGeom.depth) < 0.052f) | ||
1260 | { | ||
1261 | //contactGeom.depth *= .00005f; | ||
1262 | //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth)); | ||
1263 | // m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z)); | ||
1264 | result = true; | ||
1265 | break; | ||
1266 | } | ||
1267 | else | ||
1268 | { | ||
1269 | //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth)); | ||
1270 | } | ||
1271 | } | ||
1272 | else | ||
1273 | { | ||
1274 | //m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z)); | ||
1275 | //int i = 0; | ||
1276 | } | ||
1277 | } | ||
1278 | else if (at == ActorTypes.Prim) | ||
1279 | { | ||
1280 | //d.AABB aabb1 = new d.AABB(); | ||
1281 | //d.AABB aabb2 = new d.AABB(); | ||
1282 | |||
1283 | //d.GeomGetAABB(contactGeom.g2, out aabb2); | ||
1284 | //d.GeomGetAABB(contactGeom.g1, out aabb1); | ||
1285 | //aabb1. | ||
1286 | if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f) && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f) && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f)) && contactGeom.g1 != LandGeom && contactGeom.g2 != LandGeom) | ||
1287 | { | ||
1288 | if (contactGeom.normal.X == contact.normal.X && contactGeom.normal.Y == contact.normal.Y && contactGeom.normal.Z == contact.normal.Z) | ||
1289 | { | ||
1290 | if (Math.Abs(contact.depth - contactGeom.depth) < 0.272f) | ||
1291 | { | ||
1292 | result = true; | ||
1293 | break; | ||
1294 | } | ||
1295 | } | ||
1296 | //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth)); | ||
1297 | //m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z)); | ||
1298 | } | ||
1299 | |||
1300 | } | ||
1301 | |||
1302 | //} | ||
1303 | |||
1304 | } | ||
1305 | } | ||
1306 | return result; | ||
1307 | } | ||
1308 | |||
1309 | private void collision_accounting_events(PhysicsActor p1, PhysicsActor p2, ContactPoint contact) | ||
1310 | { | ||
1311 | // obj1LocalID = 0; | ||
1312 | //returncollisions = false; | ||
1313 | obj2LocalID = 0; | ||
1314 | //ctype = 0; | ||
1315 | //cStartStop = 0; | ||
1316 | if (!p2.SubscribedEvents() && !p1.SubscribedEvents()) | ||
1317 | return; | ||
1318 | |||
1319 | switch ((ActorTypes)p2.PhysicsActorType) | ||
1320 | { | ||
1321 | case ActorTypes.Agent: | ||
1322 | cc2 = (OdeCharacter)p2; | ||
1323 | |||
1324 | // obj1LocalID = cc2.m_localID; | ||
1325 | switch ((ActorTypes)p1.PhysicsActorType) | ||
1326 | { | ||
1327 | case ActorTypes.Agent: | ||
1328 | cc1 = (OdeCharacter)p1; | ||
1329 | obj2LocalID = cc1.m_localID; | ||
1330 | cc1.AddCollisionEvent(cc2.m_localID, contact); | ||
1331 | //ctype = (int)CollisionCategories.Character; | ||
1332 | |||
1333 | //if (cc1.CollidingObj) | ||
1334 | //cStartStop = (int)StatusIndicators.Generic; | ||
1335 | //else | ||
1336 | //cStartStop = (int)StatusIndicators.Start; | ||
1337 | |||
1338 | //returncollisions = true; | ||
1339 | break; | ||
1340 | case ActorTypes.Prim: | ||
1341 | if (p1 is OdePrim) | ||
1342 | { | ||
1343 | cp1 = (OdePrim) p1; | ||
1344 | obj2LocalID = cp1.m_localID; | ||
1345 | cp1.AddCollisionEvent(cc2.m_localID, contact); | ||
1346 | } | ||
1347 | //ctype = (int)CollisionCategories.Geom; | ||
1348 | |||
1349 | //if (cp1.CollidingObj) | ||
1350 | //cStartStop = (int)StatusIndicators.Generic; | ||
1351 | //else | ||
1352 | //cStartStop = (int)StatusIndicators.Start; | ||
1353 | |||
1354 | //returncollisions = true; | ||
1355 | break; | ||
1356 | |||
1357 | case ActorTypes.Ground: | ||
1358 | case ActorTypes.Unknown: | ||
1359 | obj2LocalID = 0; | ||
1360 | //ctype = (int)CollisionCategories.Land; | ||
1361 | //returncollisions = true; | ||
1362 | break; | ||
1363 | } | ||
1364 | |||
1365 | cc2.AddCollisionEvent(obj2LocalID, contact); | ||
1366 | break; | ||
1367 | case ActorTypes.Prim: | ||
1368 | |||
1369 | if (p2 is OdePrim) | ||
1370 | { | ||
1371 | cp2 = (OdePrim) p2; | ||
1372 | |||
1373 | // obj1LocalID = cp2.m_localID; | ||
1374 | switch ((ActorTypes) p1.PhysicsActorType) | ||
1375 | { | ||
1376 | case ActorTypes.Agent: | ||
1377 | if (p1 is OdeCharacter) | ||
1378 | { | ||
1379 | cc1 = (OdeCharacter) p1; | ||
1380 | obj2LocalID = cc1.m_localID; | ||
1381 | cc1.AddCollisionEvent(cp2.m_localID, contact); | ||
1382 | //ctype = (int)CollisionCategories.Character; | ||
1383 | |||
1384 | //if (cc1.CollidingObj) | ||
1385 | //cStartStop = (int)StatusIndicators.Generic; | ||
1386 | //else | ||
1387 | //cStartStop = (int)StatusIndicators.Start; | ||
1388 | //returncollisions = true; | ||
1389 | } | ||
1390 | break; | ||
1391 | case ActorTypes.Prim: | ||
1392 | |||
1393 | if (p1 is OdePrim) | ||
1394 | { | ||
1395 | cp1 = (OdePrim) p1; | ||
1396 | obj2LocalID = cp1.m_localID; | ||
1397 | cp1.AddCollisionEvent(cp2.m_localID, contact); | ||
1398 | //ctype = (int)CollisionCategories.Geom; | ||
1399 | |||
1400 | //if (cp1.CollidingObj) | ||
1401 | //cStartStop = (int)StatusIndicators.Generic; | ||
1402 | //else | ||
1403 | //cStartStop = (int)StatusIndicators.Start; | ||
1404 | |||
1405 | //returncollisions = true; | ||
1406 | } | ||
1407 | break; | ||
1408 | |||
1409 | case ActorTypes.Ground: | ||
1410 | case ActorTypes.Unknown: | ||
1411 | obj2LocalID = 0; | ||
1412 | //ctype = (int)CollisionCategories.Land; | ||
1413 | |||
1414 | //returncollisions = true; | ||
1415 | break; | ||
1416 | } | ||
1417 | |||
1418 | cp2.AddCollisionEvent(obj2LocalID, contact); | ||
1419 | } | ||
1420 | break; | ||
1421 | } | ||
1422 | //if (returncollisions) | ||
1423 | //{ | ||
1424 | |||
1425 | //lock (m_storedCollisions) | ||
1426 | //{ | ||
1427 | //cDictKey = obj1LocalID.ToString() + obj2LocalID.ToString() + cStartStop.ToString() + ctype.ToString(); | ||
1428 | //if (m_storedCollisions.ContainsKey(cDictKey)) | ||
1429 | //{ | ||
1430 | //sCollisionData objd = m_storedCollisions[cDictKey]; | ||
1431 | //objd.NumberOfCollisions += 1; | ||
1432 | //objd.lastframe = framecount; | ||
1433 | //m_storedCollisions[cDictKey] = objd; | ||
1434 | //} | ||
1435 | //else | ||
1436 | //{ | ||
1437 | //sCollisionData objd = new sCollisionData(); | ||
1438 | //objd.ColliderLocalId = obj1LocalID; | ||
1439 | //objd.CollidedWithLocalId = obj2LocalID; | ||
1440 | //objd.CollisionType = ctype; | ||
1441 | //objd.NumberOfCollisions = 1; | ||
1442 | //objd.lastframe = framecount; | ||
1443 | //objd.StatusIndicator = cStartStop; | ||
1444 | //m_storedCollisions.Add(cDictKey, objd); | ||
1445 | //} | ||
1446 | //} | ||
1447 | // } | ||
1448 | } | ||
1449 | |||
1450 | public int TriArrayCallback(IntPtr trimesh, IntPtr refObject, int[] triangleIndex, int triCount) | ||
1451 | { | ||
1452 | /* String name1 = null; | ||
1453 | String name2 = null; | ||
1454 | |||
1455 | if (!geom_name_map.TryGetValue(trimesh, out name1)) | ||
1456 | { | ||
1457 | name1 = "null"; | ||
1458 | } | ||
1459 | if (!geom_name_map.TryGetValue(refObject, out name2)) | ||
1460 | { | ||
1461 | name2 = "null"; | ||
1462 | } | ||
1463 | |||
1464 | m_log.InfoFormat("TriArrayCallback: A collision was detected between {1} and {2}", 0, name1, name2); | ||
1465 | */ | ||
1466 | return 1; | ||
1467 | } | ||
1468 | |||
1469 | public int TriCallback(IntPtr trimesh, IntPtr refObject, int triangleIndex) | ||
1470 | { | ||
1471 | String name1 = null; | ||
1472 | String name2 = null; | ||
1473 | |||
1474 | if (!geom_name_map.TryGetValue(trimesh, out name1)) | ||
1475 | { | ||
1476 | name1 = "null"; | ||
1477 | } | ||
1478 | |||
1479 | if (!geom_name_map.TryGetValue(refObject, out name2)) | ||
1480 | { | ||
1481 | name2 = "null"; | ||
1482 | } | ||
1483 | |||
1484 | // m_log.InfoFormat("TriCallback: A collision was detected between {1} and {2}. Index was {3}", 0, name1, name2, triangleIndex); | ||
1485 | |||
1486 | d.Vector3 v0 = new d.Vector3(); | ||
1487 | d.Vector3 v1 = new d.Vector3(); | ||
1488 | d.Vector3 v2 = new d.Vector3(); | ||
1489 | |||
1490 | d.GeomTriMeshGetTriangle(trimesh, 0, ref v0, ref v1, ref v2); | ||
1491 | // m_log.DebugFormat("Triangle {0} is <{1},{2},{3}>, <{4},{5},{6}>, <{7},{8},{9}>", triangleIndex, v0.X, v0.Y, v0.Z, v1.X, v1.Y, v1.Z, v2.X, v2.Y, v2.Z); | ||
1492 | |||
1493 | return 1; | ||
1494 | } | ||
1495 | |||
1496 | /// <summary> | ||
1497 | /// This is our collision testing routine in ODE | ||
1498 | /// </summary> | ||
1499 | /// <param name="timeStep"></param> | ||
1500 | private void collision_optimized(float timeStep) | ||
1501 | { | ||
1502 | _perloopContact.Clear(); | ||
1503 | |||
1504 | lock (_characters) | ||
1505 | { | ||
1506 | foreach (OdeCharacter chr in _characters) | ||
1507 | { | ||
1508 | // Reset the collision values to false | ||
1509 | // since we don't know if we're colliding yet | ||
1510 | |||
1511 | // For some reason this can happen. Don't ask... | ||
1512 | // | ||
1513 | if (chr == null) | ||
1514 | continue; | ||
1515 | |||
1516 | if (chr.Shell == IntPtr.Zero || chr.Body == IntPtr.Zero) | ||
1517 | continue; | ||
1518 | |||
1519 | chr.IsColliding = false; | ||
1520 | chr.CollidingGround = false; | ||
1521 | chr.CollidingObj = false; | ||
1522 | |||
1523 | // test the avatar's geometry for collision with the space | ||
1524 | // This will return near and the space that they are the closest to | ||
1525 | // And we'll run this again against the avatar and the space segment | ||
1526 | // This will return with a bunch of possible objects in the space segment | ||
1527 | // and we'll run it again on all of them. | ||
1528 | try | ||
1529 | { | ||
1530 | d.SpaceCollide2(space, chr.Shell, IntPtr.Zero, nearCallback); | ||
1531 | } | ||
1532 | catch (AccessViolationException) | ||
1533 | { | ||
1534 | m_log.Warn("[PHYSICS]: Unable to space collide"); | ||
1535 | } | ||
1536 | //float terrainheight = GetTerrainHeightAtXY(chr.Position.X, chr.Position.Y); | ||
1537 | //if (chr.Position.Z + (chr.Velocity.Z * timeStep) < terrainheight + 10) | ||
1538 | //{ | ||
1539 | //chr.Position.Z = terrainheight + 10.0f; | ||
1540 | //forcedZ = true; | ||
1541 | //} | ||
1542 | } | ||
1543 | } | ||
1544 | |||
1545 | lock (_activeprims) | ||
1546 | { | ||
1547 | List<OdePrim> removeprims = null; | ||
1548 | foreach (OdePrim chr in _activeprims) | ||
1549 | { | ||
1550 | if (chr.Body != IntPtr.Zero && d.BodyIsEnabled(chr.Body) && (!chr.m_disabled)) | ||
1551 | { | ||
1552 | try | ||
1553 | { | ||
1554 | lock (chr) | ||
1555 | { | ||
1556 | if (space != IntPtr.Zero && chr.prim_geom != IntPtr.Zero && chr.m_taintremove == false) | ||
1557 | { | ||
1558 | d.SpaceCollide2(space, chr.prim_geom, IntPtr.Zero, nearCallback); | ||
1559 | } | ||
1560 | else | ||
1561 | { | ||
1562 | if (removeprims == null) | ||
1563 | { | ||
1564 | removeprims = new List<OdePrim>(); | ||
1565 | } | ||
1566 | removeprims.Add(chr); | ||
1567 | m_log.Debug("[PHYSICS]: unable to collide test active prim against space. The space was zero, the geom was zero or it was in the process of being removed. Removed it from the active prim list. This needs to be fixed!"); | ||
1568 | } | ||
1569 | } | ||
1570 | } | ||
1571 | catch (AccessViolationException) | ||
1572 | { | ||
1573 | m_log.Warn("[PHYSICS]: Unable to space collide"); | ||
1574 | } | ||
1575 | } | ||
1576 | } | ||
1577 | if (removeprims != null) | ||
1578 | { | ||
1579 | foreach (OdePrim chr in removeprims) | ||
1580 | { | ||
1581 | _activeprims.Remove(chr); | ||
1582 | } | ||
1583 | } | ||
1584 | } | ||
1585 | |||
1586 | _perloopContact.Clear(); | ||
1587 | } | ||
1588 | |||
1589 | #endregion | ||
1590 | |||
1591 | public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents) | ||
1592 | { | ||
1593 | m_worldOffset = offset; | ||
1594 | WorldExtents = new Vector2(extents.X, extents.Y); | ||
1595 | m_parentScene = pScene; | ||
1596 | |||
1597 | } | ||
1598 | |||
1599 | // Recovered for use by fly height. Kitto Flora | ||
1600 | public float GetTerrainHeightAtXY(float x, float y) | ||
1601 | { | ||
1602 | |||
1603 | int offsetX = ((int)(x / (int)Constants.RegionSize)) * (int)Constants.RegionSize; | ||
1604 | int offsetY = ((int)(y / (int)Constants.RegionSize)) * (int)Constants.RegionSize; | ||
1605 | |||
1606 | IntPtr heightFieldGeom = IntPtr.Zero; | ||
1607 | |||
1608 | if (RegionTerrain.TryGetValue(new Vector3(offsetX,offsetY,0), out heightFieldGeom)) | ||
1609 | { | ||
1610 | if (heightFieldGeom != IntPtr.Zero) | ||
1611 | { | ||
1612 | if (TerrainHeightFieldHeights.ContainsKey(heightFieldGeom)) | ||
1613 | { | ||
1614 | |||
1615 | int index; | ||
1616 | |||
1617 | |||
1618 | if ((int)x > WorldExtents.X || (int)y > WorldExtents.Y || | ||
1619 | (int)x < 0.001f || (int)y < 0.001f) | ||
1620 | return 0; | ||
1621 | |||
1622 | x = x - offsetX; | ||
1623 | y = y - offsetY; | ||
1624 | |||
1625 | index = (int)((int)x * ((int)Constants.RegionSize + 2) + (int)y); | ||
1626 | |||
1627 | if (index < TerrainHeightFieldHeights[heightFieldGeom].Length) | ||
1628 | { | ||
1629 | //m_log.DebugFormat("x{0} y{1} = {2}", x, y, (float)TerrainHeightFieldHeights[heightFieldGeom][index]); | ||
1630 | return (float)TerrainHeightFieldHeights[heightFieldGeom][index]; | ||
1631 | } | ||
1632 | |||
1633 | else | ||
1634 | return 0f; | ||
1635 | } | ||
1636 | else | ||
1637 | { | ||
1638 | return 0f; | ||
1639 | } | ||
1640 | |||
1641 | } | ||
1642 | else | ||
1643 | { | ||
1644 | return 0f; | ||
1645 | } | ||
1646 | |||
1647 | } | ||
1648 | else | ||
1649 | { | ||
1650 | return 0f; | ||
1651 | } | ||
1652 | |||
1653 | |||
1654 | } | ||
1655 | // End recovered. Kitto Flora | ||
1656 | |||
1657 | public void addCollisionEventReporting(PhysicsActor obj) | ||
1658 | { | ||
1659 | lock (_collisionEventPrim) | ||
1660 | { | ||
1661 | if (!_collisionEventPrim.Contains(obj)) | ||
1662 | _collisionEventPrim.Add(obj); | ||
1663 | } | ||
1664 | } | ||
1665 | |||
1666 | public void remCollisionEventReporting(PhysicsActor obj) | ||
1667 | { | ||
1668 | lock (_collisionEventPrim) | ||
1669 | { | ||
1670 | if (!_collisionEventPrim.Contains(obj)) | ||
1671 | _collisionEventPrim.Remove(obj); | ||
1672 | } | ||
1673 | } | ||
1674 | |||
1675 | #region Add/Remove Entities | ||
1676 | |||
1677 | public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying) | ||
1678 | { | ||
1679 | Vector3 pos; | ||
1680 | pos.X = position.X; | ||
1681 | pos.Y = position.Y; | ||
1682 | pos.Z = position.Z; | ||
1683 | OdeCharacter newAv = new OdeCharacter(avName, this, pos, ode, size, avPIDD, avPIDP, avCapRadius, avStandupTensor, avDensity, avHeightFudgeFactor, avMovementDivisorWalk, avMovementDivisorRun); | ||
1684 | newAv.Flying = isFlying; | ||
1685 | newAv.MinimumGroundFlightOffset = minimumGroundFlightOffset; | ||
1686 | |||
1687 | return newAv; | ||
1688 | } | ||
1689 | |||
1690 | public void AddCharacter(OdeCharacter chr) | ||
1691 | { | ||
1692 | lock (_characters) | ||
1693 | { | ||
1694 | if (!_characters.Contains(chr)) | ||
1695 | { | ||
1696 | _characters.Add(chr); | ||
1697 | if (chr.bad) | ||
1698 | m_log.DebugFormat("[PHYSICS] Added BAD actor {0} to characters list", chr.m_uuid); | ||
1699 | } | ||
1700 | } | ||
1701 | } | ||
1702 | |||
1703 | public void RemoveCharacter(OdeCharacter chr) | ||
1704 | { | ||
1705 | lock (_characters) | ||
1706 | { | ||
1707 | if (_characters.Contains(chr)) | ||
1708 | { | ||
1709 | _characters.Remove(chr); | ||
1710 | } | ||
1711 | } | ||
1712 | } | ||
1713 | public void BadCharacter(OdeCharacter chr) | ||
1714 | { | ||
1715 | lock (_badCharacter) | ||
1716 | { | ||
1717 | if (!_badCharacter.Contains(chr)) | ||
1718 | _badCharacter.Add(chr); | ||
1719 | } | ||
1720 | } | ||
1721 | |||
1722 | public override void RemoveAvatar(PhysicsActor actor) | ||
1723 | { | ||
1724 | //m_log.Debug("[PHYSICS]:ODELOCK"); | ||
1725 | ((OdeCharacter) actor).Destroy(); | ||
1726 | |||
1727 | } | ||
1728 | |||
1729 | private PhysicsActor AddPrim(String name, Vector3 position, Vector3 size, Quaternion rotation, | ||
1730 | IMesh mesh, PrimitiveBaseShape pbs, bool isphysical) | ||
1731 | { | ||
1732 | |||
1733 | Vector3 pos = position; | ||
1734 | Vector3 siz = size; | ||
1735 | Quaternion rot = rotation; | ||
1736 | |||
1737 | OdePrim newPrim; | ||
1738 | lock (OdeLock) | ||
1739 | { | ||
1740 | newPrim = new OdePrim(name, this, pos, siz, rot, mesh, pbs, isphysical, ode); | ||
1741 | |||
1742 | lock (_prims) | ||
1743 | _prims.Add(newPrim); | ||
1744 | } | ||
1745 | |||
1746 | return newPrim; | ||
1747 | } | ||
1748 | |||
1749 | public void addActivePrim(OdePrim activatePrim) | ||
1750 | { | ||
1751 | // adds active prim.. (ones that should be iterated over in collisions_optimized | ||
1752 | lock (_activeprims) | ||
1753 | { | ||
1754 | if (!_activeprims.Contains(activatePrim)) | ||
1755 | _activeprims.Add(activatePrim); | ||
1756 | //else | ||
1757 | // m_log.Warn("[PHYSICS]: Double Entry in _activeprims detected, potential crash immenent"); | ||
1758 | } | ||
1759 | } | ||
1760 | |||
1761 | public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, | ||
1762 | Vector3 size, Quaternion rotation) //To be removed | ||
1763 | { | ||
1764 | return AddPrimShape(primName, pbs, position, size, rotation, false); | ||
1765 | } | ||
1766 | |||
1767 | public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, | ||
1768 | Vector3 size, Quaternion rotation, bool isPhysical) | ||
1769 | { | ||
1770 | PhysicsActor result; | ||
1771 | IMesh mesh = null; | ||
1772 | |||
1773 | if (needsMeshing(pbs)) | ||
1774 | mesh = mesher.CreateMesh(primName, pbs, size, 32f, isPhysical); | ||
1775 | |||
1776 | result = AddPrim(primName, position, size, rotation, mesh, pbs, isPhysical); | ||
1777 | |||
1778 | return result; | ||
1779 | } | ||
1780 | |||
1781 | public override float TimeDilation | ||
1782 | { | ||
1783 | get { return m_timeDilation; } | ||
1784 | } | ||
1785 | |||
1786 | public override bool SupportsNINJAJoints | ||
1787 | { | ||
1788 | get { return m_NINJA_physics_joints_enabled; } | ||
1789 | } | ||
1790 | |||
1791 | // internal utility function: must be called within a lock (OdeLock) | ||
1792 | private void InternalAddActiveJoint(PhysicsJoint joint) | ||
1793 | { | ||
1794 | activeJoints.Add(joint); | ||
1795 | SOPName_to_activeJoint.Add(joint.ObjectNameInScene, joint); | ||
1796 | } | ||
1797 | |||
1798 | // internal utility function: must be called within a lock (OdeLock) | ||
1799 | private void InternalAddPendingJoint(OdePhysicsJoint joint) | ||
1800 | { | ||
1801 | pendingJoints.Add(joint); | ||
1802 | SOPName_to_pendingJoint.Add(joint.ObjectNameInScene, joint); | ||
1803 | } | ||
1804 | |||
1805 | // internal utility function: must be called within a lock (OdeLock) | ||
1806 | private void InternalRemovePendingJoint(PhysicsJoint joint) | ||
1807 | { | ||
1808 | pendingJoints.Remove(joint); | ||
1809 | SOPName_to_pendingJoint.Remove(joint.ObjectNameInScene); | ||
1810 | } | ||
1811 | |||
1812 | // internal utility function: must be called within a lock (OdeLock) | ||
1813 | private void InternalRemoveActiveJoint(PhysicsJoint joint) | ||
1814 | { | ||
1815 | activeJoints.Remove(joint); | ||
1816 | SOPName_to_activeJoint.Remove(joint.ObjectNameInScene); | ||
1817 | } | ||
1818 | |||
1819 | public override void DumpJointInfo() | ||
1820 | { | ||
1821 | string hdr = "[NINJA] JOINTINFO: "; | ||
1822 | foreach (PhysicsJoint j in pendingJoints) | ||
1823 | { | ||
1824 | m_log.Debug(hdr + " pending joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams); | ||
1825 | } | ||
1826 | m_log.Debug(hdr + pendingJoints.Count + " total pending joints"); | ||
1827 | foreach (string jointName in SOPName_to_pendingJoint.Keys) | ||
1828 | { | ||
1829 | m_log.Debug(hdr + " pending joints dict contains Name: " + jointName); | ||
1830 | } | ||
1831 | m_log.Debug(hdr + SOPName_to_pendingJoint.Keys.Count + " total pending joints dict entries"); | ||
1832 | foreach (PhysicsJoint j in activeJoints) | ||
1833 | { | ||
1834 | m_log.Debug(hdr + " active joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams); | ||
1835 | } | ||
1836 | m_log.Debug(hdr + activeJoints.Count + " total active joints"); | ||
1837 | foreach (string jointName in SOPName_to_activeJoint.Keys) | ||
1838 | { | ||
1839 | m_log.Debug(hdr + " active joints dict contains Name: " + jointName); | ||
1840 | } | ||
1841 | m_log.Debug(hdr + SOPName_to_activeJoint.Keys.Count + " total active joints dict entries"); | ||
1842 | |||
1843 | m_log.Debug(hdr + " Per-body joint connectivity information follows."); | ||
1844 | m_log.Debug(hdr + joints_connecting_actor.Keys.Count + " bodies are connected by joints."); | ||
1845 | foreach (string actorName in joints_connecting_actor.Keys) | ||
1846 | { | ||
1847 | m_log.Debug(hdr + " Actor " + actorName + " has the following joints connecting it"); | ||
1848 | foreach (PhysicsJoint j in joints_connecting_actor[actorName]) | ||
1849 | { | ||
1850 | m_log.Debug(hdr + " * joint Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams); | ||
1851 | } | ||
1852 | m_log.Debug(hdr + joints_connecting_actor[actorName].Count + " connecting joints total for this actor"); | ||
1853 | } | ||
1854 | } | ||
1855 | |||
1856 | public override void RequestJointDeletion(string ObjectNameInScene) | ||
1857 | { | ||
1858 | lock (externalJointRequestsLock) | ||
1859 | { | ||
1860 | if (!requestedJointsToBeDeleted.Contains(ObjectNameInScene)) // forbid same deletion request from entering twice to prevent spurious deletions processed asynchronously | ||
1861 | { | ||
1862 | requestedJointsToBeDeleted.Add(ObjectNameInScene); | ||
1863 | } | ||
1864 | } | ||
1865 | } | ||
1866 | |||
1867 | private void DeleteRequestedJoints() | ||
1868 | { | ||
1869 | List<string> myRequestedJointsToBeDeleted; | ||
1870 | lock (externalJointRequestsLock) | ||
1871 | { | ||
1872 | // make a local copy of the shared list for processing (threading issues) | ||
1873 | myRequestedJointsToBeDeleted = new List<string>(requestedJointsToBeDeleted); | ||
1874 | } | ||
1875 | |||
1876 | foreach (string jointName in myRequestedJointsToBeDeleted) | ||
1877 | { | ||
1878 | lock (OdeLock) | ||
1879 | { | ||
1880 | //m_log.Debug("[NINJA] trying to deleting requested joint " + jointName); | ||
1881 | if (SOPName_to_activeJoint.ContainsKey(jointName) || SOPName_to_pendingJoint.ContainsKey(jointName)) | ||
1882 | { | ||
1883 | OdePhysicsJoint joint = null; | ||
1884 | if (SOPName_to_activeJoint.ContainsKey(jointName)) | ||
1885 | { | ||
1886 | joint = SOPName_to_activeJoint[jointName] as OdePhysicsJoint; | ||
1887 | InternalRemoveActiveJoint(joint); | ||
1888 | } | ||
1889 | else if (SOPName_to_pendingJoint.ContainsKey(jointName)) | ||
1890 | { | ||
1891 | joint = SOPName_to_pendingJoint[jointName] as OdePhysicsJoint; | ||
1892 | InternalRemovePendingJoint(joint); | ||
1893 | } | ||
1894 | |||
1895 | if (joint != null) | ||
1896 | { | ||
1897 | //m_log.Debug("joint.BodyNames.Count is " + joint.BodyNames.Count + " and contents " + joint.BodyNames); | ||
1898 | for (int iBodyName = 0; iBodyName < 2; iBodyName++) | ||
1899 | { | ||
1900 | string bodyName = joint.BodyNames[iBodyName]; | ||
1901 | if (bodyName != "NULL") | ||
1902 | { | ||
1903 | joints_connecting_actor[bodyName].Remove(joint); | ||
1904 | if (joints_connecting_actor[bodyName].Count == 0) | ||
1905 | { | ||
1906 | joints_connecting_actor.Remove(bodyName); | ||
1907 | } | ||
1908 | } | ||
1909 | } | ||
1910 | |||
1911 | DoJointDeactivated(joint); | ||
1912 | if (joint.jointID != IntPtr.Zero) | ||
1913 | { | ||
1914 | d.JointDestroy(joint.jointID); | ||
1915 | joint.jointID = IntPtr.Zero; | ||
1916 | //DoJointErrorMessage(joint, "successfully destroyed joint " + jointName); | ||
1917 | } | ||
1918 | else | ||
1919 | { | ||
1920 | //m_log.Warn("[NINJA] Ignoring re-request to destroy joint " + jointName); | ||
1921 | } | ||
1922 | } | ||
1923 | else | ||
1924 | { | ||
1925 | // DoJointErrorMessage(joint, "coult not find joint to destroy based on name " + jointName); | ||
1926 | } | ||
1927 | } | ||
1928 | else | ||
1929 | { | ||
1930 | // DoJointErrorMessage(joint, "WARNING - joint removal failed, joint " + jointName); | ||
1931 | } | ||
1932 | } | ||
1933 | } | ||
1934 | |||
1935 | // remove processed joints from the shared list | ||
1936 | lock (externalJointRequestsLock) | ||
1937 | { | ||
1938 | foreach (string jointName in myRequestedJointsToBeDeleted) | ||
1939 | { | ||
1940 | requestedJointsToBeDeleted.Remove(jointName); | ||
1941 | } | ||
1942 | } | ||
1943 | } | ||
1944 | |||
1945 | // for pending joints we don't know if their associated bodies exist yet or not. | ||
1946 | // the joint is actually created during processing of the taints | ||
1947 | private void CreateRequestedJoints() | ||
1948 | { | ||
1949 | List<PhysicsJoint> myRequestedJointsToBeCreated; | ||
1950 | lock (externalJointRequestsLock) | ||
1951 | { | ||
1952 | // make a local copy of the shared list for processing (threading issues) | ||
1953 | myRequestedJointsToBeCreated = new List<PhysicsJoint>(requestedJointsToBeCreated); | ||
1954 | } | ||
1955 | |||
1956 | foreach (PhysicsJoint joint in myRequestedJointsToBeCreated) | ||
1957 | { | ||
1958 | lock (OdeLock) | ||
1959 | { | ||
1960 | if (SOPName_to_pendingJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_pendingJoint[joint.ObjectNameInScene] != null) | ||
1961 | { | ||
1962 | DoJointErrorMessage(joint, "WARNING: ignoring request to re-add already pending joint Name:" + joint.ObjectNameInScene + " type:" + joint.Type + " parms: " + joint.RawParams + " pos: " + joint.Position + " rot:" + joint.Rotation); | ||
1963 | continue; | ||
1964 | } | ||
1965 | if (SOPName_to_activeJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_activeJoint[joint.ObjectNameInScene] != null) | ||
1966 | { | ||
1967 | DoJointErrorMessage(joint, "WARNING: ignoring request to re-add already active joint Name:" + joint.ObjectNameInScene + " type:" + joint.Type + " parms: " + joint.RawParams + " pos: " + joint.Position + " rot:" + joint.Rotation); | ||
1968 | continue; | ||
1969 | } | ||
1970 | |||
1971 | InternalAddPendingJoint(joint as OdePhysicsJoint); | ||
1972 | |||
1973 | if (joint.BodyNames.Count >= 2) | ||
1974 | { | ||
1975 | for (int iBodyName = 0; iBodyName < 2; iBodyName++) | ||
1976 | { | ||
1977 | string bodyName = joint.BodyNames[iBodyName]; | ||
1978 | if (bodyName != "NULL") | ||
1979 | { | ||
1980 | if (!joints_connecting_actor.ContainsKey(bodyName)) | ||
1981 | { | ||
1982 | joints_connecting_actor.Add(bodyName, new List<PhysicsJoint>()); | ||
1983 | } | ||
1984 | joints_connecting_actor[bodyName].Add(joint); | ||
1985 | } | ||
1986 | } | ||
1987 | } | ||
1988 | } | ||
1989 | } | ||
1990 | |||
1991 | // remove processed joints from shared list | ||
1992 | lock (externalJointRequestsLock) | ||
1993 | { | ||
1994 | foreach (PhysicsJoint joint in myRequestedJointsToBeCreated) | ||
1995 | { | ||
1996 | requestedJointsToBeCreated.Remove(joint); | ||
1997 | } | ||
1998 | } | ||
1999 | |||
2000 | } | ||
2001 | |||
2002 | // public function to add an request for joint creation | ||
2003 | // this joint will just be added to a waiting list that is NOT processed during the main | ||
2004 | // Simulate() loop (to avoid deadlocks). After Simulate() is finished, we handle unprocessed joint requests. | ||
2005 | |||
2006 | public override PhysicsJoint RequestJointCreation(string objectNameInScene, PhysicsJointType jointType, Vector3 position, | ||
2007 | Quaternion rotation, string parms, List<string> bodyNames, string trackedBodyName, Quaternion localRotation) | ||
2008 | |||
2009 | { | ||
2010 | |||
2011 | OdePhysicsJoint joint = new OdePhysicsJoint(); | ||
2012 | joint.ObjectNameInScene = objectNameInScene; | ||
2013 | joint.Type = jointType; | ||
2014 | joint.Position = position; | ||
2015 | joint.Rotation = rotation; | ||
2016 | joint.RawParams = parms; | ||
2017 | joint.BodyNames = new List<string>(bodyNames); | ||
2018 | joint.TrackedBodyName = trackedBodyName; | ||
2019 | joint.LocalRotation = localRotation; | ||
2020 | joint.jointID = IntPtr.Zero; | ||
2021 | joint.ErrorMessageCount = 0; | ||
2022 | |||
2023 | lock (externalJointRequestsLock) | ||
2024 | { | ||
2025 | if (!requestedJointsToBeCreated.Contains(joint)) // forbid same creation request from entering twice | ||
2026 | { | ||
2027 | requestedJointsToBeCreated.Add(joint); | ||
2028 | } | ||
2029 | } | ||
2030 | return joint; | ||
2031 | } | ||
2032 | |||
2033 | private void RemoveAllJointsConnectedToActor(PhysicsActor actor) | ||
2034 | { | ||
2035 | //m_log.Debug("RemoveAllJointsConnectedToActor: start"); | ||
2036 | if (actor.SOPName != null && joints_connecting_actor.ContainsKey(actor.SOPName) && joints_connecting_actor[actor.SOPName] != null) | ||
2037 | { | ||
2038 | |||
2039 | List<PhysicsJoint> jointsToRemove = new List<PhysicsJoint>(); | ||
2040 | //TODO: merge these 2 loops (originally it was needed to avoid altering a list being iterated over, but it is no longer needed due to the joint request queue mechanism) | ||
2041 | foreach (PhysicsJoint j in joints_connecting_actor[actor.SOPName]) | ||
2042 | { | ||
2043 | jointsToRemove.Add(j); | ||
2044 | } | ||
2045 | foreach (PhysicsJoint j in jointsToRemove) | ||
2046 | { | ||
2047 | //m_log.Debug("RemoveAllJointsConnectedToActor: about to request deletion of " + j.ObjectNameInScene); | ||
2048 | RequestJointDeletion(j.ObjectNameInScene); | ||
2049 | //m_log.Debug("RemoveAllJointsConnectedToActor: done request deletion of " + j.ObjectNameInScene); | ||
2050 | j.TrackedBodyName = null; // *IMMEDIATELY* prevent any further movement of this joint (else a deleted actor might cause spurious tracking motion of the joint for a few frames, leading to the joint proxy object disappearing) | ||
2051 | } | ||
2052 | } | ||
2053 | } | ||
2054 | |||
2055 | public override void RemoveAllJointsConnectedToActorThreadLocked(PhysicsActor actor) | ||
2056 | { | ||
2057 | //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: start"); | ||
2058 | lock (OdeLock) | ||
2059 | { | ||
2060 | //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: got lock"); | ||
2061 | RemoveAllJointsConnectedToActor(actor); | ||
2062 | } | ||
2063 | } | ||
2064 | |||
2065 | // normally called from within OnJointMoved, which is called from within a lock (OdeLock) | ||
2066 | public override Vector3 GetJointAnchor(PhysicsJoint joint) | ||
2067 | { | ||
2068 | Debug.Assert(joint.IsInPhysicsEngine); | ||
2069 | d.Vector3 pos = new d.Vector3(); | ||
2070 | |||
2071 | if (!(joint is OdePhysicsJoint)) | ||
2072 | { | ||
2073 | DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene); | ||
2074 | } | ||
2075 | else | ||
2076 | { | ||
2077 | OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint; | ||
2078 | switch (odeJoint.Type) | ||
2079 | { | ||
2080 | case PhysicsJointType.Ball: | ||
2081 | d.JointGetBallAnchor(odeJoint.jointID, out pos); | ||
2082 | break; | ||
2083 | case PhysicsJointType.Hinge: | ||
2084 | d.JointGetHingeAnchor(odeJoint.jointID, out pos); | ||
2085 | break; | ||
2086 | } | ||
2087 | } | ||
2088 | return new Vector3(pos.X, pos.Y, pos.Z); | ||
2089 | } | ||
2090 | |||
2091 | // normally called from within OnJointMoved, which is called from within a lock (OdeLock) | ||
2092 | // WARNING: ODE sometimes returns <0,0,0> as the joint axis! Therefore this function | ||
2093 | // appears to be unreliable. Fortunately we can compute the joint axis ourselves by | ||
2094 | // keeping track of the joint's original orientation relative to one of the involved bodies. | ||
2095 | public override Vector3 GetJointAxis(PhysicsJoint joint) | ||
2096 | { | ||
2097 | Debug.Assert(joint.IsInPhysicsEngine); | ||
2098 | d.Vector3 axis = new d.Vector3(); | ||
2099 | |||
2100 | if (!(joint is OdePhysicsJoint)) | ||
2101 | { | ||
2102 | DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene); | ||
2103 | } | ||
2104 | else | ||
2105 | { | ||
2106 | OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint; | ||
2107 | switch (odeJoint.Type) | ||
2108 | { | ||
2109 | case PhysicsJointType.Ball: | ||
2110 | DoJointErrorMessage(joint, "warning - axis requested for ball joint: " + joint.ObjectNameInScene); | ||
2111 | break; | ||
2112 | case PhysicsJointType.Hinge: | ||
2113 | d.JointGetHingeAxis(odeJoint.jointID, out axis); | ||
2114 | break; | ||
2115 | } | ||
2116 | } | ||
2117 | return new Vector3(axis.X, axis.Y, axis.Z); | ||
2118 | } | ||
2119 | |||
2120 | |||
2121 | public void remActivePrim(OdePrim deactivatePrim) | ||
2122 | { | ||
2123 | lock (_activeprims) | ||
2124 | { | ||
2125 | _activeprims.Remove(deactivatePrim); | ||
2126 | } | ||
2127 | } | ||
2128 | |||
2129 | public override void RemovePrim(PhysicsActor prim) | ||
2130 | { | ||
2131 | if (prim is OdePrim) | ||
2132 | { | ||
2133 | lock (OdeLock) | ||
2134 | { | ||
2135 | OdePrim p = (OdePrim) prim; | ||
2136 | |||
2137 | p.setPrimForRemoval(); | ||
2138 | AddPhysicsActorTaint(prim); | ||
2139 | //RemovePrimThreadLocked(p); | ||
2140 | } | ||
2141 | } | ||
2142 | } | ||
2143 | |||
2144 | /// <summary> | ||
2145 | /// This is called from within simulate but outside the locked portion | ||
2146 | /// We need to do our own locking here | ||
2147 | /// Essentially, we need to remove the prim from our space segment, whatever segment it's in. | ||
2148 | /// | ||
2149 | /// If there are no more prim in the segment, we need to empty (spacedestroy)the segment and reclaim memory | ||
2150 | /// that the space was using. | ||
2151 | /// </summary> | ||
2152 | /// <param name="prim"></param> | ||
2153 | public void RemovePrimThreadLocked(OdePrim prim) | ||
2154 | { | ||
2155 | //Console.WriteLine("RemovePrimThreadLocked " + prim.m_primName); | ||
2156 | lock (prim) | ||
2157 | { | ||
2158 | remCollisionEventReporting(prim); | ||
2159 | lock (ode) | ||
2160 | { | ||
2161 | if (prim.prim_geom != IntPtr.Zero) | ||
2162 | { | ||
2163 | prim.ResetTaints(); | ||
2164 | |||
2165 | if (prim.IsPhysical) | ||
2166 | { | ||
2167 | prim.disableBody(); | ||
2168 | if (prim.childPrim) | ||
2169 | { | ||
2170 | prim.childPrim = false; | ||
2171 | prim.Body = IntPtr.Zero; | ||
2172 | prim.m_disabled = true; | ||
2173 | prim.IsPhysical = false; | ||
2174 | } | ||
2175 | |||
2176 | |||
2177 | } | ||
2178 | // we don't want to remove the main space | ||
2179 | |||
2180 | // If the geometry is in the targetspace, remove it from the target space | ||
2181 | //m_log.Warn(prim.m_targetSpace); | ||
2182 | |||
2183 | //if (prim.m_targetSpace != IntPtr.Zero) | ||
2184 | //{ | ||
2185 | //if (d.SpaceQuery(prim.m_targetSpace, prim.prim_geom)) | ||
2186 | //{ | ||
2187 | |||
2188 | //if (d.GeomIsSpace(prim.m_targetSpace)) | ||
2189 | //{ | ||
2190 | //waitForSpaceUnlock(prim.m_targetSpace); | ||
2191 | //d.SpaceRemove(prim.m_targetSpace, prim.prim_geom); | ||
2192 | prim.m_targetSpace = IntPtr.Zero; | ||
2193 | //} | ||
2194 | //else | ||
2195 | //{ | ||
2196 | // m_log.Info("[Physics]: Invalid Scene passed to 'removeprim from scene':" + | ||
2197 | //((OdePrim)prim).m_targetSpace.ToString()); | ||
2198 | //} | ||
2199 | |||
2200 | //} | ||
2201 | //} | ||
2202 | //m_log.Warn(prim.prim_geom); | ||
2203 | try | ||
2204 | { | ||
2205 | if (prim.prim_geom != IntPtr.Zero) | ||
2206 | { | ||
2207 | d.GeomDestroy(prim.prim_geom); | ||
2208 | prim.prim_geom = IntPtr.Zero; | ||
2209 | } | ||
2210 | else | ||
2211 | { | ||
2212 | m_log.Warn("[PHYSICS]: Unable to remove prim from physics scene"); | ||
2213 | } | ||
2214 | } | ||
2215 | catch (AccessViolationException) | ||
2216 | { | ||
2217 | m_log.Info("[PHYSICS]: Couldn't remove prim from physics scene, it was already be removed."); | ||
2218 | } | ||
2219 | lock (_prims) | ||
2220 | _prims.Remove(prim); | ||
2221 | |||
2222 | //If there are no more geometries in the sub-space, we don't need it in the main space anymore | ||
2223 | //if (d.SpaceGetNumGeoms(prim.m_targetSpace) == 0) | ||
2224 | //{ | ||
2225 | //if (prim.m_targetSpace != null) | ||
2226 | //{ | ||
2227 | //if (d.GeomIsSpace(prim.m_targetSpace)) | ||
2228 | //{ | ||
2229 | //waitForSpaceUnlock(prim.m_targetSpace); | ||
2230 | //d.SpaceRemove(space, prim.m_targetSpace); | ||
2231 | // free up memory used by the space. | ||
2232 | //d.SpaceDestroy(prim.m_targetSpace); | ||
2233 | //int[] xyspace = calculateSpaceArrayItemFromPos(prim.Position); | ||
2234 | //resetSpaceArrayItemToZero(xyspace[0], xyspace[1]); | ||
2235 | //} | ||
2236 | //else | ||
2237 | //{ | ||
2238 | //m_log.Info("[Physics]: Invalid Scene passed to 'removeprim from scene':" + | ||
2239 | //((OdePrim) prim).m_targetSpace.ToString()); | ||
2240 | //} | ||
2241 | //} | ||
2242 | //} | ||
2243 | |||
2244 | if (SupportsNINJAJoints) | ||
2245 | { | ||
2246 | RemoveAllJointsConnectedToActorThreadLocked(prim); | ||
2247 | } | ||
2248 | } | ||
2249 | } | ||
2250 | } | ||
2251 | } | ||
2252 | |||
2253 | #endregion | ||
2254 | |||
2255 | #region Space Separation Calculation | ||
2256 | |||
2257 | /// <summary> | ||
2258 | /// Takes a space pointer and zeros out the array we're using to hold the spaces | ||
2259 | /// </summary> | ||
2260 | /// <param name="pSpace"></param> | ||
2261 | public void resetSpaceArrayItemToZero(IntPtr pSpace) | ||
2262 | { | ||
2263 | for (int x = 0; x < staticPrimspace.GetLength(0); x++) | ||
2264 | { | ||
2265 | for (int y = 0; y < staticPrimspace.GetLength(1); y++) | ||
2266 | { | ||
2267 | if (staticPrimspace[x, y] == pSpace) | ||
2268 | staticPrimspace[x, y] = IntPtr.Zero; | ||
2269 | } | ||
2270 | } | ||
2271 | } | ||
2272 | |||
2273 | public void resetSpaceArrayItemToZero(int arrayitemX, int arrayitemY) | ||
2274 | { | ||
2275 | staticPrimspace[arrayitemX, arrayitemY] = IntPtr.Zero; | ||
2276 | } | ||
2277 | |||
2278 | /// <summary> | ||
2279 | /// Called when a static prim moves. Allocates a space for the prim based on its position | ||
2280 | /// </summary> | ||
2281 | /// <param name="geom">the pointer to the geom that moved</param> | ||
2282 | /// <param name="pos">the position that the geom moved to</param> | ||
2283 | /// <param name="currentspace">a pointer to the space it was in before it was moved.</param> | ||
2284 | /// <returns>a pointer to the new space it's in</returns> | ||
2285 | public IntPtr recalculateSpaceForGeom(IntPtr geom, Vector3 pos, IntPtr currentspace) | ||
2286 | { | ||
2287 | // Called from setting the Position and Size of an ODEPrim so | ||
2288 | // it's already in locked space. | ||
2289 | |||
2290 | // we don't want to remove the main space | ||
2291 | // we don't need to test physical here because this function should | ||
2292 | // never be called if the prim is physical(active) | ||
2293 | |||
2294 | // All physical prim end up in the root space | ||
2295 | //Thread.Sleep(20); | ||
2296 | if (currentspace != space) | ||
2297 | { | ||
2298 | //m_log.Info("[SPACE]: C:" + currentspace.ToString() + " g:" + geom.ToString()); | ||
2299 | //if (currentspace == IntPtr.Zero) | ||
2300 | //{ | ||
2301 | //int adfadf = 0; | ||
2302 | //} | ||
2303 | if (d.SpaceQuery(currentspace, geom) && currentspace != IntPtr.Zero) | ||
2304 | { | ||
2305 | if (d.GeomIsSpace(currentspace)) | ||
2306 | { | ||
2307 | waitForSpaceUnlock(currentspace); | ||
2308 | d.SpaceRemove(currentspace, geom); | ||
2309 | } | ||
2310 | else | ||
2311 | { | ||
2312 | m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" + currentspace + | ||
2313 | " Geom:" + geom); | ||
2314 | } | ||
2315 | } | ||
2316 | else | ||
2317 | { | ||
2318 | IntPtr sGeomIsIn = d.GeomGetSpace(geom); | ||
2319 | if (sGeomIsIn != IntPtr.Zero) | ||
2320 | { | ||
2321 | if (d.GeomIsSpace(currentspace)) | ||
2322 | { | ||
2323 | waitForSpaceUnlock(sGeomIsIn); | ||
2324 | d.SpaceRemove(sGeomIsIn, geom); | ||
2325 | } | ||
2326 | else | ||
2327 | { | ||
2328 | m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" + | ||
2329 | sGeomIsIn + " Geom:" + geom); | ||
2330 | } | ||
2331 | } | ||
2332 | } | ||
2333 | |||
2334 | //If there are no more geometries in the sub-space, we don't need it in the main space anymore | ||
2335 | if (d.SpaceGetNumGeoms(currentspace) == 0) | ||
2336 | { | ||
2337 | if (currentspace != IntPtr.Zero) | ||
2338 | { | ||
2339 | if (d.GeomIsSpace(currentspace)) | ||
2340 | { | ||
2341 | waitForSpaceUnlock(currentspace); | ||
2342 | waitForSpaceUnlock(space); | ||
2343 | d.SpaceRemove(space, currentspace); | ||
2344 | // free up memory used by the space. | ||
2345 | |||
2346 | //d.SpaceDestroy(currentspace); | ||
2347 | resetSpaceArrayItemToZero(currentspace); | ||
2348 | } | ||
2349 | else | ||
2350 | { | ||
2351 | m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" + | ||
2352 | currentspace + " Geom:" + geom); | ||
2353 | } | ||
2354 | } | ||
2355 | } | ||
2356 | } | ||
2357 | else | ||
2358 | { | ||
2359 | // this is a physical object that got disabled. ;.; | ||
2360 | if (currentspace != IntPtr.Zero && geom != IntPtr.Zero) | ||
2361 | { | ||
2362 | if (d.SpaceQuery(currentspace, geom)) | ||
2363 | { | ||
2364 | if (d.GeomIsSpace(currentspace)) | ||
2365 | { | ||
2366 | waitForSpaceUnlock(currentspace); | ||
2367 | d.SpaceRemove(currentspace, geom); | ||
2368 | } | ||
2369 | else | ||
2370 | { | ||
2371 | m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" + | ||
2372 | currentspace + " Geom:" + geom); | ||
2373 | } | ||
2374 | } | ||
2375 | else | ||
2376 | { | ||
2377 | IntPtr sGeomIsIn = d.GeomGetSpace(geom); | ||
2378 | if (sGeomIsIn != IntPtr.Zero) | ||
2379 | { | ||
2380 | if (d.GeomIsSpace(sGeomIsIn)) | ||
2381 | { | ||
2382 | waitForSpaceUnlock(sGeomIsIn); | ||
2383 | d.SpaceRemove(sGeomIsIn, geom); | ||
2384 | } | ||
2385 | else | ||
2386 | { | ||
2387 | m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" + | ||
2388 | sGeomIsIn + " Geom:" + geom); | ||
2389 | } | ||
2390 | } | ||
2391 | } | ||
2392 | } | ||
2393 | } | ||
2394 | |||
2395 | // The routines in the Position and Size sections do the 'inserting' into the space, | ||
2396 | // so all we have to do is make sure that the space that we're putting the prim into | ||
2397 | // is in the 'main' space. | ||
2398 | int[] iprimspaceArrItem = calculateSpaceArrayItemFromPos(pos); | ||
2399 | IntPtr newspace = calculateSpaceForGeom(pos); | ||
2400 | |||
2401 | if (newspace == IntPtr.Zero) | ||
2402 | { | ||
2403 | newspace = createprimspace(iprimspaceArrItem[0], iprimspaceArrItem[1]); | ||
2404 | d.HashSpaceSetLevels(newspace, smallHashspaceLow, smallHashspaceHigh); | ||
2405 | } | ||
2406 | |||
2407 | return newspace; | ||
2408 | } | ||
2409 | |||
2410 | /// <summary> | ||
2411 | /// Creates a new space at X Y | ||
2412 | /// </summary> | ||
2413 | /// <param name="iprimspaceArrItemX"></param> | ||
2414 | /// <param name="iprimspaceArrItemY"></param> | ||
2415 | /// <returns>A pointer to the created space</returns> | ||
2416 | public IntPtr createprimspace(int iprimspaceArrItemX, int iprimspaceArrItemY) | ||
2417 | { | ||
2418 | // creating a new space for prim and inserting it into main space. | ||
2419 | staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY] = d.HashSpaceCreate(IntPtr.Zero); | ||
2420 | d.GeomSetCategoryBits(staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY], (int)CollisionCategories.Space); | ||
2421 | waitForSpaceUnlock(space); | ||
2422 | d.SpaceSetSublevel(space, 1); | ||
2423 | d.SpaceAdd(space, staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY]); | ||
2424 | return staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY]; | ||
2425 | } | ||
2426 | |||
2427 | /// <summary> | ||
2428 | /// Calculates the space the prim should be in by its position | ||
2429 | /// </summary> | ||
2430 | /// <param name="pos"></param> | ||
2431 | /// <returns>a pointer to the space. This could be a new space or reused space.</returns> | ||
2432 | public IntPtr calculateSpaceForGeom(Vector3 pos) | ||
2433 | { | ||
2434 | int[] xyspace = calculateSpaceArrayItemFromPos(pos); | ||
2435 | //m_log.Info("[Physics]: Attempting to use arrayItem: " + xyspace[0].ToString() + "," + xyspace[1].ToString()); | ||
2436 | return staticPrimspace[xyspace[0], xyspace[1]]; | ||
2437 | } | ||
2438 | |||
2439 | /// <summary> | ||
2440 | /// Holds the space allocation logic | ||
2441 | /// </summary> | ||
2442 | /// <param name="pos"></param> | ||
2443 | /// <returns>an array item based on the position</returns> | ||
2444 | public int[] calculateSpaceArrayItemFromPos(Vector3 pos) | ||
2445 | { | ||
2446 | int[] returnint = new int[2]; | ||
2447 | |||
2448 | returnint[0] = (int) (pos.X/metersInSpace); | ||
2449 | |||
2450 | if (returnint[0] > ((int) (259f/metersInSpace))) | ||
2451 | returnint[0] = ((int) (259f/metersInSpace)); | ||
2452 | if (returnint[0] < 0) | ||
2453 | returnint[0] = 0; | ||
2454 | |||
2455 | returnint[1] = (int) (pos.Y/metersInSpace); | ||
2456 | if (returnint[1] > ((int) (259f/metersInSpace))) | ||
2457 | returnint[1] = ((int) (259f/metersInSpace)); | ||
2458 | if (returnint[1] < 0) | ||
2459 | returnint[1] = 0; | ||
2460 | |||
2461 | return returnint; | ||
2462 | } | ||
2463 | |||
2464 | #endregion | ||
2465 | |||
2466 | /// <summary> | ||
2467 | /// Routine to figure out if we need to mesh this prim with our mesher | ||
2468 | /// </summary> | ||
2469 | /// <param name="pbs"></param> | ||
2470 | /// <returns></returns> | ||
2471 | public bool needsMeshing(PrimitiveBaseShape pbs) | ||
2472 | { | ||
2473 | // most of this is redundant now as the mesher will return null if it cant mesh a prim | ||
2474 | // but we still need to check for sculptie meshing being enabled so this is the most | ||
2475 | // convenient place to do it for now... | ||
2476 | |||
2477 | // //if (pbs.PathCurve == (byte)Primitive.PathCurve.Circle && pbs.ProfileCurve == (byte)Primitive.ProfileCurve.Circle && pbs.PathScaleY <= 0.75f) | ||
2478 | // //m_log.Debug("needsMeshing: " + " pathCurve: " + pbs.PathCurve.ToString() + " profileCurve: " + pbs.ProfileCurve.ToString() + " pathScaleY: " + Primitive.UnpackPathScale(pbs.PathScaleY).ToString()); | ||
2479 | int iPropertiesNotSupportedDefault = 0; | ||
2480 | |||
2481 | if (pbs.SculptEntry && !meshSculptedPrim) | ||
2482 | { | ||
2483 | #if SPAM | ||
2484 | m_log.Warn("NonMesh"); | ||
2485 | #endif | ||
2486 | return false; | ||
2487 | } | ||
2488 | |||
2489 | // if it's a standard box or sphere with no cuts, hollows, twist or top shear, return false since ODE can use an internal representation for the prim | ||
2490 | if (!forceSimplePrimMeshing) | ||
2491 | { | ||
2492 | if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) | ||
2493 | || (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1 | ||
2494 | && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)) | ||
2495 | { | ||
2496 | |||
2497 | if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 | ||
2498 | && pbs.ProfileHollow == 0 | ||
2499 | && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0 | ||
2500 | && pbs.PathBegin == 0 && pbs.PathEnd == 0 | ||
2501 | && pbs.PathTaperX == 0 && pbs.PathTaperY == 0 | ||
2502 | && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 | ||
2503 | && pbs.PathShearX == 0 && pbs.PathShearY == 0) | ||
2504 | { | ||
2505 | #if SPAM | ||
2506 | m_log.Warn("NonMesh"); | ||
2507 | #endif | ||
2508 | return false; | ||
2509 | } | ||
2510 | } | ||
2511 | } | ||
2512 | |||
2513 | if (pbs.ProfileHollow != 0) | ||
2514 | iPropertiesNotSupportedDefault++; | ||
2515 | |||
2516 | if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0)) | ||
2517 | iPropertiesNotSupportedDefault++; | ||
2518 | |||
2519 | if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0) | ||
2520 | iPropertiesNotSupportedDefault++; | ||
2521 | |||
2522 | if ((pbs.PathScaleX != 100) || (pbs.PathScaleY != 100)) | ||
2523 | iPropertiesNotSupportedDefault++; | ||
2524 | |||
2525 | if ((pbs.PathShearX != 0) || (pbs.PathShearY != 0)) | ||
2526 | iPropertiesNotSupportedDefault++; | ||
2527 | |||
2528 | if (pbs.ProfileShape == ProfileShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight) | ||
2529 | iPropertiesNotSupportedDefault++; | ||
2530 | |||
2531 | if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1 && (pbs.Scale.X != pbs.Scale.Y || pbs.Scale.Y != pbs.Scale.Z || pbs.Scale.Z != pbs.Scale.X)) | ||
2532 | iPropertiesNotSupportedDefault++; | ||
2533 | |||
2534 | if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte) Extrusion.Curve1) | ||
2535 | iPropertiesNotSupportedDefault++; | ||
2536 | |||
2537 | // test for torus | ||
2538 | if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Square) | ||
2539 | { | ||
2540 | if (pbs.PathCurve == (byte)Extrusion.Curve1) | ||
2541 | { | ||
2542 | iPropertiesNotSupportedDefault++; | ||
2543 | } | ||
2544 | } | ||
2545 | else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Circle) | ||
2546 | { | ||
2547 | if (pbs.PathCurve == (byte)Extrusion.Straight) | ||
2548 | { | ||
2549 | iPropertiesNotSupportedDefault++; | ||
2550 | } | ||
2551 | |||
2552 | // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits | ||
2553 | else if (pbs.PathCurve == (byte)Extrusion.Curve1) | ||
2554 | { | ||
2555 | iPropertiesNotSupportedDefault++; | ||
2556 | } | ||
2557 | } | ||
2558 | else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle) | ||
2559 | { | ||
2560 | if (pbs.PathCurve == (byte)Extrusion.Curve1 || pbs.PathCurve == (byte)Extrusion.Curve2) | ||
2561 | { | ||
2562 | iPropertiesNotSupportedDefault++; | ||
2563 | } | ||
2564 | } | ||
2565 | else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle) | ||
2566 | { | ||
2567 | if (pbs.PathCurve == (byte)Extrusion.Straight) | ||
2568 | { | ||
2569 | iPropertiesNotSupportedDefault++; | ||
2570 | } | ||
2571 | else if (pbs.PathCurve == (byte)Extrusion.Curve1) | ||
2572 | { | ||
2573 | iPropertiesNotSupportedDefault++; | ||
2574 | } | ||
2575 | } | ||
2576 | |||
2577 | |||
2578 | if (iPropertiesNotSupportedDefault == 0) | ||
2579 | { | ||
2580 | #if SPAM | ||
2581 | m_log.Warn("NonMesh"); | ||
2582 | #endif | ||
2583 | return false; | ||
2584 | } | ||
2585 | #if SPAM | ||
2586 | m_log.Debug("Mesh"); | ||
2587 | #endif | ||
2588 | return true; | ||
2589 | } | ||
2590 | |||
2591 | /// <summary> | ||
2592 | /// Called after our prim properties are set Scale, position etc. | ||
2593 | /// We use this event queue like method to keep changes to the physical scene occuring in the threadlocked mutex | ||
2594 | /// This assures us that we have no race conditions | ||
2595 | /// </summary> | ||
2596 | /// <param name="prim"></param> | ||
2597 | public override void AddPhysicsActorTaint(PhysicsActor prim) | ||
2598 | { | ||
2599 | |||
2600 | if (prim is OdePrim) | ||
2601 | { | ||
2602 | OdePrim taintedprim = ((OdePrim) prim); | ||
2603 | lock (_taintedPrimLock) | ||
2604 | { | ||
2605 | if (!(_taintedPrimH.Contains(taintedprim))) | ||
2606 | { | ||
2607 | //Console.WriteLine("AddPhysicsActorTaint to " + taintedprim.m_primName); | ||
2608 | _taintedPrimH.Add(taintedprim); // HashSet for searching | ||
2609 | _taintedPrimL.Add(taintedprim); // List for ordered readout | ||
2610 | } | ||
2611 | } | ||
2612 | return; | ||
2613 | } | ||
2614 | else if (prim is OdeCharacter) | ||
2615 | { | ||
2616 | OdeCharacter taintedchar = ((OdeCharacter)prim); | ||
2617 | lock (_taintedActors) | ||
2618 | { | ||
2619 | if (!(_taintedActors.Contains(taintedchar))) | ||
2620 | { | ||
2621 | _taintedActors.Add(taintedchar); | ||
2622 | if (taintedchar.bad) | ||
2623 | m_log.DebugFormat("[PHYSICS]: Added BAD actor {0} to tainted actors", taintedchar.m_uuid); | ||
2624 | } | ||
2625 | } | ||
2626 | } | ||
2627 | } | ||
2628 | |||
2629 | /// <summary> | ||
2630 | /// This is our main simulate loop | ||
2631 | /// It's thread locked by a Mutex in the scene. | ||
2632 | /// It holds Collisions, it instructs ODE to step through the physical reactions | ||
2633 | /// It moves the objects around in memory | ||
2634 | /// It calls the methods that report back to the object owners.. (scenepresence, SceneObjectGroup) | ||
2635 | /// </summary> | ||
2636 | /// <param name="timeStep"></param> | ||
2637 | /// <returns></returns> | ||
2638 | public override float Simulate(float timeStep) | ||
2639 | { | ||
2640 | if (framecount >= int.MaxValue) | ||
2641 | framecount = 0; | ||
2642 | //if (m_worldOffset != Vector3.Zero) | ||
2643 | // return 0; | ||
2644 | |||
2645 | framecount++; | ||
2646 | |||
2647 | DateTime now = DateTime.UtcNow; | ||
2648 | TimeSpan SinceLastFrame = now - m_lastframe; | ||
2649 | m_lastframe = now; | ||
2650 | float realtime = (float)SinceLastFrame.TotalSeconds; | ||
2651 | // Console.WriteLine("ts={0} rt={1}", timeStep, realtime); | ||
2652 | timeStep = realtime; | ||
2653 | |||
2654 | // float fps = 1.0f / realtime; | ||
2655 | float fps = 0.0f; // number of ODE steps in this Simulate step | ||
2656 | //m_log.Info(timeStep.ToString()); | ||
2657 | step_time += timeStep; | ||
2658 | |||
2659 | // If We're loaded down by something else, | ||
2660 | // or debugging with the Visual Studio project on pause | ||
2661 | // skip a few frames to catch up gracefully. | ||
2662 | // without shooting the physicsactors all over the place | ||
2663 | |||
2664 | if (step_time >= m_SkipFramesAtms) | ||
2665 | { | ||
2666 | // Instead of trying to catch up, it'll do 5 physics frames only | ||
2667 | step_time = ODE_STEPSIZE; | ||
2668 | m_physicsiterations = 5; | ||
2669 | } | ||
2670 | else | ||
2671 | { | ||
2672 | m_physicsiterations = 10; | ||
2673 | } | ||
2674 | |||
2675 | if (SupportsNINJAJoints) | ||
2676 | { | ||
2677 | DeleteRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks | ||
2678 | CreateRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks | ||
2679 | } | ||
2680 | |||
2681 | lock (OdeLock) | ||
2682 | { | ||
2683 | // Process 10 frames if the sim is running normal.. | ||
2684 | // process 5 frames if the sim is running slow | ||
2685 | //try | ||
2686 | //{ | ||
2687 | //d.WorldSetQuickStepNumIterations(world, m_physicsiterations); | ||
2688 | //} | ||
2689 | //catch (StackOverflowException) | ||
2690 | //{ | ||
2691 | // m_log.Error("[PHYSICS]: The operating system wasn't able to allocate enough memory for the simulation. Restarting the sim."); | ||
2692 | // ode.drelease(world); | ||
2693 | //base.TriggerPhysicsBasedRestart(); | ||
2694 | //} | ||
2695 | |||
2696 | int i = 0; | ||
2697 | |||
2698 | // Figure out the Frames Per Second we're going at. | ||
2699 | //(step_time == 0.004f, there's 250 of those per second. Times the step time/step size | ||
2700 | |||
2701 | // fps = (step_time / ODE_STEPSIZE) * 1000; | ||
2702 | // HACK: Using a time dilation of 1.0 to debug rubberbanding issues | ||
2703 | //m_timeDilation = Math.Min((step_time / ODE_STEPSIZE) / (0.09375f / ODE_STEPSIZE), 1.0f); | ||
2704 | |||
2705 | // step_time = 0.09375f; | ||
2706 | |||
2707 | while (step_time > 0.0f) | ||
2708 | { | ||
2709 | //lock (ode) | ||
2710 | //{ | ||
2711 | //if (!ode.lockquery()) | ||
2712 | //{ | ||
2713 | // ode.dlock(world); | ||
2714 | try | ||
2715 | { | ||
2716 | // Insert, remove Characters | ||
2717 | bool processedtaints = false; | ||
2718 | |||
2719 | lock (_taintedActors) | ||
2720 | { | ||
2721 | if (_taintedActors.Count > 0) | ||
2722 | { | ||
2723 | foreach (OdeCharacter character in _taintedActors) | ||
2724 | { | ||
2725 | |||
2726 | character.ProcessTaints(ODE_STEPSIZE); | ||
2727 | |||
2728 | processedtaints = true; | ||
2729 | //character.m_collisionscore = 0; | ||
2730 | } | ||
2731 | |||
2732 | if (processedtaints) | ||
2733 | _taintedActors.Clear(); | ||
2734 | } | ||
2735 | } // end lock _taintedActors | ||
2736 | |||
2737 | // Modify other objects in the scene. | ||
2738 | processedtaints = false; | ||
2739 | |||
2740 | lock (_taintedPrimLock) | ||
2741 | { | ||
2742 | foreach (OdePrim prim in _taintedPrimL) | ||
2743 | { | ||
2744 | if (prim.m_taintremove) | ||
2745 | { | ||
2746 | //Console.WriteLine("Simulate calls RemovePrimThreadLocked"); | ||
2747 | RemovePrimThreadLocked(prim); | ||
2748 | } | ||
2749 | else | ||
2750 | { | ||
2751 | //Console.WriteLine("Simulate calls ProcessTaints"); | ||
2752 | prim.ProcessTaints(ODE_STEPSIZE); | ||
2753 | } | ||
2754 | processedtaints = true; | ||
2755 | prim.m_collisionscore = 0; | ||
2756 | |||
2757 | // This loop can block up the Heartbeat for a very long time on large regions. | ||
2758 | // We need to let the Watchdog know that the Heartbeat is not dead | ||
2759 | // NOTE: This is currently commented out, but if things like OAR loading are | ||
2760 | // timing the heartbeat out we will need to uncomment it | ||
2761 | //Watchdog.UpdateThread(); | ||
2762 | } | ||
2763 | |||
2764 | if (SupportsNINJAJoints) | ||
2765 | { | ||
2766 | // Create pending joints, if possible | ||
2767 | |||
2768 | // joints can only be processed after ALL bodies are processed (and exist in ODE), since creating | ||
2769 | // a joint requires specifying the body id of both involved bodies | ||
2770 | if (pendingJoints.Count > 0) | ||
2771 | { | ||
2772 | List<PhysicsJoint> successfullyProcessedPendingJoints = new List<PhysicsJoint>(); | ||
2773 | //DoJointErrorMessage(joints_connecting_actor, "taint: " + pendingJoints.Count + " pending joints"); | ||
2774 | foreach (PhysicsJoint joint in pendingJoints) | ||
2775 | { | ||
2776 | //DoJointErrorMessage(joint, "taint: time to create joint with parms: " + joint.RawParams); | ||
2777 | string[] jointParams = joint.RawParams.Split(" ".ToCharArray(), | ||
2778 | System.StringSplitOptions.RemoveEmptyEntries); | ||
2779 | List<IntPtr> jointBodies = new List<IntPtr>(); | ||
2780 | bool allJointBodiesAreReady = true; | ||
2781 | foreach (string jointParam in jointParams) | ||
2782 | { | ||
2783 | if (jointParam == "NULL") | ||
2784 | { | ||
2785 | //DoJointErrorMessage(joint, "attaching NULL joint to world"); | ||
2786 | jointBodies.Add(IntPtr.Zero); | ||
2787 | } | ||
2788 | else | ||
2789 | { | ||
2790 | //DoJointErrorMessage(joint, "looking for prim name: " + jointParam); | ||
2791 | bool foundPrim = false; | ||
2792 | lock (_prims) | ||
2793 | { | ||
2794 | foreach (OdePrim prim in _prims) // FIXME: inefficient | ||
2795 | { | ||
2796 | if (prim.SOPName == jointParam) | ||
2797 | { | ||
2798 | //DoJointErrorMessage(joint, "found for prim name: " + jointParam); | ||
2799 | if (prim.IsPhysical && prim.Body != IntPtr.Zero) | ||
2800 | { | ||
2801 | jointBodies.Add(prim.Body); | ||
2802 | foundPrim = true; | ||
2803 | break; | ||
2804 | } | ||
2805 | else | ||
2806 | { | ||
2807 | DoJointErrorMessage(joint, "prim name " + jointParam + | ||
2808 | " exists but is not (yet) physical; deferring joint creation. " + | ||
2809 | "IsPhysical property is " + prim.IsPhysical + | ||
2810 | " and body is " + prim.Body); | ||
2811 | foundPrim = false; | ||
2812 | break; | ||
2813 | } | ||
2814 | } | ||
2815 | } | ||
2816 | } | ||
2817 | if (foundPrim) | ||
2818 | { | ||
2819 | // all is fine | ||
2820 | } | ||
2821 | else | ||
2822 | { | ||
2823 | allJointBodiesAreReady = false; | ||
2824 | break; | ||
2825 | } | ||
2826 | } | ||
2827 | } | ||
2828 | if (allJointBodiesAreReady) | ||
2829 | { | ||
2830 | //DoJointErrorMessage(joint, "allJointBodiesAreReady for " + joint.ObjectNameInScene + " with parms " + joint.RawParams); | ||
2831 | if (jointBodies[0] == jointBodies[1]) | ||
2832 | { | ||
2833 | DoJointErrorMessage(joint, "ERROR: joint cannot be created; the joint bodies are the same, body1==body2. Raw body is " + jointBodies[0] + ". raw parms: " + joint.RawParams); | ||
2834 | } | ||
2835 | else | ||
2836 | { | ||
2837 | switch (joint.Type) | ||
2838 | { | ||
2839 | case PhysicsJointType.Ball: | ||
2840 | { | ||
2841 | IntPtr odeJoint; | ||
2842 | //DoJointErrorMessage(joint, "ODE creating ball joint "); | ||
2843 | odeJoint = d.JointCreateBall(world, IntPtr.Zero); | ||
2844 | //DoJointErrorMessage(joint, "ODE attaching ball joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]); | ||
2845 | d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]); | ||
2846 | //DoJointErrorMessage(joint, "ODE setting ball anchor: " + odeJoint + " to vec:" + joint.Position); | ||
2847 | d.JointSetBallAnchor(odeJoint, | ||
2848 | joint.Position.X, | ||
2849 | joint.Position.Y, | ||
2850 | joint.Position.Z); | ||
2851 | //DoJointErrorMessage(joint, "ODE joint setting OK"); | ||
2852 | //DoJointErrorMessage(joint, "The ball joint's bodies are here: b0: "); | ||
2853 | //DoJointErrorMessage(joint, "" + (jointBodies[0] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[0]) : "fixed environment")); | ||
2854 | //DoJointErrorMessage(joint, "The ball joint's bodies are here: b1: "); | ||
2855 | //DoJointErrorMessage(joint, "" + (jointBodies[1] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[1]) : "fixed environment")); | ||
2856 | |||
2857 | if (joint is OdePhysicsJoint) | ||
2858 | { | ||
2859 | ((OdePhysicsJoint)joint).jointID = odeJoint; | ||
2860 | } | ||
2861 | else | ||
2862 | { | ||
2863 | DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!"); | ||
2864 | } | ||
2865 | } | ||
2866 | break; | ||
2867 | case PhysicsJointType.Hinge: | ||
2868 | { | ||
2869 | IntPtr odeJoint; | ||
2870 | //DoJointErrorMessage(joint, "ODE creating hinge joint "); | ||
2871 | odeJoint = d.JointCreateHinge(world, IntPtr.Zero); | ||
2872 | //DoJointErrorMessage(joint, "ODE attaching hinge joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]); | ||
2873 | d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]); | ||
2874 | //DoJointErrorMessage(joint, "ODE setting hinge anchor: " + odeJoint + " to vec:" + joint.Position); | ||
2875 | d.JointSetHingeAnchor(odeJoint, | ||
2876 | joint.Position.X, | ||
2877 | joint.Position.Y, | ||
2878 | joint.Position.Z); | ||
2879 | // We use the orientation of the x-axis of the joint's coordinate frame | ||
2880 | // as the axis for the hinge. | ||
2881 | |||
2882 | // Therefore, we must get the joint's coordinate frame based on the | ||
2883 | // joint.Rotation field, which originates from the orientation of the | ||
2884 | // joint's proxy object in the scene. | ||
2885 | |||
2886 | // The joint's coordinate frame is defined as the transformation matrix | ||
2887 | // that converts a vector from joint-local coordinates into world coordinates. | ||
2888 | // World coordinates are defined as the XYZ coordinate system of the sim, | ||
2889 | // as shown in the top status-bar of the viewer. | ||
2890 | |||
2891 | // Once we have the joint's coordinate frame, we extract its X axis (AtAxis) | ||
2892 | // and use that as the hinge axis. | ||
2893 | |||
2894 | //joint.Rotation.Normalize(); | ||
2895 | Matrix4 proxyFrame = Matrix4.CreateFromQuaternion(joint.Rotation); | ||
2896 | |||
2897 | // Now extract the X axis of the joint's coordinate frame. | ||
2898 | |||
2899 | // Do not try to use proxyFrame.AtAxis or you will become mired in the | ||
2900 | // tar pit of transposed, inverted, and generally messed-up orientations. | ||
2901 | // (In other words, Matrix4.AtAxis() is borked.) | ||
2902 | // Vector3 jointAxis = proxyFrame.AtAxis; <--- this path leadeth to madness | ||
2903 | |||
2904 | // Instead, compute the X axis of the coordinate frame by transforming | ||
2905 | // the (1,0,0) vector. At least that works. | ||
2906 | |||
2907 | //m_log.Debug("PHY: making axis: complete matrix is " + proxyFrame); | ||
2908 | Vector3 jointAxis = Vector3.Transform(Vector3.UnitX, proxyFrame); | ||
2909 | //m_log.Debug("PHY: making axis: hinge joint axis is " + jointAxis); | ||
2910 | //DoJointErrorMessage(joint, "ODE setting hinge axis: " + odeJoint + " to vec:" + jointAxis); | ||
2911 | d.JointSetHingeAxis(odeJoint, | ||
2912 | jointAxis.X, | ||
2913 | jointAxis.Y, | ||
2914 | jointAxis.Z); | ||
2915 | //d.JointSetHingeParam(odeJoint, (int)dParam.CFM, 0.1f); | ||
2916 | if (joint is OdePhysicsJoint) | ||
2917 | { | ||
2918 | ((OdePhysicsJoint)joint).jointID = odeJoint; | ||
2919 | } | ||
2920 | else | ||
2921 | { | ||
2922 | DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!"); | ||
2923 | } | ||
2924 | } | ||
2925 | break; | ||
2926 | } | ||
2927 | successfullyProcessedPendingJoints.Add(joint); | ||
2928 | } | ||
2929 | } | ||
2930 | else | ||
2931 | { | ||
2932 | DoJointErrorMessage(joint, "joint could not yet be created; still pending"); | ||
2933 | } | ||
2934 | } | ||
2935 | foreach (PhysicsJoint successfullyProcessedJoint in successfullyProcessedPendingJoints) | ||
2936 | { | ||
2937 | //DoJointErrorMessage(successfullyProcessedJoint, "finalizing succesfully procsssed joint " + successfullyProcessedJoint.ObjectNameInScene + " parms " + successfullyProcessedJoint.RawParams); | ||
2938 | //DoJointErrorMessage(successfullyProcessedJoint, "removing from pending"); | ||
2939 | InternalRemovePendingJoint(successfullyProcessedJoint); | ||
2940 | //DoJointErrorMessage(successfullyProcessedJoint, "adding to active"); | ||
2941 | InternalAddActiveJoint(successfullyProcessedJoint); | ||
2942 | //DoJointErrorMessage(successfullyProcessedJoint, "done"); | ||
2943 | } | ||
2944 | } | ||
2945 | } // end SupportsNINJAJoints | ||
2946 | |||
2947 | if (processedtaints) | ||
2948 | //Console.WriteLine("Simulate calls Clear of _taintedPrim list"); | ||
2949 | _taintedPrimH.Clear(); // ??? if this only ??? | ||
2950 | _taintedPrimL.Clear(); | ||
2951 | } // end lock _taintedPrimLock | ||
2952 | |||
2953 | // Move characters | ||
2954 | lock (_characters) | ||
2955 | { | ||
2956 | List<OdeCharacter> defects = new List<OdeCharacter>(); | ||
2957 | foreach (OdeCharacter actor in _characters) | ||
2958 | { | ||
2959 | if (actor != null) | ||
2960 | actor.Move(ODE_STEPSIZE, defects); | ||
2961 | } | ||
2962 | if (0 != defects.Count) | ||
2963 | { | ||
2964 | foreach (OdeCharacter defect in defects) | ||
2965 | { | ||
2966 | RemoveCharacter(defect); | ||
2967 | } | ||
2968 | } | ||
2969 | } // end lock _characters | ||
2970 | |||
2971 | // Move other active objects | ||
2972 | lock (_activeprims) | ||
2973 | { | ||
2974 | foreach (OdePrim prim in _activeprims) | ||
2975 | { | ||
2976 | prim.m_collisionscore = 0; | ||
2977 | prim.Move(ODE_STEPSIZE); | ||
2978 | } | ||
2979 | } // end lock _activeprims | ||
2980 | |||
2981 | //if ((framecount % m_randomizeWater) == 0) | ||
2982 | // randomizeWater(waterlevel); | ||
2983 | |||
2984 | //int RayCastTimeMS = m_rayCastManager.ProcessQueuedRequests(); | ||
2985 | m_rayCastManager.ProcessQueuedRequests(); | ||
2986 | |||
2987 | collision_optimized(ODE_STEPSIZE); | ||
2988 | |||
2989 | lock (_collisionEventPrim) | ||
2990 | { | ||
2991 | foreach (PhysicsActor obj in _collisionEventPrim) | ||
2992 | { | ||
2993 | if (obj == null) | ||
2994 | continue; | ||
2995 | |||
2996 | switch ((ActorTypes)obj.PhysicsActorType) | ||
2997 | { | ||
2998 | case ActorTypes.Agent: | ||
2999 | OdeCharacter cobj = (OdeCharacter)obj; | ||
3000 | cobj.AddCollisionFrameTime(100); | ||
3001 | cobj.SendCollisions(); | ||
3002 | break; | ||
3003 | case ActorTypes.Prim: | ||
3004 | OdePrim pobj = (OdePrim)obj; | ||
3005 | pobj.SendCollisions(); | ||
3006 | break; | ||
3007 | } | ||
3008 | } | ||
3009 | } // end lock _collisionEventPrim | ||
3010 | |||
3011 | //if (m_global_contactcount > 5) | ||
3012 | //{ | ||
3013 | // m_log.DebugFormat("[PHYSICS]: Contacts:{0}", m_global_contactcount); | ||
3014 | //} | ||
3015 | |||
3016 | m_global_contactcount = 0; | ||
3017 | |||
3018 | d.WorldQuickStep(world, ODE_STEPSIZE); | ||
3019 | d.JointGroupEmpty(contactgroup); | ||
3020 | fps++; | ||
3021 | //ode.dunlock(world); | ||
3022 | } // end try | ||
3023 | catch (Exception e) | ||
3024 | { | ||
3025 | m_log.ErrorFormat("[PHYSICS]: {0}, {1}, {2}", e.Message, e.TargetSite, e); | ||
3026 | ode.dunlock(world); | ||
3027 | } | ||
3028 | |||
3029 | step_time -= ODE_STEPSIZE; | ||
3030 | i++; | ||
3031 | //} | ||
3032 | //else | ||
3033 | //{ | ||
3034 | //fps = 0; | ||
3035 | //} | ||
3036 | //} | ||
3037 | } // end while (step_time > 0.0f) | ||
3038 | |||
3039 | lock (_characters) | ||
3040 | { | ||
3041 | foreach (OdeCharacter actor in _characters) | ||
3042 | { | ||
3043 | if (actor != null) | ||
3044 | { | ||
3045 | if (actor.bad) | ||
3046 | m_log.WarnFormat("[PHYSICS]: BAD Actor {0} in _characters list was not removed?", actor.m_uuid); | ||
3047 | actor.UpdatePositionAndVelocity(); | ||
3048 | } | ||
3049 | } | ||
3050 | } | ||
3051 | |||
3052 | lock (_badCharacter) | ||
3053 | { | ||
3054 | if (_badCharacter.Count > 0) | ||
3055 | { | ||
3056 | foreach (OdeCharacter chr in _badCharacter) | ||
3057 | { | ||
3058 | RemoveCharacter(chr); | ||
3059 | } | ||
3060 | _badCharacter.Clear(); | ||
3061 | } | ||
3062 | } | ||
3063 | |||
3064 | lock (_activeprims) | ||
3065 | { | ||
3066 | //if (timeStep < 0.2f) | ||
3067 | { | ||
3068 | foreach (OdePrim actor in _activeprims) | ||
3069 | { | ||
3070 | if (actor.IsPhysical && (d.BodyIsEnabled(actor.Body) || !actor._zeroFlag)) | ||
3071 | { | ||
3072 | actor.UpdatePositionAndVelocity(); | ||
3073 | |||
3074 | if (SupportsNINJAJoints) | ||
3075 | { | ||
3076 | // If an actor moved, move its joint proxy objects as well. | ||
3077 | // There seems to be an event PhysicsActor.OnPositionUpdate that could be used | ||
3078 | // for this purpose but it is never called! So we just do the joint | ||
3079 | // movement code here. | ||
3080 | |||
3081 | if (actor.SOPName != null && | ||
3082 | joints_connecting_actor.ContainsKey(actor.SOPName) && | ||
3083 | joints_connecting_actor[actor.SOPName] != null && | ||
3084 | joints_connecting_actor[actor.SOPName].Count > 0) | ||
3085 | { | ||
3086 | foreach (PhysicsJoint affectedJoint in joints_connecting_actor[actor.SOPName]) | ||
3087 | { | ||
3088 | if (affectedJoint.IsInPhysicsEngine) | ||
3089 | { | ||
3090 | DoJointMoved(affectedJoint); | ||
3091 | } | ||
3092 | else | ||
3093 | { | ||
3094 | DoJointErrorMessage(affectedJoint, "a body connected to a joint was moved, but the joint doesn't exist yet! this will lead to joint error. joint was: " + affectedJoint.ObjectNameInScene + " parms:" + affectedJoint.RawParams); | ||
3095 | } | ||
3096 | } | ||
3097 | } | ||
3098 | } | ||
3099 | } | ||
3100 | } | ||
3101 | } | ||
3102 | } // end lock _activeprims | ||
3103 | |||
3104 | //DumpJointInfo(); | ||
3105 | |||
3106 | // Finished with all sim stepping. If requested, dump world state to file for debugging. | ||
3107 | // TODO: This call to the export function is already inside lock (OdeLock) - but is an extra lock needed? | ||
3108 | // TODO: This overwrites all dump files in-place. Should this be a growing logfile, or separate snapshots? | ||
3109 | if (physics_logging && (physics_logging_interval>0) && (framecount % physics_logging_interval == 0)) | ||
3110 | { | ||
3111 | string fname = "state-" + world.ToString() + ".DIF"; // give each physics world a separate filename | ||
3112 | string prefix = "world" + world.ToString(); // prefix for variable names in exported .DIF file | ||
3113 | |||
3114 | if (physics_logging_append_existing_logfile) | ||
3115 | { | ||
3116 | string header = "-------------- START OF PHYSICS FRAME " + framecount.ToString() + " --------------"; | ||
3117 | TextWriter fwriter = File.AppendText(fname); | ||
3118 | fwriter.WriteLine(header); | ||
3119 | fwriter.Close(); | ||
3120 | } | ||
3121 | d.WorldExportDIF(world, fname, physics_logging_append_existing_logfile, prefix); | ||
3122 | } | ||
3123 | } // end lock OdeLock | ||
3124 | |||
3125 | return fps * 1000.0f; //NB This is a FRAME COUNT, not a time! AND is divide by 1000 in SimStatusReporter! | ||
3126 | } // end Simulate | ||
3127 | |||
3128 | public override void GetResults() | ||
3129 | { | ||
3130 | } | ||
3131 | |||
3132 | public override bool IsThreaded | ||
3133 | { | ||
3134 | // for now we won't be multithreaded | ||
3135 | get { return (false); } | ||
3136 | } | ||
3137 | |||
3138 | #region ODE Specific Terrain Fixes | ||
3139 | public float[] ResizeTerrain512NearestNeighbour(float[] heightMap) | ||
3140 | { | ||
3141 | float[] returnarr = new float[262144]; | ||
3142 | float[,] resultarr = new float[(int)WorldExtents.X, (int)WorldExtents.Y]; | ||
3143 | |||
3144 | // Filling out the array into its multi-dimensional components | ||
3145 | for (int y = 0; y < WorldExtents.Y; y++) | ||
3146 | { | ||
3147 | for (int x = 0; x < WorldExtents.X; x++) | ||
3148 | { | ||
3149 | resultarr[y, x] = heightMap[y * (int)WorldExtents.Y + x]; | ||
3150 | } | ||
3151 | } | ||
3152 | |||
3153 | // Resize using Nearest Neighbour | ||
3154 | |||
3155 | // This particular way is quick but it only works on a multiple of the original | ||
3156 | |||
3157 | // The idea behind this method can be described with the following diagrams | ||
3158 | // second pass and third pass happen in the same loop really.. just separated | ||
3159 | // them to show what this does. | ||
3160 | |||
3161 | // First Pass | ||
3162 | // ResultArr: | ||
3163 | // 1,1,1,1,1,1 | ||
3164 | // 1,1,1,1,1,1 | ||
3165 | // 1,1,1,1,1,1 | ||
3166 | // 1,1,1,1,1,1 | ||
3167 | // 1,1,1,1,1,1 | ||
3168 | // 1,1,1,1,1,1 | ||
3169 | |||
3170 | // Second Pass | ||
3171 | // ResultArr2: | ||
3172 | // 1,,1,,1,,1,,1,,1, | ||
3173 | // ,,,,,,,,,, | ||
3174 | // 1,,1,,1,,1,,1,,1, | ||
3175 | // ,,,,,,,,,, | ||
3176 | // 1,,1,,1,,1,,1,,1, | ||
3177 | // ,,,,,,,,,, | ||
3178 | // 1,,1,,1,,1,,1,,1, | ||
3179 | // ,,,,,,,,,, | ||
3180 | // 1,,1,,1,,1,,1,,1, | ||
3181 | // ,,,,,,,,,, | ||
3182 | // 1,,1,,1,,1,,1,,1, | ||
3183 | |||
3184 | // Third pass fills in the blanks | ||
3185 | // ResultArr2: | ||
3186 | // 1,1,1,1,1,1,1,1,1,1,1,1 | ||
3187 | // 1,1,1,1,1,1,1,1,1,1,1,1 | ||
3188 | // 1,1,1,1,1,1,1,1,1,1,1,1 | ||
3189 | // 1,1,1,1,1,1,1,1,1,1,1,1 | ||
3190 | // 1,1,1,1,1,1,1,1,1,1,1,1 | ||
3191 | // 1,1,1,1,1,1,1,1,1,1,1,1 | ||
3192 | // 1,1,1,1,1,1,1,1,1,1,1,1 | ||
3193 | // 1,1,1,1,1,1,1,1,1,1,1,1 | ||
3194 | // 1,1,1,1,1,1,1,1,1,1,1,1 | ||
3195 | // 1,1,1,1,1,1,1,1,1,1,1,1 | ||
3196 | // 1,1,1,1,1,1,1,1,1,1,1,1 | ||
3197 | |||
3198 | // X,Y = . | ||
3199 | // X+1,y = ^ | ||
3200 | // X,Y+1 = * | ||
3201 | // X+1,Y+1 = # | ||
3202 | |||
3203 | // Filling in like this; | ||
3204 | // .* | ||
3205 | // ^# | ||
3206 | // 1st . | ||
3207 | // 2nd * | ||
3208 | // 3rd ^ | ||
3209 | // 4th # | ||
3210 | // on single loop. | ||
3211 | |||
3212 | float[,] resultarr2 = new float[512, 512]; | ||
3213 | for (int y = 0; y < WorldExtents.Y; y++) | ||
3214 | { | ||
3215 | for (int x = 0; x < WorldExtents.X; x++) | ||
3216 | { | ||
3217 | resultarr2[y * 2, x * 2] = resultarr[y, x]; | ||
3218 | |||
3219 | if (y < WorldExtents.Y) | ||
3220 | { | ||
3221 | resultarr2[(y * 2) + 1, x * 2] = resultarr[y, x]; | ||
3222 | } | ||
3223 | if (x < WorldExtents.X) | ||
3224 | { | ||
3225 | resultarr2[y * 2, (x * 2) + 1] = resultarr[y, x]; | ||
3226 | } | ||
3227 | if (x < WorldExtents.X && y < WorldExtents.Y) | ||
3228 | { | ||
3229 | resultarr2[(y * 2) + 1, (x * 2) + 1] = resultarr[y, x]; | ||
3230 | } | ||
3231 | } | ||
3232 | } | ||
3233 | |||
3234 | //Flatten out the array | ||
3235 | int i = 0; | ||
3236 | for (int y = 0; y < 512; y++) | ||
3237 | { | ||
3238 | for (int x = 0; x < 512; x++) | ||
3239 | { | ||
3240 | if (resultarr2[y, x] <= 0) | ||
3241 | returnarr[i] = 0.0000001f; | ||
3242 | else | ||
3243 | returnarr[i] = resultarr2[y, x]; | ||
3244 | |||
3245 | i++; | ||
3246 | } | ||
3247 | } | ||
3248 | |||
3249 | return returnarr; | ||
3250 | } | ||
3251 | |||
3252 | public float[] ResizeTerrain512Interpolation(float[] heightMap) | ||
3253 | { | ||
3254 | float[] returnarr = new float[262144]; | ||
3255 | float[,] resultarr = new float[512,512]; | ||
3256 | |||
3257 | // Filling out the array into its multi-dimensional components | ||
3258 | for (int y = 0; y < 256; y++) | ||
3259 | { | ||
3260 | for (int x = 0; x < 256; x++) | ||
3261 | { | ||
3262 | resultarr[y, x] = heightMap[y * 256 + x]; | ||
3263 | } | ||
3264 | } | ||
3265 | |||
3266 | // Resize using interpolation | ||
3267 | |||
3268 | // This particular way is quick but it only works on a multiple of the original | ||
3269 | |||
3270 | // The idea behind this method can be described with the following diagrams | ||
3271 | // second pass and third pass happen in the same loop really.. just separated | ||
3272 | // them to show what this does. | ||
3273 | |||
3274 | // First Pass | ||
3275 | // ResultArr: | ||
3276 | // 1,1,1,1,1,1 | ||
3277 | // 1,1,1,1,1,1 | ||
3278 | // 1,1,1,1,1,1 | ||
3279 | // 1,1,1,1,1,1 | ||
3280 | // 1,1,1,1,1,1 | ||
3281 | // 1,1,1,1,1,1 | ||
3282 | |||
3283 | // Second Pass | ||
3284 | // ResultArr2: | ||
3285 | // 1,,1,,1,,1,,1,,1, | ||
3286 | // ,,,,,,,,,, | ||
3287 | // 1,,1,,1,,1,,1,,1, | ||
3288 | // ,,,,,,,,,, | ||
3289 | // 1,,1,,1,,1,,1,,1, | ||
3290 | // ,,,,,,,,,, | ||
3291 | // 1,,1,,1,,1,,1,,1, | ||
3292 | // ,,,,,,,,,, | ||
3293 | // 1,,1,,1,,1,,1,,1, | ||
3294 | // ,,,,,,,,,, | ||
3295 | // 1,,1,,1,,1,,1,,1, | ||
3296 | |||
3297 | // Third pass fills in the blanks | ||
3298 | // ResultArr2: | ||
3299 | // 1,1,1,1,1,1,1,1,1,1,1,1 | ||
3300 | // 1,1,1,1,1,1,1,1,1,1,1,1 | ||
3301 | // 1,1,1,1,1,1,1,1,1,1,1,1 | ||
3302 | // 1,1,1,1,1,1,1,1,1,1,1,1 | ||
3303 | // 1,1,1,1,1,1,1,1,1,1,1,1 | ||
3304 | // 1,1,1,1,1,1,1,1,1,1,1,1 | ||
3305 | // 1,1,1,1,1,1,1,1,1,1,1,1 | ||
3306 | // 1,1,1,1,1,1,1,1,1,1,1,1 | ||
3307 | // 1,1,1,1,1,1,1,1,1,1,1,1 | ||
3308 | // 1,1,1,1,1,1,1,1,1,1,1,1 | ||
3309 | // 1,1,1,1,1,1,1,1,1,1,1,1 | ||
3310 | |||
3311 | // X,Y = . | ||
3312 | // X+1,y = ^ | ||
3313 | // X,Y+1 = * | ||
3314 | // X+1,Y+1 = # | ||
3315 | |||
3316 | // Filling in like this; | ||
3317 | // .* | ||
3318 | // ^# | ||
3319 | // 1st . | ||
3320 | // 2nd * | ||
3321 | // 3rd ^ | ||
3322 | // 4th # | ||
3323 | // on single loop. | ||
3324 | |||
3325 | float[,] resultarr2 = new float[512,512]; | ||
3326 | for (int y = 0; y < (int)Constants.RegionSize; y++) | ||
3327 | { | ||
3328 | for (int x = 0; x < (int)Constants.RegionSize; x++) | ||
3329 | { | ||
3330 | resultarr2[y*2, x*2] = resultarr[y, x]; | ||
3331 | |||
3332 | if (y < (int)Constants.RegionSize) | ||
3333 | { | ||
3334 | if (y + 1 < (int)Constants.RegionSize) | ||
3335 | { | ||
3336 | if (x + 1 < (int)Constants.RegionSize) | ||
3337 | { | ||
3338 | resultarr2[(y*2) + 1, x*2] = ((resultarr[y, x] + resultarr[y + 1, x] + | ||
3339 | resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4); | ||
3340 | } | ||
3341 | else | ||
3342 | { | ||
3343 | resultarr2[(y*2) + 1, x*2] = ((resultarr[y, x] + resultarr[y + 1, x])/2); | ||
3344 | } | ||
3345 | } | ||
3346 | else | ||
3347 | { | ||
3348 | resultarr2[(y*2) + 1, x*2] = resultarr[y, x]; | ||
3349 | } | ||
3350 | } | ||
3351 | if (x < (int)Constants.RegionSize) | ||
3352 | { | ||
3353 | if (x + 1 < (int)Constants.RegionSize) | ||
3354 | { | ||
3355 | if (y + 1 < (int)Constants.RegionSize) | ||
3356 | { | ||
3357 | resultarr2[y*2, (x*2) + 1] = ((resultarr[y, x] + resultarr[y + 1, x] + | ||
3358 | resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4); | ||
3359 | } | ||
3360 | else | ||
3361 | { | ||
3362 | resultarr2[y*2, (x*2) + 1] = ((resultarr[y, x] + resultarr[y, x + 1])/2); | ||
3363 | } | ||
3364 | } | ||
3365 | else | ||
3366 | { | ||
3367 | resultarr2[y*2, (x*2) + 1] = resultarr[y, x]; | ||
3368 | } | ||
3369 | } | ||
3370 | if (x < (int)Constants.RegionSize && y < (int)Constants.RegionSize) | ||
3371 | { | ||
3372 | if ((x + 1 < (int)Constants.RegionSize) && (y + 1 < (int)Constants.RegionSize)) | ||
3373 | { | ||
3374 | resultarr2[(y*2) + 1, (x*2) + 1] = ((resultarr[y, x] + resultarr[y + 1, x] + | ||
3375 | resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4); | ||
3376 | } | ||
3377 | else | ||
3378 | { | ||
3379 | resultarr2[(y*2) + 1, (x*2) + 1] = resultarr[y, x]; | ||
3380 | } | ||
3381 | } | ||
3382 | } | ||
3383 | } | ||
3384 | //Flatten out the array | ||
3385 | int i = 0; | ||
3386 | for (int y = 0; y < 512; y++) | ||
3387 | { | ||
3388 | for (int x = 0; x < 512; x++) | ||
3389 | { | ||
3390 | if (Single.IsNaN(resultarr2[y, x]) || Single.IsInfinity(resultarr2[y, x])) | ||
3391 | { | ||
3392 | m_log.Warn("[PHYSICS]: Non finite heightfield element detected. Setting it to 0"); | ||
3393 | resultarr2[y, x] = 0; | ||
3394 | } | ||
3395 | returnarr[i] = resultarr2[y, x]; | ||
3396 | i++; | ||
3397 | } | ||
3398 | } | ||
3399 | |||
3400 | return returnarr; | ||
3401 | } | ||
3402 | |||
3403 | #endregion | ||
3404 | |||
3405 | public override void SetTerrain(float[] heightMap) | ||
3406 | { | ||
3407 | if (m_worldOffset != Vector3.Zero && m_parentScene != null) | ||
3408 | { | ||
3409 | if (m_parentScene is OdeScene) | ||
3410 | { | ||
3411 | ((OdeScene)m_parentScene).SetTerrain(heightMap, m_worldOffset); | ||
3412 | } | ||
3413 | } | ||
3414 | else | ||
3415 | { | ||
3416 | SetTerrain(heightMap, m_worldOffset); | ||
3417 | } | ||
3418 | } | ||
3419 | |||
3420 | public void SetTerrain(float[] heightMap, Vector3 pOffset) | ||
3421 | { | ||
3422 | // this._heightmap[i] = (double)heightMap[i]; | ||
3423 | // dbm (danx0r) -- creating a buffer zone of one extra sample all around | ||
3424 | //_origheightmap = heightMap; | ||
3425 | |||
3426 | float[] _heightmap; | ||
3427 | |||
3428 | // zero out a heightmap array float array (single dimension [flattened])) | ||
3429 | //if ((int)Constants.RegionSize == 256) | ||
3430 | // _heightmap = new float[514 * 514]; | ||
3431 | //else | ||
3432 | |||
3433 | _heightmap = new float[(((int)Constants.RegionSize + 2) * ((int)Constants.RegionSize + 2))]; | ||
3434 | |||
3435 | uint heightmapWidth = Constants.RegionSize + 1; | ||
3436 | uint heightmapHeight = Constants.RegionSize + 1; | ||
3437 | |||
3438 | uint heightmapWidthSamples; | ||
3439 | |||
3440 | uint heightmapHeightSamples; | ||
3441 | |||
3442 | //if (((int)Constants.RegionSize) == 256) | ||
3443 | //{ | ||
3444 | // heightmapWidthSamples = 2 * (uint)Constants.RegionSize + 2; | ||
3445 | // heightmapHeightSamples = 2 * (uint)Constants.RegionSize + 2; | ||
3446 | // heightmapWidth++; | ||
3447 | // heightmapHeight++; | ||
3448 | //} | ||
3449 | //else | ||
3450 | //{ | ||
3451 | |||
3452 | heightmapWidthSamples = (uint)Constants.RegionSize + 1; | ||
3453 | heightmapHeightSamples = (uint)Constants.RegionSize + 1; | ||
3454 | //} | ||
3455 | |||
3456 | const float scale = 1.0f; | ||
3457 | const float offset = 0.0f; | ||
3458 | const float thickness = 0.2f; | ||
3459 | const int wrap = 0; | ||
3460 | |||
3461 | int regionsize = (int) Constants.RegionSize + 2; | ||
3462 | //Double resolution | ||
3463 | //if (((int)Constants.RegionSize) == 256) | ||
3464 | // heightMap = ResizeTerrain512Interpolation(heightMap); | ||
3465 | |||
3466 | |||
3467 | // if (((int)Constants.RegionSize) == 256 && (int)Constants.RegionSize == 256) | ||
3468 | // regionsize = 512; | ||
3469 | |||
3470 | float hfmin = 2000; | ||
3471 | float hfmax = -2000; | ||
3472 | |||
3473 | for (int x = 0; x < heightmapWidthSamples; x++) | ||
3474 | { | ||
3475 | for (int y = 0; y < heightmapHeightSamples; y++) | ||
3476 | { | ||
3477 | int xx = Util.Clip(x - 1, 0, regionsize - 1); | ||
3478 | int yy = Util.Clip(y - 1, 0, regionsize - 1); | ||
3479 | |||
3480 | |||
3481 | float val= heightMap[yy * (int)Constants.RegionSize + xx]; | ||
3482 | _heightmap[x * ((int)Constants.RegionSize + 2) + y] = val; | ||
3483 | |||
3484 | hfmin = (val < hfmin) ? val : hfmin; | ||
3485 | hfmax = (val > hfmax) ? val : hfmax; | ||
3486 | } | ||
3487 | } | ||
3488 | |||
3489 | |||
3490 | |||
3491 | |||
3492 | lock (OdeLock) | ||
3493 | { | ||
3494 | IntPtr GroundGeom = IntPtr.Zero; | ||
3495 | if (RegionTerrain.TryGetValue(pOffset, out GroundGeom)) | ||
3496 | { | ||
3497 | RegionTerrain.Remove(pOffset); | ||
3498 | if (GroundGeom != IntPtr.Zero) | ||
3499 | { | ||
3500 | if (TerrainHeightFieldHeights.ContainsKey(GroundGeom)) | ||
3501 | { | ||
3502 | TerrainHeightFieldHeights.Remove(GroundGeom); | ||
3503 | } | ||
3504 | d.SpaceRemove(space, GroundGeom); | ||
3505 | d.GeomDestroy(GroundGeom); | ||
3506 | } | ||
3507 | |||
3508 | } | ||
3509 | IntPtr HeightmapData = d.GeomHeightfieldDataCreate(); | ||
3510 | d.GeomHeightfieldDataBuildSingle(HeightmapData, _heightmap, 0, heightmapWidth + 1, heightmapHeight + 1, | ||
3511 | (int)heightmapWidthSamples + 1, (int)heightmapHeightSamples + 1, scale, | ||
3512 | offset, thickness, wrap); | ||
3513 | d.GeomHeightfieldDataSetBounds(HeightmapData, hfmin - 1, hfmax + 1); | ||
3514 | GroundGeom = d.CreateHeightfield(space, HeightmapData, 1); | ||
3515 | if (GroundGeom != IntPtr.Zero) | ||
3516 | { | ||
3517 | d.GeomSetCategoryBits(GroundGeom, (int)(CollisionCategories.Land)); | ||
3518 | d.GeomSetCollideBits(GroundGeom, (int)(CollisionCategories.Space)); | ||
3519 | |||
3520 | } | ||
3521 | geom_name_map[GroundGeom] = "Terrain"; | ||
3522 | |||
3523 | d.Matrix3 R = new d.Matrix3(); | ||
3524 | |||
3525 | Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f); | ||
3526 | Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f); | ||
3527 | //Axiom.Math.Quaternion q3 = Axiom.Math.Quaternion.FromAngleAxis(3.14f, new Axiom.Math.Vector3(0, 0, 1)); | ||
3528 | |||
3529 | q1 = q1 * q2; | ||
3530 | //q1 = q1 * q3; | ||
3531 | Vector3 v3; | ||
3532 | float angle; | ||
3533 | q1.GetAxisAngle(out v3, out angle); | ||
3534 | |||
3535 | d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle); | ||
3536 | d.GeomSetRotation(GroundGeom, ref R); | ||
3537 | d.GeomSetPosition(GroundGeom, (pOffset.X + ((int)Constants.RegionSize * 0.5f)) - 1, (pOffset.Y + ((int)Constants.RegionSize * 0.5f)) - 1, 0); | ||
3538 | IntPtr testGround = IntPtr.Zero; | ||
3539 | if (RegionTerrain.TryGetValue(pOffset, out testGround)) | ||
3540 | { | ||
3541 | RegionTerrain.Remove(pOffset); | ||
3542 | } | ||
3543 | RegionTerrain.Add(pOffset, GroundGeom, GroundGeom); | ||
3544 | TerrainHeightFieldHeights.Add(GroundGeom,_heightmap); | ||
3545 | |||
3546 | } | ||
3547 | } | ||
3548 | |||
3549 | public override void DeleteTerrain() | ||
3550 | { | ||
3551 | } | ||
3552 | |||
3553 | public float GetWaterLevel() | ||
3554 | { | ||
3555 | return waterlevel; | ||
3556 | } | ||
3557 | |||
3558 | public override bool SupportsCombining() | ||
3559 | { | ||
3560 | return true; | ||
3561 | } | ||
3562 | |||
3563 | public override void UnCombine(PhysicsScene pScene) | ||
3564 | { | ||
3565 | IntPtr localGround = IntPtr.Zero; | ||
3566 | // float[] localHeightfield; | ||
3567 | bool proceed = false; | ||
3568 | List<IntPtr> geomDestroyList = new List<IntPtr>(); | ||
3569 | |||
3570 | lock (OdeLock) | ||
3571 | { | ||
3572 | if (RegionTerrain.TryGetValue(Vector3.Zero, out localGround)) | ||
3573 | { | ||
3574 | foreach (IntPtr geom in TerrainHeightFieldHeights.Keys) | ||
3575 | { | ||
3576 | if (geom == localGround) | ||
3577 | { | ||
3578 | // localHeightfield = TerrainHeightFieldHeights[geom]; | ||
3579 | proceed = true; | ||
3580 | } | ||
3581 | else | ||
3582 | { | ||
3583 | geomDestroyList.Add(geom); | ||
3584 | } | ||
3585 | } | ||
3586 | |||
3587 | if (proceed) | ||
3588 | { | ||
3589 | m_worldOffset = Vector3.Zero; | ||
3590 | WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize); | ||
3591 | m_parentScene = null; | ||
3592 | |||
3593 | foreach (IntPtr g in geomDestroyList) | ||
3594 | { | ||
3595 | // removingHeightField needs to be done or the garbage collector will | ||
3596 | // collect the terrain data before we tell ODE to destroy it causing | ||
3597 | // memory corruption | ||
3598 | if (TerrainHeightFieldHeights.ContainsKey(g)) | ||
3599 | { | ||
3600 | // float[] removingHeightField = TerrainHeightFieldHeights[g]; | ||
3601 | TerrainHeightFieldHeights.Remove(g); | ||
3602 | |||
3603 | if (RegionTerrain.ContainsKey(g)) | ||
3604 | { | ||
3605 | RegionTerrain.Remove(g); | ||
3606 | } | ||
3607 | |||
3608 | d.GeomDestroy(g); | ||
3609 | //removingHeightField = new float[0]; | ||
3610 | } | ||
3611 | } | ||
3612 | |||
3613 | } | ||
3614 | else | ||
3615 | { | ||
3616 | m_log.Warn("[PHYSICS]: Couldn't proceed with UnCombine. Region has inconsistant data."); | ||
3617 | |||
3618 | } | ||
3619 | } | ||
3620 | } | ||
3621 | } | ||
3622 | |||
3623 | public override void SetWaterLevel(float baseheight) | ||
3624 | { | ||
3625 | waterlevel = baseheight; | ||
3626 | randomizeWater(waterlevel); | ||
3627 | } | ||
3628 | |||
3629 | public void randomizeWater(float baseheight) | ||
3630 | { | ||
3631 | const uint heightmapWidth = m_regionWidth + 2; | ||
3632 | const uint heightmapHeight = m_regionHeight + 2; | ||
3633 | const uint heightmapWidthSamples = m_regionWidth + 2; | ||
3634 | const uint heightmapHeightSamples = m_regionHeight + 2; | ||
3635 | const float scale = 1.0f; | ||
3636 | const float offset = 0.0f; | ||
3637 | const float thickness = 2.9f; | ||
3638 | const int wrap = 0; | ||
3639 | |||
3640 | for (int i = 0; i < (258 * 258); i++) | ||
3641 | { | ||
3642 | _watermap[i] = (baseheight-0.1f) + ((float)fluidRandomizer.Next(1,9) / 10f); | ||
3643 | // m_log.Info((baseheight - 0.1f) + ((float)fluidRandomizer.Next(1, 9) / 10f)); | ||
3644 | } | ||
3645 | |||
3646 | lock (OdeLock) | ||
3647 | { | ||
3648 | if (WaterGeom != IntPtr.Zero) | ||
3649 | { | ||
3650 | d.SpaceRemove(space, WaterGeom); | ||
3651 | } | ||
3652 | IntPtr HeightmapData = d.GeomHeightfieldDataCreate(); | ||
3653 | d.GeomHeightfieldDataBuildSingle(HeightmapData, _watermap, 0, heightmapWidth, heightmapHeight, | ||
3654 | (int)heightmapWidthSamples, (int)heightmapHeightSamples, scale, | ||
3655 | offset, thickness, wrap); | ||
3656 | d.GeomHeightfieldDataSetBounds(HeightmapData, m_regionWidth, m_regionHeight); | ||
3657 | WaterGeom = d.CreateHeightfield(space, HeightmapData, 1); | ||
3658 | if (WaterGeom != IntPtr.Zero) | ||
3659 | { | ||
3660 | d.GeomSetCategoryBits(WaterGeom, (int)(CollisionCategories.Water)); | ||
3661 | d.GeomSetCollideBits(WaterGeom, (int)(CollisionCategories.Space)); | ||
3662 | |||
3663 | } | ||
3664 | geom_name_map[WaterGeom] = "Water"; | ||
3665 | |||
3666 | d.Matrix3 R = new d.Matrix3(); | ||
3667 | |||
3668 | Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f); | ||
3669 | Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f); | ||
3670 | //Axiom.Math.Quaternion q3 = Axiom.Math.Quaternion.FromAngleAxis(3.14f, new Axiom.Math.Vector3(0, 0, 1)); | ||
3671 | |||
3672 | q1 = q1 * q2; | ||
3673 | //q1 = q1 * q3; | ||
3674 | Vector3 v3; | ||
3675 | float angle; | ||
3676 | q1.GetAxisAngle(out v3, out angle); | ||
3677 | |||
3678 | d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle); | ||
3679 | d.GeomSetRotation(WaterGeom, ref R); | ||
3680 | d.GeomSetPosition(WaterGeom, 128, 128, 0); | ||
3681 | |||
3682 | } | ||
3683 | |||
3684 | } | ||
3685 | |||
3686 | public override void Dispose() | ||
3687 | { | ||
3688 | m_rayCastManager.Dispose(); | ||
3689 | m_rayCastManager = null; | ||
3690 | |||
3691 | lock (OdeLock) | ||
3692 | { | ||
3693 | lock (_prims) | ||
3694 | { | ||
3695 | foreach (OdePrim prm in _prims) | ||
3696 | { | ||
3697 | RemovePrim(prm); | ||
3698 | } | ||
3699 | } | ||
3700 | |||
3701 | //foreach (OdeCharacter act in _characters) | ||
3702 | //{ | ||
3703 | //RemoveAvatar(act); | ||
3704 | //} | ||
3705 | d.WorldDestroy(world); | ||
3706 | //d.CloseODE(); | ||
3707 | } | ||
3708 | } | ||
3709 | public override Dictionary<uint, float> GetTopColliders() | ||
3710 | { | ||
3711 | Dictionary<uint, float> returncolliders = new Dictionary<uint, float>(); | ||
3712 | int cnt = 0; | ||
3713 | lock (_prims) | ||
3714 | { | ||
3715 | foreach (OdePrim prm in _prims) | ||
3716 | { | ||
3717 | if (prm.CollisionScore > 0) | ||
3718 | { | ||
3719 | returncolliders.Add(prm.m_localID, prm.CollisionScore); | ||
3720 | cnt++; | ||
3721 | prm.CollisionScore = 0f; | ||
3722 | if (cnt > 25) | ||
3723 | { | ||
3724 | break; | ||
3725 | } | ||
3726 | } | ||
3727 | } | ||
3728 | } | ||
3729 | return returncolliders; | ||
3730 | } | ||
3731 | |||
3732 | public override bool SupportsRayCast() | ||
3733 | { | ||
3734 | return true; | ||
3735 | } | ||
3736 | |||
3737 | public override void RaycastWorld(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod) | ||
3738 | { | ||
3739 | if (retMethod != null) | ||
3740 | { | ||
3741 | m_rayCastManager.QueueRequest(position, direction, length, retMethod); | ||
3742 | } | ||
3743 | } | ||
3744 | |||
3745 | #if USE_DRAWSTUFF | ||
3746 | // Keyboard callback | ||
3747 | public void command(int cmd) | ||
3748 | { | ||
3749 | IntPtr geom; | ||
3750 | d.Mass mass; | ||
3751 | d.Vector3 sides = new d.Vector3(d.RandReal() * 0.5f + 0.1f, d.RandReal() * 0.5f + 0.1f, d.RandReal() * 0.5f + 0.1f); | ||
3752 | |||
3753 | |||
3754 | |||
3755 | Char ch = Char.ToLower((Char)cmd); | ||
3756 | switch ((Char)ch) | ||
3757 | { | ||
3758 | case 'w': | ||
3759 | try | ||
3760 | { | ||
3761 | Vector3 rotate = (new Vector3(1, 0, 0) * Quaternion.CreateFromEulers(hpr.Z * Utils.DEG_TO_RAD, hpr.Y * Utils.DEG_TO_RAD, hpr.X * Utils.DEG_TO_RAD)); | ||
3762 | |||
3763 | xyz.X += rotate.X; xyz.Y += rotate.Y; xyz.Z += rotate.Z; | ||
3764 | ds.SetViewpoint(ref xyz, ref hpr); | ||
3765 | } | ||
3766 | catch (ArgumentException) | ||
3767 | { hpr.X = 0; } | ||
3768 | break; | ||
3769 | |||
3770 | case 'a': | ||
3771 | hpr.X++; | ||
3772 | ds.SetViewpoint(ref xyz, ref hpr); | ||
3773 | break; | ||
3774 | |||
3775 | case 's': | ||
3776 | try | ||
3777 | { | ||
3778 | Vector3 rotate2 = (new Vector3(-1, 0, 0) * Quaternion.CreateFromEulers(hpr.Z * Utils.DEG_TO_RAD, hpr.Y * Utils.DEG_TO_RAD, hpr.X * Utils.DEG_TO_RAD)); | ||
3779 | |||
3780 | xyz.X += rotate2.X; xyz.Y += rotate2.Y; xyz.Z += rotate2.Z; | ||
3781 | ds.SetViewpoint(ref xyz, ref hpr); | ||
3782 | } | ||
3783 | catch (ArgumentException) | ||
3784 | { hpr.X = 0; } | ||
3785 | break; | ||
3786 | case 'd': | ||
3787 | hpr.X--; | ||
3788 | ds.SetViewpoint(ref xyz, ref hpr); | ||
3789 | break; | ||
3790 | case 'r': | ||
3791 | xyz.Z++; | ||
3792 | ds.SetViewpoint(ref xyz, ref hpr); | ||
3793 | break; | ||
3794 | case 'f': | ||
3795 | xyz.Z--; | ||
3796 | ds.SetViewpoint(ref xyz, ref hpr); | ||
3797 | break; | ||
3798 | case 'e': | ||
3799 | xyz.Y++; | ||
3800 | ds.SetViewpoint(ref xyz, ref hpr); | ||
3801 | break; | ||
3802 | case 'q': | ||
3803 | xyz.Y--; | ||
3804 | ds.SetViewpoint(ref xyz, ref hpr); | ||
3805 | break; | ||
3806 | } | ||
3807 | } | ||
3808 | |||
3809 | public void step(int pause) | ||
3810 | { | ||
3811 | |||
3812 | ds.SetColor(1.0f, 1.0f, 0.0f); | ||
3813 | ds.SetTexture(ds.Texture.Wood); | ||
3814 | lock (_prims) | ||
3815 | { | ||
3816 | foreach (OdePrim prm in _prims) | ||
3817 | { | ||
3818 | //IntPtr body = d.GeomGetBody(prm.prim_geom); | ||
3819 | if (prm.prim_geom != IntPtr.Zero) | ||
3820 | { | ||
3821 | d.Vector3 pos; | ||
3822 | d.GeomCopyPosition(prm.prim_geom, out pos); | ||
3823 | //d.BodyCopyPosition(body, out pos); | ||
3824 | |||
3825 | d.Matrix3 R; | ||
3826 | d.GeomCopyRotation(prm.prim_geom, out R); | ||
3827 | //d.BodyCopyRotation(body, out R); | ||
3828 | |||
3829 | |||
3830 | d.Vector3 sides = new d.Vector3(); | ||
3831 | sides.X = prm.Size.X; | ||
3832 | sides.Y = prm.Size.Y; | ||
3833 | sides.Z = prm.Size.Z; | ||
3834 | |||
3835 | ds.DrawBox(ref pos, ref R, ref sides); | ||
3836 | } | ||
3837 | } | ||
3838 | } | ||
3839 | ds.SetColor(1.0f, 0.0f, 0.0f); | ||
3840 | lock (_characters) | ||
3841 | { | ||
3842 | foreach (OdeCharacter chr in _characters) | ||
3843 | { | ||
3844 | if (chr.Shell != IntPtr.Zero) | ||
3845 | { | ||
3846 | IntPtr body = d.GeomGetBody(chr.Shell); | ||
3847 | |||
3848 | d.Vector3 pos; | ||
3849 | d.GeomCopyPosition(chr.Shell, out pos); | ||
3850 | //d.BodyCopyPosition(body, out pos); | ||
3851 | |||
3852 | d.Matrix3 R; | ||
3853 | d.GeomCopyRotation(chr.Shell, out R); | ||
3854 | //d.BodyCopyRotation(body, out R); | ||
3855 | |||
3856 | ds.DrawCapsule(ref pos, ref R, chr.Size.Z, 0.35f); | ||
3857 | d.Vector3 sides = new d.Vector3(); | ||
3858 | sides.X = 0.5f; | ||
3859 | sides.Y = 0.5f; | ||
3860 | sides.Z = 0.5f; | ||
3861 | |||
3862 | ds.DrawBox(ref pos, ref R, ref sides); | ||
3863 | } | ||
3864 | } | ||
3865 | } | ||
3866 | } | ||
3867 | |||
3868 | public void start(int unused) | ||
3869 | { | ||
3870 | ds.SetViewpoint(ref xyz, ref hpr); | ||
3871 | } | ||
3872 | #endif | ||
3873 | } | ||
3874 | } | ||
diff --git a/OpenSim/Region/Physics/ChOdePlugin/Tests/ODETestClass.cs b/OpenSim/Region/Physics/ChOdePlugin/Tests/ODETestClass.cs new file mode 100644 index 0000000..69e2d03 --- /dev/null +++ b/OpenSim/Region/Physics/ChOdePlugin/Tests/ODETestClass.cs | |||
@@ -0,0 +1,122 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using Nini.Config; | ||
30 | using NUnit.Framework; | ||
31 | using OpenMetaverse; | ||
32 | using OpenSim.Framework; | ||
33 | using OpenSim.Region.Physics.Manager; | ||
34 | using log4net; | ||
35 | using System.Reflection; | ||
36 | |||
37 | namespace OpenSim.Region.Physics.OdePlugin | ||
38 | { | ||
39 | [TestFixture] | ||
40 | public class ODETestClass | ||
41 | { | ||
42 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
43 | |||
44 | private OdePlugin cbt; | ||
45 | private PhysicsScene ps; | ||
46 | private IMeshingPlugin imp; | ||
47 | |||
48 | [SetUp] | ||
49 | public void Initialize() | ||
50 | { | ||
51 | // Loading ODEPlugin | ||
52 | cbt = new OdePlugin(); | ||
53 | // Loading Zero Mesher | ||
54 | imp = new ZeroMesherPlugin(); | ||
55 | // Getting Physics Scene | ||
56 | ps = cbt.GetScene("test"); | ||
57 | // Initializing Physics Scene. | ||
58 | ps.Initialise(imp.GetMesher(),null); | ||
59 | float[] _heightmap = new float[(int)Constants.RegionSize * (int)Constants.RegionSize]; | ||
60 | for (int i = 0; i < ((int)Constants.RegionSize * (int)Constants.RegionSize); i++) | ||
61 | { | ||
62 | _heightmap[i] = 21f; | ||
63 | } | ||
64 | ps.SetTerrain(_heightmap); | ||
65 | } | ||
66 | |||
67 | [TearDown] | ||
68 | public void Terminate() | ||
69 | { | ||
70 | ps.DeleteTerrain(); | ||
71 | ps.Dispose(); | ||
72 | |||
73 | } | ||
74 | |||
75 | [Test] | ||
76 | public void CreateAndDropPhysicalCube() | ||
77 | { | ||
78 | PrimitiveBaseShape newcube = PrimitiveBaseShape.CreateBox(); | ||
79 | Vector3 position = new Vector3(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f), 128f); | ||
80 | Vector3 size = new Vector3(0.5f, 0.5f, 0.5f); | ||
81 | Quaternion rot = Quaternion.Identity; | ||
82 | PhysicsActor prim = ps.AddPrimShape("CoolShape", newcube, position, size, rot, true); | ||
83 | OdePrim oprim = (OdePrim)prim; | ||
84 | OdeScene pscene = (OdeScene) ps; | ||
85 | |||
86 | Assert.That(oprim.m_taintadd); | ||
87 | |||
88 | prim.LocalID = 5; | ||
89 | |||
90 | for (int i = 0; i < 58; i++) | ||
91 | { | ||
92 | ps.Simulate(0.133f); | ||
93 | |||
94 | Assert.That(oprim.prim_geom != (IntPtr)0); | ||
95 | |||
96 | Assert.That(oprim.m_targetSpace != (IntPtr)0); | ||
97 | |||
98 | //Assert.That(oprim.m_targetSpace == pscene.space); | ||
99 | m_log.Info("TargetSpace: " + oprim.m_targetSpace + " - SceneMainSpace: " + pscene.space); | ||
100 | |||
101 | Assert.That(!oprim.m_taintadd); | ||
102 | m_log.Info("Prim Position (" + oprim.m_localID + "): " + prim.Position.ToString()); | ||
103 | |||
104 | // Make sure we're above the ground | ||
105 | //Assert.That(prim.Position.Z > 20f); | ||
106 | //m_log.Info("PrimCollisionScore (" + oprim.m_localID + "): " + oprim.m_collisionscore); | ||
107 | |||
108 | // Make sure we've got a Body | ||
109 | Assert.That(oprim.Body != (IntPtr)0); | ||
110 | //m_log.Info( | ||
111 | } | ||
112 | |||
113 | // Make sure we're not somewhere above the ground | ||
114 | Assert.That(prim.Position.Z < 21.5f); | ||
115 | |||
116 | ps.RemovePrim(prim); | ||
117 | Assert.That(oprim.m_taintremove); | ||
118 | ps.Simulate(0.133f); | ||
119 | Assert.That(oprim.Body == (IntPtr)0); | ||
120 | } | ||
121 | } | ||
122 | } | ||
diff --git a/OpenSim/Region/Physics/ChOdePlugin/drawstuff.cs b/OpenSim/Region/Physics/ChOdePlugin/drawstuff.cs new file mode 100644 index 0000000..87ca446 --- /dev/null +++ b/OpenSim/Region/Physics/ChOdePlugin/drawstuff.cs | |||
@@ -0,0 +1,98 @@ | |||
1 | /* | ||
2 | * Copyright ODE | ||
3 | * Ode.NET - .NET bindings for ODE | ||
4 | * Jason Perkins (starkos@industriousone.com) | ||
5 | * Licensed under the New BSD | ||
6 | * Part of the OpenDynamicsEngine | ||
7 | Open Dynamics Engine | ||
8 | Copyright (c) 2001-2007, Russell L. Smith. | ||
9 | All rights reserved. | ||
10 | |||
11 | Redistribution and use in source and binary forms, with or without | ||
12 | modification, are permitted provided that the following conditions | ||
13 | are met: | ||
14 | |||
15 | Redistributions of source code must retain the above copyright notice, | ||
16 | this list of conditions and the following disclaimer. | ||
17 | |||
18 | Redistributions in binary form must reproduce the above copyright notice, | ||
19 | this list of conditions and the following disclaimer in the documentation | ||
20 | and/or other materials provided with the distribution. | ||
21 | |||
22 | Neither the names of ODE's copyright owner nor the names of its | ||
23 | contributors may be used to endorse or promote products derived from | ||
24 | this software without specific prior written permission. | ||
25 | |||
26 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
27 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
28 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
29 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
30 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
31 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED | ||
32 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | ||
33 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||
34 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||
35 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
36 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
37 | * | ||
38 | * | ||
39 | */ | ||
40 | |||
41 | using System; | ||
42 | using System.Runtime.InteropServices; | ||
43 | using Ode.NET; | ||
44 | |||
45 | namespace Drawstuff.NET | ||
46 | { | ||
47 | #if dDOUBLE | ||
48 | using dReal = System.Double; | ||
49 | #else | ||
50 | using dReal = System.Single; | ||
51 | #endif | ||
52 | |||
53 | public static class ds | ||
54 | { | ||
55 | public const int VERSION = 2; | ||
56 | |||
57 | public enum Texture | ||
58 | { | ||
59 | None, | ||
60 | Wood | ||
61 | } | ||
62 | |||
63 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] | ||
64 | public delegate void CallbackFunction(int arg); | ||
65 | |||
66 | [StructLayout(LayoutKind.Sequential)] | ||
67 | public struct Functions | ||
68 | { | ||
69 | public int version; | ||
70 | public CallbackFunction start; | ||
71 | public CallbackFunction step; | ||
72 | public CallbackFunction command; | ||
73 | public CallbackFunction stop; | ||
74 | public string path_to_textures; | ||
75 | } | ||
76 | |||
77 | [DllImport("drawstuff", EntryPoint = "dsDrawBox")] | ||
78 | public static extern void DrawBox(ref d.Vector3 pos, ref d.Matrix3 R, ref d.Vector3 sides); | ||
79 | |||
80 | [DllImport("drawstuff", EntryPoint = "dsDrawCapsule")] | ||
81 | public static extern void DrawCapsule(ref d.Vector3 pos, ref d.Matrix3 R, dReal length, dReal radius); | ||
82 | |||
83 | [DllImport("drawstuff", EntryPoint = "dsDrawConvex")] | ||
84 | public static extern void DrawConvex(ref d.Vector3 pos, ref d.Matrix3 R, dReal[] planes, int planeCount, dReal[] points, int pointCount, int[] polygons); | ||
85 | |||
86 | [DllImport("drawstuff", EntryPoint = "dsSetColor")] | ||
87 | public static extern void SetColor(float red, float green, float blue); | ||
88 | |||
89 | [DllImport("drawstuff", EntryPoint = "dsSetTexture")] | ||
90 | public static extern void SetTexture(Texture texture); | ||
91 | |||
92 | [DllImport("drawstuff", EntryPoint = "dsSetViewpoint")] | ||
93 | public static extern void SetViewpoint(ref d.Vector3 xyz, ref d.Vector3 hpr); | ||
94 | |||
95 | [DllImport("drawstuff", EntryPoint = "dsSimulationLoop")] | ||
96 | public static extern void SimulationLoop(int argc, string[] argv, int window_width, int window_height, ref Functions fn); | ||
97 | } | ||
98 | } | ||
diff --git a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs index 06ed8fb..a38fccc 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs | |||
@@ -1205,7 +1205,6 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1205 | 1205 | ||
1206 | public override float APIDDamping{ set { return; } } | 1206 | public override float APIDDamping{ set { return; } } |
1207 | 1207 | ||
1208 | |||
1209 | public override void SubscribeEvents(int ms) | 1208 | public override void SubscribeEvents(int ms) |
1210 | { | 1209 | { |
1211 | m_requestedUpdateFrequency = ms; | 1210 | m_requestedUpdateFrequency = ms; |
diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs index 973aa84..567fd0e 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs | |||
@@ -2824,7 +2824,7 @@ Console.WriteLine(" JointCreateFixed"); | |||
2824 | } | 2824 | } |
2825 | public override bool PIDActive { set { m_usePID = value; } } | 2825 | public override bool PIDActive { set { m_usePID = value; } } |
2826 | public override float PIDTau { set { m_PIDTau = value; } } | 2826 | public override float PIDTau { set { m_PIDTau = value; } } |
2827 | 2827 | ||
2828 | public override float PIDHoverHeight { set { m_PIDHoverHeight = value; ; } } | 2828 | public override float PIDHoverHeight { set { m_PIDHoverHeight = value; ; } } |
2829 | public override bool PIDHoverActive { set { m_useHoverPID = value; } } | 2829 | public override bool PIDHoverActive { set { m_useHoverPID = value; } } |
2830 | public override PIDHoverType PIDHoverType { set { m_PIDHoverType = value; } } | 2830 | public override PIDHoverType PIDHoverType { set { m_PIDHoverType = value; } } |
diff --git a/OpenSim/Region/Physics/POSPlugin/POSPrim.cs b/OpenSim/Region/Physics/POSPlugin/POSPrim.cs index 7447f76..edccf47 100644 --- a/OpenSim/Region/Physics/POSPlugin/POSPrim.cs +++ b/OpenSim/Region/Physics/POSPlugin/POSPrim.cs | |||
@@ -299,7 +299,7 @@ namespace OpenSim.Region.Physics.POSPlugin | |||
299 | { | 299 | { |
300 | set { return; } | 300 | set { return; } |
301 | } | 301 | } |
302 | 302 | ||
303 | public override Quaternion APIDTarget | 303 | public override Quaternion APIDTarget |
304 | { | 304 | { |
305 | set { return; } | 305 | set { return; } |
diff --git a/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs b/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs index 1a99c83..92f060b 100644 --- a/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs +++ b/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs | |||
@@ -88,89 +88,7 @@ namespace OpenSim.Region.RegionCombinerModule | |||
88 | public void RegionLoaded(Scene scene) | 88 | public void RegionLoaded(Scene scene) |
89 | { | 89 | { |
90 | if (enabledYN) | 90 | if (enabledYN) |
91 | { | ||
92 | RegionLoadedDoWork(scene); | 91 | RegionLoadedDoWork(scene); |
93 | |||
94 | scene.EventManager.OnNewPresence += NewPresence; | ||
95 | } | ||
96 | } | ||
97 | |||
98 | private void NewPresence(ScenePresence presence) | ||
99 | { | ||
100 | if (presence.IsChildAgent) | ||
101 | { | ||
102 | byte[] throttleData; | ||
103 | |||
104 | try | ||
105 | { | ||
106 | throttleData = presence.ControllingClient.GetThrottlesPacked(1); | ||
107 | } | ||
108 | catch (NotImplementedException) | ||
109 | { | ||
110 | return; | ||
111 | } | ||
112 | |||
113 | if (throttleData == null) | ||
114 | return; | ||
115 | |||
116 | if (throttleData.Length == 0) | ||
117 | return; | ||
118 | |||
119 | if (throttleData.Length != 28) | ||
120 | return; | ||
121 | |||
122 | byte[] adjData; | ||
123 | int pos = 0; | ||
124 | |||
125 | if (!BitConverter.IsLittleEndian) | ||
126 | { | ||
127 | byte[] newData = new byte[7 * 4]; | ||
128 | Buffer.BlockCopy(throttleData, 0, newData, 0, 7 * 4); | ||
129 | |||
130 | for (int i = 0; i < 7; i++) | ||
131 | Array.Reverse(newData, i * 4, 4); | ||
132 | |||
133 | adjData = newData; | ||
134 | } | ||
135 | else | ||
136 | { | ||
137 | adjData = throttleData; | ||
138 | } | ||
139 | |||
140 | // 0.125f converts from bits to bytes | ||
141 | int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; | ||
142 | int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; | ||
143 | int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; | ||
144 | int cloud = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; | ||
145 | int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; | ||
146 | int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; | ||
147 | int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); | ||
148 | // State is a subcategory of task that we allocate a percentage to | ||
149 | |||
150 | |||
151 | //int total = resend + land + wind + cloud + task + texture + asset; | ||
152 | |||
153 | byte[] data = new byte[7 * 4]; | ||
154 | int ii = 0; | ||
155 | |||
156 | Buffer.BlockCopy(Utils.FloatToBytes(resend), 0, data, ii, 4); ii += 4; | ||
157 | Buffer.BlockCopy(Utils.FloatToBytes(land * 50), 0, data, ii, 4); ii += 4; | ||
158 | Buffer.BlockCopy(Utils.FloatToBytes(wind), 0, data, ii, 4); ii += 4; | ||
159 | Buffer.BlockCopy(Utils.FloatToBytes(cloud), 0, data, ii, 4); ii += 4; | ||
160 | Buffer.BlockCopy(Utils.FloatToBytes(task), 0, data, ii, 4); ii += 4; | ||
161 | Buffer.BlockCopy(Utils.FloatToBytes(texture), 0, data, ii, 4); ii += 4; | ||
162 | Buffer.BlockCopy(Utils.FloatToBytes(asset), 0, data, ii, 4); | ||
163 | |||
164 | try | ||
165 | { | ||
166 | presence.ControllingClient.SetChildAgentThrottle(data); | ||
167 | } | ||
168 | catch (NotImplementedException) | ||
169 | { | ||
170 | return; | ||
171 | } | ||
172 | |||
173 | } | ||
174 | } | 92 | } |
175 | 93 | ||
176 | private void RegionLoadedDoWork(Scene scene) | 94 | private void RegionLoadedDoWork(Scene scene) |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/CM_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/CM_Api.cs new file mode 100644 index 0000000..d4250c1 --- /dev/null +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/CM_Api.cs | |||
@@ -0,0 +1,473 @@ | |||
1 | using System; | ||
2 | using System.Reflection; | ||
3 | using System.Collections; | ||
4 | using System.Collections.Generic; | ||
5 | using System.Runtime.Remoting.Lifetime; | ||
6 | using OpenMetaverse; | ||
7 | using Nini.Config; | ||
8 | using OpenSim; | ||
9 | using OpenSim.Framework; | ||
10 | using OpenSim.Region.CoreModules.World.Meta7Windlight; | ||
11 | using OpenSim.Region.Framework.Interfaces; | ||
12 | using OpenSim.Region.Framework.Scenes; | ||
13 | using OpenSim.Region.ScriptEngine.Shared; | ||
14 | using OpenSim.Region.ScriptEngine.Shared.Api.Plugins; | ||
15 | using OpenSim.Region.ScriptEngine.Shared.ScriptBase; | ||
16 | using OpenSim.Region.ScriptEngine.Interfaces; | ||
17 | using OpenSim.Region.ScriptEngine.Shared.Api.Interfaces; | ||
18 | |||
19 | using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat; | ||
20 | using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger; | ||
21 | using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; | ||
22 | using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list; | ||
23 | using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion; | ||
24 | using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; | ||
25 | using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3; | ||
26 | |||
27 | namespace OpenSim.Region.ScriptEngine.Shared.Api | ||
28 | { | ||
29 | [Serializable] | ||
30 | public class CM_Api : MarshalByRefObject, ICM_Api, IScriptApi | ||
31 | { | ||
32 | internal IScriptEngine m_ScriptEngine; | ||
33 | internal SceneObjectPart m_host; | ||
34 | internal uint m_localID; | ||
35 | internal UUID m_itemID; | ||
36 | internal bool m_CMFunctionsEnabled = false; | ||
37 | internal IScriptModuleComms m_comms = null; | ||
38 | |||
39 | public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, uint localID, UUID itemID) | ||
40 | { | ||
41 | m_ScriptEngine = ScriptEngine; | ||
42 | m_host = host; | ||
43 | m_localID = localID; | ||
44 | m_itemID = itemID; | ||
45 | |||
46 | if (m_ScriptEngine.Config.GetBoolean("AllowCareminsterFunctions", false)) | ||
47 | m_CMFunctionsEnabled = true; | ||
48 | |||
49 | m_comms = m_ScriptEngine.World.RequestModuleInterface<IScriptModuleComms>(); | ||
50 | if (m_comms == null) | ||
51 | m_CMFunctionsEnabled = false; | ||
52 | } | ||
53 | |||
54 | public override Object InitializeLifetimeService() | ||
55 | { | ||
56 | ILease lease = (ILease)base.InitializeLifetimeService(); | ||
57 | |||
58 | if (lease.CurrentState == LeaseState.Initial) | ||
59 | { | ||
60 | lease.InitialLeaseTime = TimeSpan.FromMinutes(0); | ||
61 | // lease.RenewOnCallTime = TimeSpan.FromSeconds(10.0); | ||
62 | // lease.SponsorshipTimeout = TimeSpan.FromMinutes(1.0); | ||
63 | } | ||
64 | return lease; | ||
65 | } | ||
66 | |||
67 | public Scene World | ||
68 | { | ||
69 | get { return m_ScriptEngine.World; } | ||
70 | } | ||
71 | |||
72 | // | ||
73 | //Dumps an error message on the debug console. | ||
74 | // | ||
75 | |||
76 | internal void CMShoutError(string message) | ||
77 | { | ||
78 | if (message.Length > 1023) | ||
79 | message = message.Substring(0, 1023); | ||
80 | |||
81 | World.SimChat(Utils.StringToBytes(message), | ||
82 | ChatTypeEnum.Shout, ScriptBaseClass.DEBUG_CHANNEL, m_host.ParentGroup.RootPart.AbsolutePosition, m_host.Name, m_host.UUID, true); | ||
83 | |||
84 | IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>(); | ||
85 | wComm.DeliverMessage(ChatTypeEnum.Shout, ScriptBaseClass.DEBUG_CHANNEL, m_host.Name, m_host.UUID, message); | ||
86 | } | ||
87 | |||
88 | /// <summary> | ||
89 | /// Get the current Windlight scene | ||
90 | /// </summary> | ||
91 | /// <returns>List of windlight parameters</returns> | ||
92 | public LSL_List cmGetWindlightScene(LSL_List rules) | ||
93 | { | ||
94 | if (!m_CMFunctionsEnabled) | ||
95 | { | ||
96 | CMShoutError("Careminster functions are not enabled."); | ||
97 | return new LSL_List(); | ||
98 | } | ||
99 | m_host.AddScriptLPS(1); | ||
100 | RegionMeta7WindlightData wl = m_host.ParentGroup.Scene.RegionInfo.WindlightSettings; | ||
101 | |||
102 | LSL_List values = new LSL_List(); | ||
103 | int idx = 0; | ||
104 | while (idx < rules.Length) | ||
105 | { | ||
106 | uint rule = (uint)rules.GetLSLIntegerItem(idx); | ||
107 | LSL_List toadd = new LSL_List(); | ||
108 | |||
109 | switch (rule) | ||
110 | { | ||
111 | case (int)ScriptBaseClass.WL_AMBIENT: | ||
112 | toadd.Add(new LSL_Rotation(wl.ambient.X, wl.ambient.Y, wl.ambient.Z, wl.ambient.W)); | ||
113 | break; | ||
114 | case (int)ScriptBaseClass.WL_BIG_WAVE_DIRECTION: | ||
115 | toadd.Add(new LSL_Vector(wl.bigWaveDirection.X, wl.bigWaveDirection.Y, 0.0f)); | ||
116 | break; | ||
117 | case (int)ScriptBaseClass.WL_BLUE_DENSITY: | ||
118 | toadd.Add(new LSL_Rotation(wl.blueDensity.X, wl.blueDensity.Y, wl.blueDensity.Z, wl.blueDensity.W)); | ||
119 | break; | ||
120 | case (int)ScriptBaseClass.WL_BLUR_MULTIPLIER: | ||
121 | toadd.Add(new LSL_Float(wl.blurMultiplier)); | ||
122 | break; | ||
123 | case (int)ScriptBaseClass.WL_CLOUD_COLOR: | ||
124 | toadd.Add(new LSL_Rotation(wl.cloudColor.X, wl.cloudColor.Y, wl.cloudColor.Z, wl.cloudColor.W)); | ||
125 | break; | ||
126 | case (int)ScriptBaseClass.WL_CLOUD_COVERAGE: | ||
127 | toadd.Add(new LSL_Float(wl.cloudCoverage)); | ||
128 | break; | ||
129 | case (int)ScriptBaseClass.WL_CLOUD_DETAIL_XY_DENSITY: | ||
130 | toadd.Add(new LSL_Vector(wl.cloudDetailXYDensity.X, wl.cloudDetailXYDensity.Y, wl.cloudDetailXYDensity.Z)); | ||
131 | break; | ||
132 | case (int)ScriptBaseClass.WL_CLOUD_SCALE: | ||
133 | toadd.Add(new LSL_Float(wl.cloudScale)); | ||
134 | break; | ||
135 | case (int)ScriptBaseClass.WL_CLOUD_SCROLL_X: | ||
136 | toadd.Add(new LSL_Float(wl.cloudScrollX)); | ||
137 | break; | ||
138 | case (int)ScriptBaseClass.WL_CLOUD_SCROLL_X_LOCK: | ||
139 | toadd.Add(new LSL_Integer(wl.cloudScrollXLock ? 1 : 0)); | ||
140 | break; | ||
141 | case (int)ScriptBaseClass.WL_CLOUD_SCROLL_Y: | ||
142 | toadd.Add(new LSL_Float(wl.cloudScrollY)); | ||
143 | break; | ||
144 | case (int)ScriptBaseClass.WL_CLOUD_SCROLL_Y_LOCK: | ||
145 | toadd.Add(new LSL_Integer(wl.cloudScrollYLock ? 1 : 0)); | ||
146 | break; | ||
147 | case (int)ScriptBaseClass.WL_CLOUD_XY_DENSITY: | ||
148 | toadd.Add(new LSL_Vector(wl.cloudXYDensity.X, wl.cloudXYDensity.Y, wl.cloudXYDensity.Z)); | ||
149 | break; | ||
150 | case (int)ScriptBaseClass.WL_DENSITY_MULTIPLIER: | ||
151 | toadd.Add(new LSL_Float(wl.densityMultiplier)); | ||
152 | break; | ||
153 | case (int)ScriptBaseClass.WL_DISTANCE_MULTIPLIER: | ||
154 | toadd.Add(new LSL_Float(wl.distanceMultiplier)); | ||
155 | break; | ||
156 | case (int)ScriptBaseClass.WL_DRAW_CLASSIC_CLOUDS: | ||
157 | toadd.Add(new LSL_Integer(wl.drawClassicClouds ? 1 : 0)); | ||
158 | break; | ||
159 | case (int)ScriptBaseClass.WL_EAST_ANGLE: | ||
160 | toadd.Add(new LSL_Float(wl.eastAngle)); | ||
161 | break; | ||
162 | case (int)ScriptBaseClass.WL_FRESNEL_OFFSET: | ||
163 | toadd.Add(new LSL_Float(wl.fresnelOffset)); | ||
164 | break; | ||
165 | case (int)ScriptBaseClass.WL_FRESNEL_SCALE: | ||
166 | toadd.Add(new LSL_Float(wl.fresnelScale)); | ||
167 | break; | ||
168 | case (int)ScriptBaseClass.WL_HAZE_DENSITY: | ||
169 | toadd.Add(new LSL_Float(wl.hazeDensity)); | ||
170 | break; | ||
171 | case (int)ScriptBaseClass.WL_HAZE_HORIZON: | ||
172 | toadd.Add(new LSL_Float(wl.hazeHorizon)); | ||
173 | break; | ||
174 | case (int)ScriptBaseClass.WL_HORIZON: | ||
175 | toadd.Add(new LSL_Rotation(wl.horizon.X, wl.horizon.Y, wl.horizon.Z, wl.horizon.W)); | ||
176 | break; | ||
177 | case (int)ScriptBaseClass.WL_LITTLE_WAVE_DIRECTION: | ||
178 | toadd.Add(new LSL_Vector(wl.littleWaveDirection.X, wl.littleWaveDirection.Y, 0.0f)); | ||
179 | break; | ||
180 | case (int)ScriptBaseClass.WL_MAX_ALTITUDE: | ||
181 | toadd.Add(new LSL_Integer(wl.maxAltitude)); | ||
182 | break; | ||
183 | case (int)ScriptBaseClass.WL_NORMAL_MAP_TEXTURE: | ||
184 | toadd.Add(new LSL_Key(wl.normalMapTexture.ToString())); | ||
185 | break; | ||
186 | case (int)ScriptBaseClass.WL_REFLECTION_WAVELET_SCALE: | ||
187 | toadd.Add(new LSL_Vector(wl.reflectionWaveletScale.X, wl.reflectionWaveletScale.Y, wl.reflectionWaveletScale.Z)); | ||
188 | break; | ||
189 | case (int)ScriptBaseClass.WL_REFRACT_SCALE_ABOVE: | ||
190 | toadd.Add(new LSL_Float(wl.refractScaleAbove)); | ||
191 | break; | ||
192 | case (int)ScriptBaseClass.WL_REFRACT_SCALE_BELOW: | ||
193 | toadd.Add(new LSL_Float(wl.refractScaleBelow)); | ||
194 | break; | ||
195 | case (int)ScriptBaseClass.WL_SCENE_GAMMA: | ||
196 | toadd.Add(new LSL_Float(wl.sceneGamma)); | ||
197 | break; | ||
198 | case (int)ScriptBaseClass.WL_STAR_BRIGHTNESS: | ||
199 | toadd.Add(new LSL_Float(wl.starBrightness)); | ||
200 | break; | ||
201 | case (int)ScriptBaseClass.WL_SUN_GLOW_FOCUS: | ||
202 | toadd.Add(new LSL_Float(wl.sunGlowFocus)); | ||
203 | break; | ||
204 | case (int)ScriptBaseClass.WL_SUN_GLOW_SIZE: | ||
205 | toadd.Add(new LSL_Float(wl.sunGlowSize)); | ||
206 | break; | ||
207 | case (int)ScriptBaseClass.WL_SUN_MOON_COLOR: | ||
208 | toadd.Add(new LSL_Rotation(wl.sunMoonColor.X, wl.sunMoonColor.Y, wl.sunMoonColor.Z, wl.sunMoonColor.W)); | ||
209 | break; | ||
210 | case (int)ScriptBaseClass.WL_UNDERWATER_FOG_MODIFIER: | ||
211 | toadd.Add(new LSL_Float(wl.underwaterFogModifier)); | ||
212 | break; | ||
213 | case (int)ScriptBaseClass.WL_WATER_COLOR: | ||
214 | toadd.Add(new LSL_Vector(wl.waterColor.X, wl.waterColor.Y, wl.waterColor.Z)); | ||
215 | break; | ||
216 | case (int)ScriptBaseClass.WL_WATER_FOG_DENSITY_EXPONENT: | ||
217 | toadd.Add(new LSL_Float(wl.waterFogDensityExponent)); | ||
218 | break; | ||
219 | } | ||
220 | |||
221 | if (toadd.Length > 0) | ||
222 | { | ||
223 | values.Add(rule); | ||
224 | values.Add(toadd.Data[0]); | ||
225 | } | ||
226 | idx++; | ||
227 | } | ||
228 | |||
229 | |||
230 | return values; | ||
231 | |||
232 | } | ||
233 | |||
234 | private RegionMeta7WindlightData getWindlightProfileFromRules(LSL_List rules) | ||
235 | { | ||
236 | RegionMeta7WindlightData wl = (RegionMeta7WindlightData)m_host.ParentGroup.Scene.RegionInfo.WindlightSettings.Clone(); | ||
237 | |||
238 | LSL_List values = new LSL_List(); | ||
239 | int idx = 0; | ||
240 | while (idx < rules.Length) | ||
241 | { | ||
242 | uint rule = (uint)rules.GetLSLIntegerItem(idx); | ||
243 | LSL_Types.Quaternion iQ; | ||
244 | LSL_Types.Vector3 iV; | ||
245 | switch (rule) | ||
246 | { | ||
247 | case (int)ScriptBaseClass.WL_AMBIENT: | ||
248 | idx++; | ||
249 | iQ = rules.GetQuaternionItem(idx); | ||
250 | wl.ambient = new Vector4((float)iQ.x, (float)iQ.y, (float)iQ.z, (float)iQ.s); | ||
251 | break; | ||
252 | case (int)ScriptBaseClass.WL_BIG_WAVE_DIRECTION: | ||
253 | idx++; | ||
254 | iV = rules.GetVector3Item(idx); | ||
255 | wl.bigWaveDirection = new Vector2((float)iV.x, (float)iV.y); | ||
256 | break; | ||
257 | case (int)ScriptBaseClass.WL_BLUE_DENSITY: | ||
258 | idx++; | ||
259 | iQ = rules.GetQuaternionItem(idx); | ||
260 | wl.blueDensity = new Vector4((float)iQ.x, (float)iQ.y, (float)iQ.z, (float)iQ.s); | ||
261 | break; | ||
262 | case (int)ScriptBaseClass.WL_BLUR_MULTIPLIER: | ||
263 | idx++; | ||
264 | wl.blurMultiplier = (float)rules.GetLSLFloatItem(idx); | ||
265 | break; | ||
266 | case (int)ScriptBaseClass.WL_CLOUD_COLOR: | ||
267 | idx++; | ||
268 | iQ = rules.GetQuaternionItem(idx); | ||
269 | wl.cloudColor = new Vector4((float)iQ.x, (float)iQ.y, (float)iQ.z, (float)iQ.s); | ||
270 | break; | ||
271 | case (int)ScriptBaseClass.WL_CLOUD_COVERAGE: | ||
272 | idx++; | ||
273 | wl.cloudCoverage = (float)rules.GetLSLFloatItem(idx); | ||
274 | break; | ||
275 | case (int)ScriptBaseClass.WL_CLOUD_DETAIL_XY_DENSITY: | ||
276 | idx++; | ||
277 | iV = rules.GetVector3Item(idx); | ||
278 | wl.cloudDetailXYDensity = new Vector3((float)iV.x, (float)iV.y, (float)iV.z); | ||
279 | break; | ||
280 | case (int)ScriptBaseClass.WL_CLOUD_SCALE: | ||
281 | idx++; | ||
282 | wl.cloudScale = (float)rules.GetLSLFloatItem(idx); | ||
283 | break; | ||
284 | case (int)ScriptBaseClass.WL_CLOUD_SCROLL_X: | ||
285 | idx++; | ||
286 | wl.cloudScrollX = (float)rules.GetLSLFloatItem(idx); | ||
287 | break; | ||
288 | case (int)ScriptBaseClass.WL_CLOUD_SCROLL_X_LOCK: | ||
289 | idx++; | ||
290 | wl.cloudScrollXLock = rules.GetLSLIntegerItem(idx).value == 1 ? true : false; | ||
291 | break; | ||
292 | case (int)ScriptBaseClass.WL_CLOUD_SCROLL_Y: | ||
293 | idx++; | ||
294 | wl.cloudScrollY = (float)rules.GetLSLFloatItem(idx); | ||
295 | break; | ||
296 | case (int)ScriptBaseClass.WL_CLOUD_SCROLL_Y_LOCK: | ||
297 | idx++; | ||
298 | wl.cloudScrollYLock = rules.GetLSLIntegerItem(idx).value == 1 ? true : false; | ||
299 | break; | ||
300 | case (int)ScriptBaseClass.WL_CLOUD_XY_DENSITY: | ||
301 | idx++; | ||
302 | iV = rules.GetVector3Item(idx); | ||
303 | wl.cloudDetailXYDensity = new Vector3((float)iV.x, (float)iV.y, (float)iV.z); | ||
304 | break; | ||
305 | case (int)ScriptBaseClass.WL_DENSITY_MULTIPLIER: | ||
306 | idx++; | ||
307 | wl.densityMultiplier = (float)rules.GetLSLFloatItem(idx); | ||
308 | break; | ||
309 | case (int)ScriptBaseClass.WL_DISTANCE_MULTIPLIER: | ||
310 | idx++; | ||
311 | wl.distanceMultiplier = (float)rules.GetLSLFloatItem(idx); | ||
312 | break; | ||
313 | case (int)ScriptBaseClass.WL_DRAW_CLASSIC_CLOUDS: | ||
314 | idx++; | ||
315 | wl.drawClassicClouds = rules.GetLSLIntegerItem(idx).value == 1 ? true : false; | ||
316 | break; | ||
317 | case (int)ScriptBaseClass.WL_EAST_ANGLE: | ||
318 | idx++; | ||
319 | wl.eastAngle = (float)rules.GetLSLFloatItem(idx); | ||
320 | break; | ||
321 | case (int)ScriptBaseClass.WL_FRESNEL_OFFSET: | ||
322 | idx++; | ||
323 | wl.fresnelOffset = (float)rules.GetLSLFloatItem(idx); | ||
324 | break; | ||
325 | case (int)ScriptBaseClass.WL_FRESNEL_SCALE: | ||
326 | idx++; | ||
327 | wl.fresnelScale = (float)rules.GetLSLFloatItem(idx); | ||
328 | break; | ||
329 | case (int)ScriptBaseClass.WL_HAZE_DENSITY: | ||
330 | idx++; | ||
331 | wl.hazeDensity = (float)rules.GetLSLFloatItem(idx); | ||
332 | break; | ||
333 | case (int)ScriptBaseClass.WL_HAZE_HORIZON: | ||
334 | idx++; | ||
335 | wl.hazeHorizon = (float)rules.GetLSLFloatItem(idx); | ||
336 | break; | ||
337 | case (int)ScriptBaseClass.WL_HORIZON: | ||
338 | idx++; | ||
339 | iQ = rules.GetQuaternionItem(idx); | ||
340 | wl.horizon = new Vector4((float)iQ.x, (float)iQ.y, (float)iQ.z, (float)iQ.s); | ||
341 | break; | ||
342 | case (int)ScriptBaseClass.WL_LITTLE_WAVE_DIRECTION: | ||
343 | idx++; | ||
344 | iV = rules.GetVector3Item(idx); | ||
345 | wl.littleWaveDirection = new Vector2((float)iV.x, (float)iV.y); | ||
346 | break; | ||
347 | case (int)ScriptBaseClass.WL_MAX_ALTITUDE: | ||
348 | idx++; | ||
349 | wl.maxAltitude = (ushort)rules.GetLSLIntegerItem(idx).value; | ||
350 | break; | ||
351 | case (int)ScriptBaseClass.WL_NORMAL_MAP_TEXTURE: | ||
352 | idx++; | ||
353 | wl.normalMapTexture = new UUID(rules.GetLSLStringItem(idx).m_string); | ||
354 | break; | ||
355 | case (int)ScriptBaseClass.WL_REFLECTION_WAVELET_SCALE: | ||
356 | idx++; | ||
357 | iV = rules.GetVector3Item(idx); | ||
358 | wl.reflectionWaveletScale = new Vector3((float)iV.x, (float)iV.y, (float)iV.z); | ||
359 | break; | ||
360 | case (int)ScriptBaseClass.WL_REFRACT_SCALE_ABOVE: | ||
361 | idx++; | ||
362 | wl.refractScaleAbove = (float)rules.GetLSLFloatItem(idx); | ||
363 | break; | ||
364 | case (int)ScriptBaseClass.WL_REFRACT_SCALE_BELOW: | ||
365 | idx++; | ||
366 | wl.refractScaleBelow = (float)rules.GetLSLFloatItem(idx); | ||
367 | break; | ||
368 | case (int)ScriptBaseClass.WL_SCENE_GAMMA: | ||
369 | idx++; | ||
370 | wl.sceneGamma = (float)rules.GetLSLFloatItem(idx); | ||
371 | break; | ||
372 | case (int)ScriptBaseClass.WL_STAR_BRIGHTNESS: | ||
373 | idx++; | ||
374 | wl.starBrightness = (float)rules.GetLSLFloatItem(idx); | ||
375 | break; | ||
376 | case (int)ScriptBaseClass.WL_SUN_GLOW_FOCUS: | ||
377 | idx++; | ||
378 | wl.sunGlowFocus = (float)rules.GetLSLFloatItem(idx); | ||
379 | break; | ||
380 | case (int)ScriptBaseClass.WL_SUN_GLOW_SIZE: | ||
381 | idx++; | ||
382 | wl.sunGlowSize = (float)rules.GetLSLFloatItem(idx); | ||
383 | break; | ||
384 | case (int)ScriptBaseClass.WL_SUN_MOON_COLOR: | ||
385 | idx++; | ||
386 | iQ = rules.GetQuaternionItem(idx); | ||
387 | wl.sunMoonColor = new Vector4((float)iQ.x, (float)iQ.y, (float)iQ.z, (float)iQ.s); | ||
388 | break; | ||
389 | case (int)ScriptBaseClass.WL_UNDERWATER_FOG_MODIFIER: | ||
390 | idx++; | ||
391 | wl.underwaterFogModifier = (float)rules.GetLSLFloatItem(idx); | ||
392 | break; | ||
393 | case (int)ScriptBaseClass.WL_WATER_COLOR: | ||
394 | idx++; | ||
395 | iV = rules.GetVector3Item(idx); | ||
396 | wl.waterColor = new Vector3((float)iV.x, (float)iV.y, (float)iV.z); | ||
397 | break; | ||
398 | case (int)ScriptBaseClass.WL_WATER_FOG_DENSITY_EXPONENT: | ||
399 | idx++; | ||
400 | wl.waterFogDensityExponent = (float)rules.GetLSLFloatItem(idx); | ||
401 | break; | ||
402 | } | ||
403 | idx++; | ||
404 | } | ||
405 | return wl; | ||
406 | } | ||
407 | /// <summary> | ||
408 | /// Set the current Windlight scene | ||
409 | /// </summary> | ||
410 | /// <param name="rules"></param> | ||
411 | /// <returns>success: true or false</returns> | ||
412 | public int cmSetWindlightScene(LSL_List rules) | ||
413 | { | ||
414 | if (!m_CMFunctionsEnabled) | ||
415 | { | ||
416 | CMShoutError("Careminster functions are not enabled."); | ||
417 | return 0; | ||
418 | } | ||
419 | if (!World.RegionInfo.EstateSettings.IsEstateManager(m_host.OwnerID) && World.GetScenePresence(m_host.OwnerID).GodLevel < 200) | ||
420 | { | ||
421 | CMShoutError("cmSetWindlightScene can only be used by estate managers or owners."); | ||
422 | return 0; | ||
423 | } | ||
424 | int success = 0; | ||
425 | m_host.AddScriptLPS(1); | ||
426 | if (Meta7WindlightModule.EnableWindlight) | ||
427 | { | ||
428 | RegionMeta7WindlightData wl = getWindlightProfileFromRules(rules); | ||
429 | m_host.ParentGroup.Scene.StoreWindlightProfile(wl); | ||
430 | success = 1; | ||
431 | } | ||
432 | else | ||
433 | { | ||
434 | CMShoutError("Windlight module is disabled"); | ||
435 | return 0; | ||
436 | } | ||
437 | return success; | ||
438 | } | ||
439 | /// <summary> | ||
440 | /// Set the current Windlight scene to a target avatar | ||
441 | /// </summary> | ||
442 | /// <param name="rules"></param> | ||
443 | /// <returns>success: true or false</returns> | ||
444 | public int cmSetWindlightSceneTargeted(LSL_List rules, LSL_Key target) | ||
445 | { | ||
446 | if (!m_CMFunctionsEnabled) | ||
447 | { | ||
448 | CMShoutError("Careminster functions are not enabled."); | ||
449 | return 0; | ||
450 | } | ||
451 | if (!World.RegionInfo.EstateSettings.IsEstateManager(m_host.OwnerID) && World.GetScenePresence(m_host.OwnerID).GodLevel < 200) | ||
452 | { | ||
453 | CMShoutError("cmSetWindlightSceneTargeted can only be used by estate managers or owners."); | ||
454 | return 0; | ||
455 | } | ||
456 | int success = 0; | ||
457 | m_host.AddScriptLPS(1); | ||
458 | if (Meta7WindlightModule.EnableWindlight) | ||
459 | { | ||
460 | RegionMeta7WindlightData wl = getWindlightProfileFromRules(rules); | ||
461 | World.EventManager.TriggerOnSendNewWindlightProfileTargeted(wl, new UUID(target.m_string)); | ||
462 | success = 1; | ||
463 | } | ||
464 | else | ||
465 | { | ||
466 | CMShoutError("Windlight module is disabled"); | ||
467 | return 0; | ||
468 | } | ||
469 | return success; | ||
470 | } | ||
471 | |||
472 | } | ||
473 | } | ||
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 39b597e..1469e7e 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | |||
@@ -28,6 +28,7 @@ | |||
28 | using System; | 28 | using System; |
29 | using System.Collections; | 29 | using System.Collections; |
30 | using System.Collections.Generic; | 30 | using System.Collections.Generic; |
31 | using System.Diagnostics; //for [DebuggerNonUserCode] | ||
31 | using System.Runtime.Remoting.Lifetime; | 32 | using System.Runtime.Remoting.Lifetime; |
32 | using System.Text; | 33 | using System.Text; |
33 | using System.Threading; | 34 | using System.Threading; |
@@ -151,6 +152,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
151 | get { return m_ScriptEngine.World; } | 152 | get { return m_ScriptEngine.World; } |
152 | } | 153 | } |
153 | 154 | ||
155 | [DebuggerNonUserCode] | ||
154 | public void state(string newState) | 156 | public void state(string newState) |
155 | { | 157 | { |
156 | m_ScriptEngine.SetState(m_itemID, newState); | 158 | m_ScriptEngine.SetState(m_itemID, newState); |
@@ -160,6 +162,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
160 | /// Reset the named script. The script must be present | 162 | /// Reset the named script. The script must be present |
161 | /// in the same prim. | 163 | /// in the same prim. |
162 | /// </summary> | 164 | /// </summary> |
165 | [DebuggerNonUserCode] | ||
163 | public void llResetScript() | 166 | public void llResetScript() |
164 | { | 167 | { |
165 | m_host.AddScriptLPS(1); | 168 | m_host.AddScriptLPS(1); |
@@ -218,7 +221,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
218 | 221 | ||
219 | public List<SceneObjectPart> GetLinkParts(int linkType) | 222 | public List<SceneObjectPart> GetLinkParts(int linkType) |
220 | { | 223 | { |
221 | List<SceneObjectPart> ret = new List<SceneObjectPart>(); | 224 | List<SceneObjectPart> ret = new List<SceneObjectPart>(); |
225 | if (m_host == null || m_host.ParentGroup == null || m_host.ParentGroup.IsDeleted) | ||
226 | return ret; | ||
222 | ret.Add(m_host); | 227 | ret.Add(m_host); |
223 | 228 | ||
224 | switch (linkType) | 229 | switch (linkType) |
@@ -272,40 +277,48 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
272 | protected UUID InventorySelf() | 277 | protected UUID InventorySelf() |
273 | { | 278 | { |
274 | UUID invItemID = new UUID(); | 279 | UUID invItemID = new UUID(); |
275 | 280 | bool unlock = false; | |
276 | lock (m_host.TaskInventory) | 281 | if (!m_host.TaskInventory.IsReadLockedByMe()) |
282 | { | ||
283 | m_host.TaskInventory.LockItemsForRead(true); | ||
284 | unlock = true; | ||
285 | } | ||
286 | foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) | ||
277 | { | 287 | { |
278 | foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) | 288 | if (inv.Value.Type == 10 && inv.Value.ItemID == m_itemID) |
279 | { | 289 | { |
280 | if (inv.Value.Type == 10 && inv.Value.ItemID == m_itemID) | 290 | invItemID = inv.Key; |
281 | { | 291 | break; |
282 | invItemID = inv.Key; | ||
283 | break; | ||
284 | } | ||
285 | } | 292 | } |
286 | } | 293 | } |
287 | 294 | if (unlock) | |
295 | { | ||
296 | m_host.TaskInventory.LockItemsForRead(false); | ||
297 | } | ||
288 | return invItemID; | 298 | return invItemID; |
289 | } | 299 | } |
290 | 300 | ||
291 | protected UUID InventoryKey(string name, int type) | 301 | protected UUID InventoryKey(string name, int type) |
292 | { | 302 | { |
293 | m_host.AddScriptLPS(1); | 303 | m_host.AddScriptLPS(1); |
294 | 304 | m_host.TaskInventory.LockItemsForRead(true); | |
295 | lock (m_host.TaskInventory) | 305 | |
306 | foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) | ||
296 | { | 307 | { |
297 | foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) | 308 | if (inv.Value.Name == name) |
298 | { | 309 | { |
299 | if (inv.Value.Name == name) | 310 | m_host.TaskInventory.LockItemsForRead(false); |
311 | |||
312 | if (inv.Value.Type != type) | ||
300 | { | 313 | { |
301 | if (inv.Value.Type != type) | 314 | return UUID.Zero; |
302 | return UUID.Zero; | ||
303 | |||
304 | return inv.Value.AssetID; | ||
305 | } | 315 | } |
316 | |||
317 | return inv.Value.AssetID; | ||
306 | } | 318 | } |
307 | } | 319 | } |
308 | 320 | ||
321 | m_host.TaskInventory.LockItemsForRead(false); | ||
309 | return UUID.Zero; | 322 | return UUID.Zero; |
310 | } | 323 | } |
311 | 324 | ||
@@ -313,17 +326,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
313 | { | 326 | { |
314 | m_host.AddScriptLPS(1); | 327 | m_host.AddScriptLPS(1); |
315 | 328 | ||
316 | lock (m_host.TaskInventory) | 329 | |
330 | m_host.TaskInventory.LockItemsForRead(true); | ||
331 | |||
332 | foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) | ||
317 | { | 333 | { |
318 | foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) | 334 | if (inv.Value.Name == name) |
319 | { | 335 | { |
320 | if (inv.Value.Name == name) | 336 | m_host.TaskInventory.LockItemsForRead(false); |
321 | { | 337 | return inv.Value.AssetID; |
322 | return inv.Value.AssetID; | ||
323 | } | ||
324 | } | 338 | } |
325 | } | 339 | } |
326 | 340 | ||
341 | m_host.TaskInventory.LockItemsForRead(false); | ||
342 | |||
343 | |||
327 | return UUID.Zero; | 344 | return UUID.Zero; |
328 | } | 345 | } |
329 | 346 | ||
@@ -705,6 +722,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
705 | { | 722 | { |
706 | //A and B should both be normalized | 723 | //A and B should both be normalized |
707 | m_host.AddScriptLPS(1); | 724 | m_host.AddScriptLPS(1); |
725 | /* This method is more accurate than the SL one, and thus causes problems | ||
726 | for scripts that deal with the SL inaccuracy around 180-degrees -.- .._. | ||
727 | |||
708 | double dotProduct = LSL_Vector.Dot(a, b); | 728 | double dotProduct = LSL_Vector.Dot(a, b); |
709 | LSL_Vector crossProduct = LSL_Vector.Cross(a, b); | 729 | LSL_Vector crossProduct = LSL_Vector.Cross(a, b); |
710 | double magProduct = LSL_Vector.Mag(a) * LSL_Vector.Mag(b); | 730 | double magProduct = LSL_Vector.Mag(a) * LSL_Vector.Mag(b); |
@@ -721,8 +741,57 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
721 | return new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f); | 741 | return new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f); |
722 | 742 | ||
723 | return new LSL_Rotation((float)x, (float)y, (float)z, (float)w); | 743 | return new LSL_Rotation((float)x, (float)y, (float)z, (float)w); |
724 | } | 744 | */ |
725 | 745 | ||
746 | // This method mimics the 180 errors found in SL | ||
747 | // See www.euclideanspace.com... angleBetween | ||
748 | LSL_Vector vec_a = a; | ||
749 | LSL_Vector vec_b = b; | ||
750 | |||
751 | // Eliminate zero length | ||
752 | LSL_Float vec_a_mag = LSL_Vector.Mag(vec_a); | ||
753 | LSL_Float vec_b_mag = LSL_Vector.Mag(vec_b); | ||
754 | if (vec_a_mag < 0.00001 || | ||
755 | vec_b_mag < 0.00001) | ||
756 | { | ||
757 | return new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f); | ||
758 | } | ||
759 | |||
760 | // Normalize | ||
761 | vec_a = llVecNorm(vec_a); | ||
762 | vec_b = llVecNorm(vec_b); | ||
763 | |||
764 | // Calculate axis and rotation angle | ||
765 | LSL_Vector axis = vec_a % vec_b; | ||
766 | LSL_Float cos_theta = vec_a * vec_b; | ||
767 | |||
768 | // Check if parallel | ||
769 | if (cos_theta > 0.99999) | ||
770 | { | ||
771 | return new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f); | ||
772 | } | ||
773 | |||
774 | // Check if anti-parallel | ||
775 | else if (cos_theta < -0.99999) | ||
776 | { | ||
777 | LSL_Vector orthog_axis = new LSL_Vector(1.0, 0.0, 0.0) - (vec_a.x / (vec_a * vec_a) * vec_a); | ||
778 | if (LSL_Vector.Mag(orthog_axis) < 0.000001) orthog_axis = new LSL_Vector(0.0, 0.0, 1.0); | ||
779 | return new LSL_Rotation((float)orthog_axis.x, (float)orthog_axis.y, (float)orthog_axis.z, 0.0); | ||
780 | } | ||
781 | else // other rotation | ||
782 | { | ||
783 | LSL_Float theta = (LSL_Float)Math.Acos(cos_theta) * 0.5f; | ||
784 | axis = llVecNorm(axis); | ||
785 | double x, y, z, s, t; | ||
786 | s = Math.Cos(theta); | ||
787 | t = Math.Sin(theta); | ||
788 | x = axis.x * t; | ||
789 | y = axis.y * t; | ||
790 | z = axis.z * t; | ||
791 | return new LSL_Rotation(x,y,z,s); | ||
792 | } | ||
793 | } | ||
794 | |||
726 | public void llWhisper(int channelID, string text) | 795 | public void llWhisper(int channelID, string text) |
727 | { | 796 | { |
728 | m_host.AddScriptLPS(1); | 797 | m_host.AddScriptLPS(1); |
@@ -1121,7 +1190,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1121 | } | 1190 | } |
1122 | 1191 | ||
1123 | public void llSetStatus(int status, int value) | 1192 | public void llSetStatus(int status, int value) |
1124 | { | 1193 | { |
1194 | if (m_host == null || m_host.ParentGroup == null || m_host.ParentGroup.IsDeleted) | ||
1195 | return; | ||
1125 | m_host.AddScriptLPS(1); | 1196 | m_host.AddScriptLPS(1); |
1126 | 1197 | ||
1127 | int statusrotationaxis = 0; | 1198 | int statusrotationaxis = 0; |
@@ -1275,7 +1346,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1275 | } | 1346 | } |
1276 | 1347 | ||
1277 | protected void SetScale(SceneObjectPart part, LSL_Vector scale) | 1348 | protected void SetScale(SceneObjectPart part, LSL_Vector scale) |
1278 | { | 1349 | { |
1279 | // TODO: this needs to trigger a persistance save as well | 1350 | // TODO: this needs to trigger a persistance save as well |
1280 | if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) | 1351 | if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) |
1281 | return; | 1352 | return; |
@@ -1334,7 +1405,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1334 | } | 1405 | } |
1335 | 1406 | ||
1336 | protected void SetColor(SceneObjectPart part, LSL_Vector color, int face) | 1407 | protected void SetColor(SceneObjectPart part, LSL_Vector color, int face) |
1337 | { | 1408 | { |
1409 | if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) | ||
1410 | return; | ||
1411 | |||
1338 | Primitive.TextureEntry tex = part.Shape.Textures; | 1412 | Primitive.TextureEntry tex = part.Shape.Textures; |
1339 | Color4 texcolor; | 1413 | Color4 texcolor; |
1340 | if (face >= 0 && face < GetNumberOfSides(part)) | 1414 | if (face >= 0 && face < GetNumberOfSides(part)) |
@@ -1371,7 +1445,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1371 | } | 1445 | } |
1372 | 1446 | ||
1373 | public void SetTexGen(SceneObjectPart part, int face,int style) | 1447 | public void SetTexGen(SceneObjectPart part, int face,int style) |
1374 | { | 1448 | { |
1449 | if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) | ||
1450 | return; | ||
1451 | |||
1375 | Primitive.TextureEntry tex = part.Shape.Textures; | 1452 | Primitive.TextureEntry tex = part.Shape.Textures; |
1376 | MappingType textype; | 1453 | MappingType textype; |
1377 | textype = MappingType.Default; | 1454 | textype = MappingType.Default; |
@@ -1401,7 +1478,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1401 | } | 1478 | } |
1402 | 1479 | ||
1403 | public void SetGlow(SceneObjectPart part, int face, float glow) | 1480 | public void SetGlow(SceneObjectPart part, int face, float glow) |
1404 | { | 1481 | { |
1482 | if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) | ||
1483 | return; | ||
1484 | |||
1405 | Primitive.TextureEntry tex = part.Shape.Textures; | 1485 | Primitive.TextureEntry tex = part.Shape.Textures; |
1406 | if (face >= 0 && face < GetNumberOfSides(part)) | 1486 | if (face >= 0 && face < GetNumberOfSides(part)) |
1407 | { | 1487 | { |
@@ -1426,7 +1506,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1426 | } | 1506 | } |
1427 | 1507 | ||
1428 | public void SetShiny(SceneObjectPart part, int face, int shiny, Bumpiness bump) | 1508 | public void SetShiny(SceneObjectPart part, int face, int shiny, Bumpiness bump) |
1429 | { | 1509 | { |
1510 | if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) | ||
1511 | return; | ||
1430 | 1512 | ||
1431 | Shininess sval = new Shininess(); | 1513 | Shininess sval = new Shininess(); |
1432 | 1514 | ||
@@ -1476,7 +1558,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1476 | } | 1558 | } |
1477 | 1559 | ||
1478 | public void SetFullBright(SceneObjectPart part, int face, bool bright) | 1560 | public void SetFullBright(SceneObjectPart part, int face, bool bright) |
1479 | { | 1561 | { |
1562 | if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) | ||
1563 | return; | ||
1564 | |||
1480 | Primitive.TextureEntry tex = part.Shape.Textures; | 1565 | Primitive.TextureEntry tex = part.Shape.Textures; |
1481 | if (face >= 0 && face < GetNumberOfSides(part)) | 1566 | if (face >= 0 && face < GetNumberOfSides(part)) |
1482 | { | 1567 | { |
@@ -1543,7 +1628,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1543 | } | 1628 | } |
1544 | 1629 | ||
1545 | protected void SetAlpha(SceneObjectPart part, double alpha, int face) | 1630 | protected void SetAlpha(SceneObjectPart part, double alpha, int face) |
1546 | { | 1631 | { |
1632 | if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) | ||
1633 | return; | ||
1634 | |||
1547 | Primitive.TextureEntry tex = part.Shape.Textures; | 1635 | Primitive.TextureEntry tex = part.Shape.Textures; |
1548 | Color4 texcolor; | 1636 | Color4 texcolor; |
1549 | if (face >= 0 && face < GetNumberOfSides(part)) | 1637 | if (face >= 0 && face < GetNumberOfSides(part)) |
@@ -1588,8 +1676,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1588 | /// <param name="Force"></param> | 1676 | /// <param name="Force"></param> |
1589 | protected void SetFlexi(SceneObjectPart part, bool flexi, int softness, float gravity, float friction, | 1677 | protected void SetFlexi(SceneObjectPart part, bool flexi, int softness, float gravity, float friction, |
1590 | float wind, float tension, LSL_Vector Force) | 1678 | float wind, float tension, LSL_Vector Force) |
1591 | { | 1679 | { |
1592 | if (part == null) | 1680 | if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) |
1593 | return; | 1681 | return; |
1594 | 1682 | ||
1595 | if (flexi) | 1683 | if (flexi) |
@@ -1623,8 +1711,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1623 | /// <param name="radius"></param> | 1711 | /// <param name="radius"></param> |
1624 | /// <param name="falloff"></param> | 1712 | /// <param name="falloff"></param> |
1625 | protected void SetPointLight(SceneObjectPart part, bool light, LSL_Vector color, float intensity, float radius, float falloff) | 1713 | protected void SetPointLight(SceneObjectPart part, bool light, LSL_Vector color, float intensity, float radius, float falloff) |
1626 | { | 1714 | { |
1627 | if (part == null) | 1715 | if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) |
1628 | return; | 1716 | return; |
1629 | 1717 | ||
1630 | if (light) | 1718 | if (light) |
@@ -1709,7 +1797,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1709 | } | 1797 | } |
1710 | 1798 | ||
1711 | protected void SetTexture(SceneObjectPart part, string texture, int face) | 1799 | protected void SetTexture(SceneObjectPart part, string texture, int face) |
1712 | { | 1800 | { |
1801 | if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) | ||
1802 | return; | ||
1803 | |||
1713 | UUID textureID=new UUID(); | 1804 | UUID textureID=new UUID(); |
1714 | 1805 | ||
1715 | if (!UUID.TryParse(texture, out textureID)) | 1806 | if (!UUID.TryParse(texture, out textureID)) |
@@ -1754,7 +1845,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1754 | } | 1845 | } |
1755 | 1846 | ||
1756 | protected void ScaleTexture(SceneObjectPart part, double u, double v, int face) | 1847 | protected void ScaleTexture(SceneObjectPart part, double u, double v, int face) |
1757 | { | 1848 | { |
1849 | if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) | ||
1850 | return; | ||
1851 | |||
1758 | Primitive.TextureEntry tex = part.Shape.Textures; | 1852 | Primitive.TextureEntry tex = part.Shape.Textures; |
1759 | if (face >= 0 && face < GetNumberOfSides(part)) | 1853 | if (face >= 0 && face < GetNumberOfSides(part)) |
1760 | { | 1854 | { |
@@ -1790,7 +1884,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1790 | } | 1884 | } |
1791 | 1885 | ||
1792 | protected void OffsetTexture(SceneObjectPart part, double u, double v, int face) | 1886 | protected void OffsetTexture(SceneObjectPart part, double u, double v, int face) |
1793 | { | 1887 | { |
1888 | if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) | ||
1889 | return; | ||
1890 | |||
1794 | Primitive.TextureEntry tex = part.Shape.Textures; | 1891 | Primitive.TextureEntry tex = part.Shape.Textures; |
1795 | if (face >= 0 && face < GetNumberOfSides(part)) | 1892 | if (face >= 0 && face < GetNumberOfSides(part)) |
1796 | { | 1893 | { |
@@ -1826,7 +1923,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1826 | } | 1923 | } |
1827 | 1924 | ||
1828 | protected void RotateTexture(SceneObjectPart part, double rotation, int face) | 1925 | protected void RotateTexture(SceneObjectPart part, double rotation, int face) |
1829 | { | 1926 | { |
1927 | if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) | ||
1928 | return; | ||
1929 | |||
1830 | Primitive.TextureEntry tex = part.Shape.Textures; | 1930 | Primitive.TextureEntry tex = part.Shape.Textures; |
1831 | if (face >= 0 && face < GetNumberOfSides(part)) | 1931 | if (face >= 0 && face < GetNumberOfSides(part)) |
1832 | { | 1932 | { |
@@ -1896,7 +1996,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1896 | } | 1996 | } |
1897 | 1997 | ||
1898 | protected void SetPos(SceneObjectPart part, LSL_Vector targetPos) | 1998 | protected void SetPos(SceneObjectPart part, LSL_Vector targetPos) |
1899 | { | 1999 | { |
2000 | if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) | ||
2001 | return; | ||
2002 | |||
1900 | // Capped movemment if distance > 10m (http://wiki.secondlife.com/wiki/LlSetPos) | 2003 | // Capped movemment if distance > 10m (http://wiki.secondlife.com/wiki/LlSetPos) |
1901 | LSL_Vector currentPos = llGetLocalPos(); | 2004 | LSL_Vector currentPos = llGetLocalPos(); |
1902 | 2005 | ||
@@ -1990,7 +2093,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1990 | } | 2093 | } |
1991 | 2094 | ||
1992 | protected void SetRot(SceneObjectPart part, Quaternion rot) | 2095 | protected void SetRot(SceneObjectPart part, Quaternion rot) |
1993 | { | 2096 | { |
2097 | if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) | ||
2098 | return; | ||
2099 | |||
1994 | part.UpdateRotation(rot); | 2100 | part.UpdateRotation(rot); |
1995 | // Update rotation does not move the object in the physics scene if it's a linkset. | 2101 | // Update rotation does not move the object in the physics scene if it's a linkset. |
1996 | 2102 | ||
@@ -2555,12 +2661,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2555 | 2661 | ||
2556 | m_host.AddScriptLPS(1); | 2662 | m_host.AddScriptLPS(1); |
2557 | 2663 | ||
2664 | m_host.TaskInventory.LockItemsForRead(true); | ||
2558 | TaskInventoryItem item = m_host.TaskInventory[invItemID]; | 2665 | TaskInventoryItem item = m_host.TaskInventory[invItemID]; |
2559 | 2666 | m_host.TaskInventory.LockItemsForRead(false); | |
2560 | lock (m_host.TaskInventory) | ||
2561 | { | ||
2562 | item = m_host.TaskInventory[invItemID]; | ||
2563 | } | ||
2564 | 2667 | ||
2565 | if (item.PermsGranter == UUID.Zero) | 2668 | if (item.PermsGranter == UUID.Zero) |
2566 | return 0; | 2669 | return 0; |
@@ -2635,6 +2738,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2635 | if (dist > m_ScriptDistanceFactor * 10.0f) | 2738 | if (dist > m_ScriptDistanceFactor * 10.0f) |
2636 | return; | 2739 | return; |
2637 | 2740 | ||
2741 | //Clone is thread-safe | ||
2638 | TaskInventoryDictionary partInventory = (TaskInventoryDictionary)m_host.TaskInventory.Clone(); | 2742 | TaskInventoryDictionary partInventory = (TaskInventoryDictionary)m_host.TaskInventory.Clone(); |
2639 | 2743 | ||
2640 | foreach (KeyValuePair<UUID, TaskInventoryItem> inv in partInventory) | 2744 | foreach (KeyValuePair<UUID, TaskInventoryItem> inv in partInventory) |
@@ -2720,6 +2824,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2720 | // Orient the object to the angle calculated | 2824 | // Orient the object to the angle calculated |
2721 | llSetRot(rot); | 2825 | llSetRot(rot); |
2722 | } | 2826 | } |
2827 | |||
2828 | public void llRotLookAt(LSL_Rotation target, double strength, double damping) | ||
2829 | { | ||
2830 | m_host.AddScriptLPS(1); | ||
2831 | // NotImplemented("llRotLookAt"); | ||
2832 | m_host.RotLookAt(Rot2Quaternion(target), (float)strength, (float)damping); | ||
2833 | |||
2834 | } | ||
2723 | 2835 | ||
2724 | public void llStopLookAt() | 2836 | public void llStopLookAt() |
2725 | { | 2837 | { |
@@ -2767,13 +2879,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2767 | { | 2879 | { |
2768 | TaskInventoryItem item; | 2880 | TaskInventoryItem item; |
2769 | 2881 | ||
2770 | lock (m_host.TaskInventory) | 2882 | m_host.TaskInventory.LockItemsForRead(true); |
2883 | if (!m_host.TaskInventory.ContainsKey(InventorySelf())) | ||
2771 | { | 2884 | { |
2772 | if (!m_host.TaskInventory.ContainsKey(InventorySelf())) | 2885 | m_host.TaskInventory.LockItemsForRead(false); |
2773 | return; | 2886 | return; |
2774 | else | ||
2775 | item = m_host.TaskInventory[InventorySelf()]; | ||
2776 | } | 2887 | } |
2888 | else | ||
2889 | { | ||
2890 | item = m_host.TaskInventory[InventorySelf()]; | ||
2891 | } | ||
2892 | m_host.TaskInventory.LockItemsForRead(false); | ||
2777 | 2893 | ||
2778 | if (item.PermsGranter != UUID.Zero) | 2894 | if (item.PermsGranter != UUID.Zero) |
2779 | { | 2895 | { |
@@ -2795,13 +2911,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2795 | { | 2911 | { |
2796 | TaskInventoryItem item; | 2912 | TaskInventoryItem item; |
2797 | 2913 | ||
2914 | m_host.TaskInventory.LockItemsForRead(true); | ||
2798 | lock (m_host.TaskInventory) | 2915 | lock (m_host.TaskInventory) |
2799 | { | 2916 | { |
2917 | |||
2800 | if (!m_host.TaskInventory.ContainsKey(InventorySelf())) | 2918 | if (!m_host.TaskInventory.ContainsKey(InventorySelf())) |
2919 | { | ||
2920 | m_host.TaskInventory.LockItemsForRead(false); | ||
2801 | return; | 2921 | return; |
2922 | } | ||
2802 | else | 2923 | else |
2924 | { | ||
2803 | item = m_host.TaskInventory[InventorySelf()]; | 2925 | item = m_host.TaskInventory[InventorySelf()]; |
2926 | } | ||
2804 | } | 2927 | } |
2928 | m_host.TaskInventory.LockItemsForRead(false); | ||
2805 | 2929 | ||
2806 | m_host.AddScriptLPS(1); | 2930 | m_host.AddScriptLPS(1); |
2807 | 2931 | ||
@@ -2838,13 +2962,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2838 | 2962 | ||
2839 | TaskInventoryItem item; | 2963 | TaskInventoryItem item; |
2840 | 2964 | ||
2841 | lock (m_host.TaskInventory) | 2965 | m_host.TaskInventory.LockItemsForRead(true); |
2966 | |||
2967 | if (!m_host.TaskInventory.ContainsKey(InventorySelf())) | ||
2842 | { | 2968 | { |
2843 | if (!m_host.TaskInventory.ContainsKey(InventorySelf())) | 2969 | m_host.TaskInventory.LockItemsForRead(false); |
2844 | return; | 2970 | return; |
2845 | else | ||
2846 | item = m_host.TaskInventory[InventorySelf()]; | ||
2847 | } | 2971 | } |
2972 | else | ||
2973 | { | ||
2974 | item = m_host.TaskInventory[InventorySelf()]; | ||
2975 | } | ||
2976 | |||
2977 | m_host.TaskInventory.LockItemsForRead(false); | ||
2848 | 2978 | ||
2849 | if (item.PermsGranter != m_host.OwnerID) | 2979 | if (item.PermsGranter != m_host.OwnerID) |
2850 | return; | 2980 | return; |
@@ -2870,13 +3000,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2870 | 3000 | ||
2871 | TaskInventoryItem item; | 3001 | TaskInventoryItem item; |
2872 | 3002 | ||
2873 | lock (m_host.TaskInventory) | 3003 | m_host.TaskInventory.LockItemsForRead(true); |
3004 | |||
3005 | if (!m_host.TaskInventory.ContainsKey(InventorySelf())) | ||
2874 | { | 3006 | { |
2875 | if (!m_host.TaskInventory.ContainsKey(InventorySelf())) | 3007 | m_host.TaskInventory.LockItemsForRead(false); |
2876 | return; | 3008 | return; |
2877 | else | ||
2878 | item = m_host.TaskInventory[InventorySelf()]; | ||
2879 | } | 3009 | } |
3010 | else | ||
3011 | { | ||
3012 | item = m_host.TaskInventory[InventorySelf()]; | ||
3013 | } | ||
3014 | m_host.TaskInventory.LockItemsForRead(false); | ||
3015 | |||
2880 | 3016 | ||
2881 | if (item.PermsGranter != m_host.OwnerID) | 3017 | if (item.PermsGranter != m_host.OwnerID) |
2882 | return; | 3018 | return; |
@@ -2912,8 +3048,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2912 | return m_host.OwnerID.ToString(); | 3048 | return m_host.OwnerID.ToString(); |
2913 | } | 3049 | } |
2914 | 3050 | ||
3051 | [DebuggerNonUserCode] | ||
2915 | public void llInstantMessage(string user, string message) | 3052 | public void llInstantMessage(string user, string message) |
2916 | { | 3053 | { |
3054 | UUID result; | ||
3055 | if (!UUID.TryParse(user, out result)) | ||
3056 | { | ||
3057 | throw new Exception(String.Format("An invalid key of '{0} was passed to llInstantMessage", user)); | ||
3058 | return; | ||
3059 | } | ||
3060 | |||
3061 | |||
2917 | m_host.AddScriptLPS(1); | 3062 | m_host.AddScriptLPS(1); |
2918 | 3063 | ||
2919 | // We may be able to use ClientView.SendInstantMessage here, but we need a client instance. | 3064 | // We may be able to use ClientView.SendInstantMessage here, but we need a client instance. |
@@ -2928,7 +3073,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2928 | UUID friendTransactionID = UUID.Random(); | 3073 | UUID friendTransactionID = UUID.Random(); |
2929 | 3074 | ||
2930 | //m_pendingFriendRequests.Add(friendTransactionID, fromAgentID); | 3075 | //m_pendingFriendRequests.Add(friendTransactionID, fromAgentID); |
2931 | 3076 | ||
2932 | GridInstantMessage msg = new GridInstantMessage(); | 3077 | GridInstantMessage msg = new GridInstantMessage(); |
2933 | msg.fromAgentID = new Guid(m_host.UUID.ToString()); // fromAgentID.Guid; | 3078 | msg.fromAgentID = new Guid(m_host.UUID.ToString()); // fromAgentID.Guid; |
2934 | msg.toAgentID = new Guid(user); // toAgentID.Guid; | 3079 | msg.toAgentID = new Guid(user); // toAgentID.Guid; |
@@ -3077,13 +3222,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
3077 | m_host.AddScriptLPS(1); | 3222 | m_host.AddScriptLPS(1); |
3078 | } | 3223 | } |
3079 | 3224 | ||
3080 | public void llRotLookAt(LSL_Rotation target, double strength, double damping) | ||
3081 | { | ||
3082 | m_host.AddScriptLPS(1); | ||
3083 | // NotImplemented("llRotLookAt"); | ||
3084 | m_host.RotLookAt(Rot2Quaternion(target), (float)strength, (float)damping); | ||
3085 | } | ||
3086 | |||
3087 | public LSL_Integer llStringLength(string str) | 3225 | public LSL_Integer llStringLength(string str) |
3088 | { | 3226 | { |
3089 | m_host.AddScriptLPS(1); | 3227 | m_host.AddScriptLPS(1); |
@@ -3107,14 +3245,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
3107 | 3245 | ||
3108 | TaskInventoryItem item; | 3246 | TaskInventoryItem item; |
3109 | 3247 | ||
3110 | lock (m_host.TaskInventory) | 3248 | m_host.TaskInventory.LockItemsForRead(true); |
3249 | if (!m_host.TaskInventory.ContainsKey(InventorySelf())) | ||
3111 | { | 3250 | { |
3112 | if (!m_host.TaskInventory.ContainsKey(InventorySelf())) | 3251 | m_host.TaskInventory.LockItemsForRead(false); |
3113 | return; | 3252 | return; |
3114 | else | ||
3115 | item = m_host.TaskInventory[InventorySelf()]; | ||
3116 | } | 3253 | } |
3117 | 3254 | else | |
3255 | { | ||
3256 | item = m_host.TaskInventory[InventorySelf()]; | ||
3257 | } | ||
3258 | m_host.TaskInventory.LockItemsForRead(false); | ||
3118 | if (item.PermsGranter == UUID.Zero) | 3259 | if (item.PermsGranter == UUID.Zero) |
3119 | return; | 3260 | return; |
3120 | 3261 | ||
@@ -3144,13 +3285,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
3144 | 3285 | ||
3145 | TaskInventoryItem item; | 3286 | TaskInventoryItem item; |
3146 | 3287 | ||
3147 | lock (m_host.TaskInventory) | 3288 | m_host.TaskInventory.LockItemsForRead(true); |
3289 | if (!m_host.TaskInventory.ContainsKey(InventorySelf())) | ||
3148 | { | 3290 | { |
3149 | if (!m_host.TaskInventory.ContainsKey(InventorySelf())) | 3291 | m_host.TaskInventory.LockItemsForRead(false); |
3150 | return; | 3292 | return; |
3151 | else | 3293 | } |
3152 | item = m_host.TaskInventory[InventorySelf()]; | 3294 | else |
3295 | { | ||
3296 | item = m_host.TaskInventory[InventorySelf()]; | ||
3153 | } | 3297 | } |
3298 | m_host.TaskInventory.LockItemsForRead(false); | ||
3299 | |||
3154 | 3300 | ||
3155 | if (item.PermsGranter == UUID.Zero) | 3301 | if (item.PermsGranter == UUID.Zero) |
3156 | return; | 3302 | return; |
@@ -3223,10 +3369,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
3223 | 3369 | ||
3224 | TaskInventoryItem item; | 3370 | TaskInventoryItem item; |
3225 | 3371 | ||
3226 | lock (m_host.TaskInventory) | 3372 | |
3373 | m_host.TaskInventory.LockItemsForRead(true); | ||
3374 | if (!m_host.TaskInventory.ContainsKey(invItemID)) | ||
3375 | { | ||
3376 | m_host.TaskInventory.LockItemsForRead(false); | ||
3377 | return; | ||
3378 | } | ||
3379 | else | ||
3227 | { | 3380 | { |
3228 | item = m_host.TaskInventory[invItemID]; | 3381 | item = m_host.TaskInventory[invItemID]; |
3229 | } | 3382 | } |
3383 | m_host.TaskInventory.LockItemsForRead(false); | ||
3230 | 3384 | ||
3231 | if (agentID == UUID.Zero || perm == 0) // Releasing permissions | 3385 | if (agentID == UUID.Zero || perm == 0) // Releasing permissions |
3232 | { | 3386 | { |
@@ -3258,11 +3412,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
3258 | 3412 | ||
3259 | if ((perm & (~implicitPerms)) == 0) // Requested only implicit perms | 3413 | if ((perm & (~implicitPerms)) == 0) // Requested only implicit perms |
3260 | { | 3414 | { |
3261 | lock (m_host.TaskInventory) | 3415 | m_host.TaskInventory.LockItemsForWrite(true); |
3262 | { | 3416 | m_host.TaskInventory[invItemID].PermsGranter = agentID; |
3263 | m_host.TaskInventory[invItemID].PermsGranter = agentID; | 3417 | m_host.TaskInventory[invItemID].PermsMask = perm; |
3264 | m_host.TaskInventory[invItemID].PermsMask = perm; | 3418 | m_host.TaskInventory.LockItemsForWrite(false); |
3265 | } | ||
3266 | 3419 | ||
3267 | m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams( | 3420 | m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams( |
3268 | "run_time_permissions", new Object[] { | 3421 | "run_time_permissions", new Object[] { |
@@ -3282,11 +3435,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
3282 | 3435 | ||
3283 | if ((perm & (~implicitPerms)) == 0) // Requested only implicit perms | 3436 | if ((perm & (~implicitPerms)) == 0) // Requested only implicit perms |
3284 | { | 3437 | { |
3285 | lock (m_host.TaskInventory) | 3438 | m_host.TaskInventory.LockItemsForWrite(true); |
3286 | { | 3439 | m_host.TaskInventory[invItemID].PermsGranter = agentID; |
3287 | m_host.TaskInventory[invItemID].PermsGranter = agentID; | 3440 | m_host.TaskInventory[invItemID].PermsMask = perm; |
3288 | m_host.TaskInventory[invItemID].PermsMask = perm; | 3441 | m_host.TaskInventory.LockItemsForWrite(false); |
3289 | } | ||
3290 | 3442 | ||
3291 | m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams( | 3443 | m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams( |
3292 | "run_time_permissions", new Object[] { | 3444 | "run_time_permissions", new Object[] { |
@@ -3307,11 +3459,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
3307 | 3459 | ||
3308 | if (!m_waitingForScriptAnswer) | 3460 | if (!m_waitingForScriptAnswer) |
3309 | { | 3461 | { |
3310 | lock (m_host.TaskInventory) | 3462 | m_host.TaskInventory.LockItemsForWrite(true); |
3311 | { | 3463 | m_host.TaskInventory[invItemID].PermsGranter = agentID; |
3312 | m_host.TaskInventory[invItemID].PermsGranter = agentID; | 3464 | m_host.TaskInventory[invItemID].PermsMask = 0; |
3313 | m_host.TaskInventory[invItemID].PermsMask = 0; | 3465 | m_host.TaskInventory.LockItemsForWrite(false); |
3314 | } | ||
3315 | 3466 | ||
3316 | presence.ControllingClient.OnScriptAnswer += handleScriptAnswer; | 3467 | presence.ControllingClient.OnScriptAnswer += handleScriptAnswer; |
3317 | m_waitingForScriptAnswer=true; | 3468 | m_waitingForScriptAnswer=true; |
@@ -3346,10 +3497,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
3346 | if ((answer & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) == 0) | 3497 | if ((answer & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) == 0) |
3347 | llReleaseControls(); | 3498 | llReleaseControls(); |
3348 | 3499 | ||
3349 | lock (m_host.TaskInventory) | 3500 | |
3350 | { | 3501 | m_host.TaskInventory.LockItemsForWrite(true); |
3351 | m_host.TaskInventory[invItemID].PermsMask = answer; | 3502 | m_host.TaskInventory[invItemID].PermsMask = answer; |
3352 | } | 3503 | m_host.TaskInventory.LockItemsForWrite(false); |
3504 | |||
3353 | 3505 | ||
3354 | m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams( | 3506 | m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams( |
3355 | "run_time_permissions", new Object[] { | 3507 | "run_time_permissions", new Object[] { |
@@ -3361,16 +3513,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
3361 | { | 3513 | { |
3362 | m_host.AddScriptLPS(1); | 3514 | m_host.AddScriptLPS(1); |
3363 | 3515 | ||
3364 | lock (m_host.TaskInventory) | 3516 | m_host.TaskInventory.LockItemsForRead(true); |
3517 | |||
3518 | foreach (TaskInventoryItem item in m_host.TaskInventory.Values) | ||
3365 | { | 3519 | { |
3366 | foreach (TaskInventoryItem item in m_host.TaskInventory.Values) | 3520 | if (item.Type == 10 && item.ItemID == m_itemID) |
3367 | { | 3521 | { |
3368 | if (item.Type == 10 && item.ItemID == m_itemID) | 3522 | m_host.TaskInventory.LockItemsForRead(false); |
3369 | { | 3523 | return item.PermsGranter.ToString(); |
3370 | return item.PermsGranter.ToString(); | ||
3371 | } | ||
3372 | } | 3524 | } |
3373 | } | 3525 | } |
3526 | m_host.TaskInventory.LockItemsForRead(false); | ||
3374 | 3527 | ||
3375 | return UUID.Zero.ToString(); | 3528 | return UUID.Zero.ToString(); |
3376 | } | 3529 | } |
@@ -3379,19 +3532,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
3379 | { | 3532 | { |
3380 | m_host.AddScriptLPS(1); | 3533 | m_host.AddScriptLPS(1); |
3381 | 3534 | ||
3382 | lock (m_host.TaskInventory) | 3535 | m_host.TaskInventory.LockItemsForRead(true); |
3536 | |||
3537 | foreach (TaskInventoryItem item in m_host.TaskInventory.Values) | ||
3383 | { | 3538 | { |
3384 | foreach (TaskInventoryItem item in m_host.TaskInventory.Values) | 3539 | if (item.Type == 10 && item.ItemID == m_itemID) |
3385 | { | 3540 | { |
3386 | if (item.Type == 10 && item.ItemID == m_itemID) | 3541 | int perms = item.PermsMask; |
3387 | { | 3542 | if (m_automaticLinkPermission) |
3388 | int perms = item.PermsMask; | 3543 | perms |= ScriptBaseClass.PERMISSION_CHANGE_LINKS; |
3389 | if (m_automaticLinkPermission) | 3544 | m_host.TaskInventory.LockItemsForRead(false); |
3390 | perms |= ScriptBaseClass.PERMISSION_CHANGE_LINKS; | 3545 | return perms; |
3391 | return perms; | ||
3392 | } | ||
3393 | } | 3546 | } |
3394 | } | 3547 | } |
3548 | m_host.TaskInventory.LockItemsForRead(false); | ||
3395 | 3549 | ||
3396 | return 0; | 3550 | return 0; |
3397 | } | 3551 | } |
@@ -3424,11 +3578,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
3424 | UUID invItemID = InventorySelf(); | 3578 | UUID invItemID = InventorySelf(); |
3425 | 3579 | ||
3426 | TaskInventoryItem item; | 3580 | TaskInventoryItem item; |
3427 | lock (m_host.TaskInventory) | 3581 | m_host.TaskInventory.LockItemsForRead(true); |
3428 | { | 3582 | item = m_host.TaskInventory[invItemID]; |
3429 | item = m_host.TaskInventory[invItemID]; | 3583 | m_host.TaskInventory.LockItemsForRead(false); |
3430 | } | 3584 | |
3431 | |||
3432 | if ((item.PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0 | 3585 | if ((item.PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0 |
3433 | && !m_automaticLinkPermission) | 3586 | && !m_automaticLinkPermission) |
3434 | { | 3587 | { |
@@ -3481,16 +3634,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
3481 | m_host.AddScriptLPS(1); | 3634 | m_host.AddScriptLPS(1); |
3482 | UUID invItemID = InventorySelf(); | 3635 | UUID invItemID = InventorySelf(); |
3483 | 3636 | ||
3484 | lock (m_host.TaskInventory) | 3637 | m_host.TaskInventory.LockItemsForRead(true); |
3485 | { | ||
3486 | if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0 | 3638 | if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0 |
3487 | && !m_automaticLinkPermission) | 3639 | && !m_automaticLinkPermission) |
3488 | { | 3640 | { |
3489 | ShoutError("Script trying to link but PERMISSION_CHANGE_LINKS permission not set!"); | 3641 | ShoutError("Script trying to link but PERMISSION_CHANGE_LINKS permission not set!"); |
3642 | m_host.TaskInventory.LockItemsForRead(false); | ||
3490 | return; | 3643 | return; |
3491 | } | 3644 | } |
3492 | } | 3645 | m_host.TaskInventory.LockItemsForRead(false); |
3493 | 3646 | ||
3494 | if (linknum < ScriptBaseClass.LINK_THIS) | 3647 | if (linknum < ScriptBaseClass.LINK_THIS) |
3495 | return; | 3648 | return; |
3496 | 3649 | ||
@@ -3667,17 +3820,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
3667 | m_host.AddScriptLPS(1); | 3820 | m_host.AddScriptLPS(1); |
3668 | int count = 0; | 3821 | int count = 0; |
3669 | 3822 | ||
3670 | lock (m_host.TaskInventory) | 3823 | m_host.TaskInventory.LockItemsForRead(true); |
3824 | foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) | ||
3671 | { | 3825 | { |
3672 | foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) | 3826 | if (inv.Value.Type == type || type == -1) |
3673 | { | 3827 | { |
3674 | if (inv.Value.Type == type || type == -1) | 3828 | count = count + 1; |
3675 | { | ||
3676 | count = count + 1; | ||
3677 | } | ||
3678 | } | 3829 | } |
3679 | } | 3830 | } |
3680 | 3831 | ||
3832 | m_host.TaskInventory.LockItemsForRead(false); | ||
3681 | return count; | 3833 | return count; |
3682 | } | 3834 | } |
3683 | 3835 | ||
@@ -3686,16 +3838,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
3686 | m_host.AddScriptLPS(1); | 3838 | m_host.AddScriptLPS(1); |
3687 | ArrayList keys = new ArrayList(); | 3839 | ArrayList keys = new ArrayList(); |
3688 | 3840 | ||
3689 | lock (m_host.TaskInventory) | 3841 | m_host.TaskInventory.LockItemsForRead(true); |
3842 | foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) | ||
3690 | { | 3843 | { |
3691 | foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) | 3844 | if (inv.Value.Type == type || type == -1) |
3692 | { | 3845 | { |
3693 | if (inv.Value.Type == type || type == -1) | 3846 | keys.Add(inv.Value.Name); |
3694 | { | ||
3695 | keys.Add(inv.Value.Name); | ||
3696 | } | ||
3697 | } | 3847 | } |
3698 | } | 3848 | } |
3849 | m_host.TaskInventory.LockItemsForRead(false); | ||
3699 | 3850 | ||
3700 | if (keys.Count == 0) | 3851 | if (keys.Count == 0) |
3701 | { | 3852 | { |
@@ -3732,20 +3883,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
3732 | } | 3883 | } |
3733 | 3884 | ||
3734 | // move the first object found with this inventory name | 3885 | // move the first object found with this inventory name |
3735 | lock (m_host.TaskInventory) | 3886 | m_host.TaskInventory.LockItemsForRead(true); |
3887 | foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) | ||
3736 | { | 3888 | { |
3737 | foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) | 3889 | if (inv.Value.Name == inventory) |
3738 | { | 3890 | { |
3739 | if (inv.Value.Name == inventory) | 3891 | found = true; |
3740 | { | 3892 | objId = inv.Key; |
3741 | found = true; | 3893 | assetType = inv.Value.Type; |
3742 | objId = inv.Key; | 3894 | objName = inv.Value.Name; |
3743 | assetType = inv.Value.Type; | 3895 | break; |
3744 | objName = inv.Value.Name; | ||
3745 | break; | ||
3746 | } | ||
3747 | } | 3896 | } |
3748 | } | 3897 | } |
3898 | m_host.TaskInventory.LockItemsForRead(false); | ||
3749 | 3899 | ||
3750 | if (!found) | 3900 | if (!found) |
3751 | { | 3901 | { |
@@ -3790,24 +3940,26 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
3790 | ScriptSleep(3000); | 3940 | ScriptSleep(3000); |
3791 | } | 3941 | } |
3792 | 3942 | ||
3943 | [DebuggerNonUserCode] | ||
3793 | public void llRemoveInventory(string name) | 3944 | public void llRemoveInventory(string name) |
3794 | { | 3945 | { |
3795 | m_host.AddScriptLPS(1); | 3946 | m_host.AddScriptLPS(1); |
3796 | 3947 | ||
3797 | lock (m_host.TaskInventory) | 3948 | m_host.TaskInventory.LockItemsForRead(true); |
3949 | foreach (TaskInventoryItem item in m_host.TaskInventory.Values) | ||
3798 | { | 3950 | { |
3799 | foreach (TaskInventoryItem item in m_host.TaskInventory.Values) | 3951 | if (item.Name == name) |
3800 | { | 3952 | { |
3801 | if (item.Name == name) | 3953 | if (item.ItemID == m_itemID) |
3802 | { | 3954 | throw new ScriptDeleteException(); |
3803 | if (item.ItemID == m_itemID) | 3955 | else |
3804 | throw new ScriptDeleteException(); | 3956 | m_host.Inventory.RemoveInventoryItem(item.ItemID); |
3805 | else | 3957 | |
3806 | m_host.Inventory.RemoveInventoryItem(item.ItemID); | 3958 | m_host.TaskInventory.LockItemsForRead(false); |
3807 | return; | 3959 | return; |
3808 | } | ||
3809 | } | 3960 | } |
3810 | } | 3961 | } |
3962 | m_host.TaskInventory.LockItemsForRead(false); | ||
3811 | } | 3963 | } |
3812 | 3964 | ||
3813 | public void llSetText(string text, LSL_Vector color, double alpha) | 3965 | public void llSetText(string text, LSL_Vector color, double alpha) |
@@ -3897,6 +4049,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
3897 | { | 4049 | { |
3898 | m_host.AddScriptLPS(1); | 4050 | m_host.AddScriptLPS(1); |
3899 | 4051 | ||
4052 | //Clone is thread safe | ||
3900 | TaskInventoryDictionary itemDictionary = (TaskInventoryDictionary)m_host.TaskInventory.Clone(); | 4053 | TaskInventoryDictionary itemDictionary = (TaskInventoryDictionary)m_host.TaskInventory.Clone(); |
3901 | 4054 | ||
3902 | foreach (TaskInventoryItem item in itemDictionary.Values) | 4055 | foreach (TaskInventoryItem item in itemDictionary.Values) |
@@ -3987,17 +4140,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
3987 | UUID soundId = UUID.Zero; | 4140 | UUID soundId = UUID.Zero; |
3988 | if (!UUID.TryParse(impact_sound, out soundId)) | 4141 | if (!UUID.TryParse(impact_sound, out soundId)) |
3989 | { | 4142 | { |
3990 | lock (m_host.TaskInventory) | 4143 | m_host.TaskInventory.LockItemsForRead(true); |
4144 | foreach (TaskInventoryItem item in m_host.TaskInventory.Values) | ||
3991 | { | 4145 | { |
3992 | foreach (TaskInventoryItem item in m_host.TaskInventory.Values) | 4146 | if (item.Type == (int)AssetType.Sound && item.Name == impact_sound) |
3993 | { | 4147 | { |
3994 | if (item.Type == (int)AssetType.Sound && item.Name == impact_sound) | 4148 | soundId = item.AssetID; |
3995 | { | 4149 | break; |
3996 | soundId = item.AssetID; | ||
3997 | break; | ||
3998 | } | ||
3999 | } | 4150 | } |
4000 | } | 4151 | } |
4152 | m_host.TaskInventory.LockItemsForRead(false); | ||
4001 | } | 4153 | } |
4002 | m_host.CollisionSound = soundId; | 4154 | m_host.CollisionSound = soundId; |
4003 | m_host.CollisionSoundVolume = (float)impact_volume; | 4155 | m_host.CollisionSoundVolume = (float)impact_volume; |
@@ -4043,6 +4195,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
4043 | UUID partItemID; | 4195 | UUID partItemID; |
4044 | foreach (SceneObjectPart part in parts) | 4196 | foreach (SceneObjectPart part in parts) |
4045 | { | 4197 | { |
4198 | //Clone is thread safe | ||
4046 | TaskInventoryDictionary itemsDictionary = (TaskInventoryDictionary)part.TaskInventory.Clone(); | 4199 | TaskInventoryDictionary itemsDictionary = (TaskInventoryDictionary)part.TaskInventory.Clone(); |
4047 | 4200 | ||
4048 | foreach (TaskInventoryItem item in itemsDictionary.Values) | 4201 | foreach (TaskInventoryItem item in itemsDictionary.Values) |
@@ -4257,17 +4410,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
4257 | 4410 | ||
4258 | m_host.AddScriptLPS(1); | 4411 | m_host.AddScriptLPS(1); |
4259 | 4412 | ||
4260 | lock (m_host.TaskInventory) | 4413 | m_host.TaskInventory.LockItemsForRead(true); |
4414 | foreach (TaskInventoryItem item in m_host.TaskInventory.Values) | ||
4261 | { | 4415 | { |
4262 | foreach (TaskInventoryItem item in m_host.TaskInventory.Values) | 4416 | if (item.Type == 10 && item.ItemID == m_itemID) |
4263 | { | 4417 | { |
4264 | if (item.Type == 10 && item.ItemID == m_itemID) | 4418 | result = item.Name!=null?item.Name:String.Empty; |
4265 | { | 4419 | break; |
4266 | result = item.Name!=null?item.Name:String.Empty; | ||
4267 | break; | ||
4268 | } | ||
4269 | } | 4420 | } |
4270 | } | 4421 | } |
4422 | m_host.TaskInventory.LockItemsForRead(false); | ||
4271 | 4423 | ||
4272 | return result; | 4424 | return result; |
4273 | } | 4425 | } |
@@ -4525,23 +4677,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
4525 | { | 4677 | { |
4526 | m_host.AddScriptLPS(1); | 4678 | m_host.AddScriptLPS(1); |
4527 | 4679 | ||
4528 | lock (m_host.TaskInventory) | 4680 | m_host.TaskInventory.LockItemsForRead(true); |
4681 | foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) | ||
4529 | { | 4682 | { |
4530 | foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) | 4683 | if (inv.Value.Name == name) |
4531 | { | 4684 | { |
4532 | if (inv.Value.Name == name) | 4685 | if ((inv.Value.CurrentPermissions & (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify)) == (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify)) |
4533 | { | 4686 | { |
4534 | if ((inv.Value.CurrentPermissions & (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify)) == (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify)) | 4687 | m_host.TaskInventory.LockItemsForRead(false); |
4535 | { | 4688 | return inv.Value.AssetID.ToString(); |
4536 | return inv.Value.AssetID.ToString(); | 4689 | } |
4537 | } | 4690 | else |
4538 | else | 4691 | { |
4539 | { | 4692 | m_host.TaskInventory.LockItemsForRead(false); |
4540 | return UUID.Zero.ToString(); | 4693 | return UUID.Zero.ToString(); |
4541 | } | ||
4542 | } | 4694 | } |
4543 | } | 4695 | } |
4544 | } | 4696 | } |
4697 | m_host.TaskInventory.LockItemsForRead(false); | ||
4545 | 4698 | ||
4546 | return UUID.Zero.ToString(); | 4699 | return UUID.Zero.ToString(); |
4547 | } | 4700 | } |
@@ -6037,14 +6190,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
6037 | 6190 | ||
6038 | protected UUID GetTaskInventoryItem(string name) | 6191 | protected UUID GetTaskInventoryItem(string name) |
6039 | { | 6192 | { |
6040 | lock (m_host.TaskInventory) | 6193 | m_host.TaskInventory.LockItemsForRead(true); |
6194 | foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) | ||
6041 | { | 6195 | { |
6042 | foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) | 6196 | if (inv.Value.Name == name) |
6043 | { | 6197 | { |
6044 | if (inv.Value.Name == name) | 6198 | m_host.TaskInventory.LockItemsForRead(false); |
6045 | return inv.Key; | 6199 | return inv.Key; |
6046 | } | 6200 | } |
6047 | } | 6201 | } |
6202 | m_host.TaskInventory.LockItemsForRead(false); | ||
6048 | 6203 | ||
6049 | return UUID.Zero; | 6204 | return UUID.Zero; |
6050 | } | 6205 | } |
@@ -6360,22 +6515,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
6360 | } | 6515 | } |
6361 | 6516 | ||
6362 | // copy the first script found with this inventory name | 6517 | // copy the first script found with this inventory name |
6363 | lock (m_host.TaskInventory) | 6518 | m_host.TaskInventory.LockItemsForRead(true); |
6519 | foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) | ||
6364 | { | 6520 | { |
6365 | foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) | 6521 | if (inv.Value.Name == name) |
6366 | { | 6522 | { |
6367 | if (inv.Value.Name == name) | 6523 | // make sure the object is a script |
6524 | if (10 == inv.Value.Type) | ||
6368 | { | 6525 | { |
6369 | // make sure the object is a script | 6526 | found = true; |
6370 | if (10 == inv.Value.Type) | 6527 | srcId = inv.Key; |
6371 | { | 6528 | break; |
6372 | found = true; | ||
6373 | srcId = inv.Key; | ||
6374 | break; | ||
6375 | } | ||
6376 | } | 6529 | } |
6377 | } | 6530 | } |
6378 | } | 6531 | } |
6532 | m_host.TaskInventory.LockItemsForRead(false); | ||
6379 | 6533 | ||
6380 | if (!found) | 6534 | if (!found) |
6381 | { | 6535 | { |
@@ -6457,8 +6611,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
6457 | } | 6611 | } |
6458 | 6612 | ||
6459 | protected ObjectShapePacket.ObjectDataBlock SetPrimitiveBlockShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist) | 6613 | protected ObjectShapePacket.ObjectDataBlock SetPrimitiveBlockShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist) |
6460 | { | 6614 | { |
6461 | ObjectShapePacket.ObjectDataBlock shapeBlock = new ObjectShapePacket.ObjectDataBlock(); | 6615 | ObjectShapePacket.ObjectDataBlock shapeBlock = new ObjectShapePacket.ObjectDataBlock(); |
6616 | if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) | ||
6617 | return shapeBlock; | ||
6462 | 6618 | ||
6463 | if (holeshape != (int)ScriptBaseClass.PRIM_HOLE_DEFAULT && | 6619 | if (holeshape != (int)ScriptBaseClass.PRIM_HOLE_DEFAULT && |
6464 | holeshape != (int)ScriptBaseClass.PRIM_HOLE_CIRCLE && | 6620 | holeshape != (int)ScriptBaseClass.PRIM_HOLE_CIRCLE && |
@@ -6528,7 +6684,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
6528 | } | 6684 | } |
6529 | 6685 | ||
6530 | protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector taper_b, LSL_Vector topshear, byte fudge) | 6686 | protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector taper_b, LSL_Vector topshear, byte fudge) |
6531 | { | 6687 | { |
6688 | if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) | ||
6689 | return; | ||
6690 | |||
6532 | ObjectShapePacket.ObjectDataBlock shapeBlock; | 6691 | ObjectShapePacket.ObjectDataBlock shapeBlock; |
6533 | 6692 | ||
6534 | shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist); | 6693 | shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist); |
@@ -6577,7 +6736,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
6577 | } | 6736 | } |
6578 | 6737 | ||
6579 | protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector dimple, byte fudge) | 6738 | protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector dimple, byte fudge) |
6580 | { | 6739 | { |
6740 | if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) | ||
6741 | return; | ||
6742 | |||
6581 | ObjectShapePacket.ObjectDataBlock shapeBlock; | 6743 | ObjectShapePacket.ObjectDataBlock shapeBlock; |
6582 | 6744 | ||
6583 | shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist); | 6745 | shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist); |
@@ -6619,7 +6781,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
6619 | } | 6781 | } |
6620 | 6782 | ||
6621 | protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector holesize, LSL_Vector topshear, LSL_Vector profilecut, LSL_Vector taper_a, float revolutions, float radiusoffset, float skew, byte fudge) | 6783 | protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector holesize, LSL_Vector topshear, LSL_Vector profilecut, LSL_Vector taper_a, float revolutions, float radiusoffset, float skew, byte fudge) |
6622 | { | 6784 | { |
6785 | if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) | ||
6786 | return; | ||
6787 | |||
6623 | ObjectShapePacket.ObjectDataBlock shapeBlock; | 6788 | ObjectShapePacket.ObjectDataBlock shapeBlock; |
6624 | 6789 | ||
6625 | shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist); | 6790 | shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist); |
@@ -6740,7 +6905,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
6740 | } | 6905 | } |
6741 | 6906 | ||
6742 | protected void SetPrimitiveShapeParams(SceneObjectPart part, string map, int type) | 6907 | protected void SetPrimitiveShapeParams(SceneObjectPart part, string map, int type) |
6743 | { | 6908 | { |
6909 | if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) | ||
6910 | return; | ||
6911 | |||
6744 | ObjectShapePacket.ObjectDataBlock shapeBlock = new ObjectShapePacket.ObjectDataBlock(); | 6912 | ObjectShapePacket.ObjectDataBlock shapeBlock = new ObjectShapePacket.ObjectDataBlock(); |
6745 | UUID sculptId; | 6913 | UUID sculptId; |
6746 | 6914 | ||
@@ -6774,14 +6942,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
6774 | } | 6942 | } |
6775 | 6943 | ||
6776 | public void llSetPrimitiveParams(LSL_List rules) | 6944 | public void llSetPrimitiveParams(LSL_List rules) |
6777 | { | 6945 | { |
6778 | m_host.AddScriptLPS(1); | 6946 | m_host.AddScriptLPS(1); |
6779 | SetPrimParams(m_host, rules); | 6947 | SetPrimParams(m_host, rules); |
6780 | } | 6948 | } |
6781 | 6949 | ||
6782 | public void llSetLinkPrimitiveParams(int linknumber, LSL_List rules) | 6950 | public void llSetLinkPrimitiveParams(int linknumber, LSL_List rules) |
6783 | { | 6951 | { |
6784 | m_host.AddScriptLPS(1); | 6952 | m_host.AddScriptLPS(1); |
6785 | 6953 | ||
6786 | List<SceneObjectPart> parts = GetLinkParts(linknumber); | 6954 | List<SceneObjectPart> parts = GetLinkParts(linknumber); |
6787 | 6955 | ||
@@ -6790,7 +6958,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
6790 | } | 6958 | } |
6791 | 6959 | ||
6792 | protected void SetPrimParams(SceneObjectPart part, LSL_List rules) | 6960 | protected void SetPrimParams(SceneObjectPart part, LSL_List rules) |
6793 | { | 6961 | { |
6962 | if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) | ||
6963 | return; | ||
6964 | |||
6794 | int idx = 0; | 6965 | int idx = 0; |
6795 | 6966 | ||
6796 | while (idx < rules.Length) | 6967 | while (idx < rules.Length) |
@@ -8195,28 +8366,28 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
8195 | { | 8366 | { |
8196 | m_host.AddScriptLPS(1); | 8367 | m_host.AddScriptLPS(1); |
8197 | 8368 | ||
8198 | lock (m_host.TaskInventory) | 8369 | m_host.TaskInventory.LockItemsForRead(true); |
8370 | foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) | ||
8199 | { | 8371 | { |
8200 | foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) | 8372 | if (inv.Value.Name == item) |
8201 | { | 8373 | { |
8202 | if (inv.Value.Name == item) | 8374 | m_host.TaskInventory.LockItemsForRead(false); |
8375 | switch (mask) | ||
8203 | { | 8376 | { |
8204 | switch (mask) | 8377 | case 0: |
8205 | { | 8378 | return (int)inv.Value.BasePermissions; |
8206 | case 0: | 8379 | case 1: |
8207 | return (int)inv.Value.BasePermissions; | 8380 | return (int)inv.Value.CurrentPermissions; |
8208 | case 1: | 8381 | case 2: |
8209 | return (int)inv.Value.CurrentPermissions; | 8382 | return (int)inv.Value.GroupPermissions; |
8210 | case 2: | 8383 | case 3: |
8211 | return (int)inv.Value.GroupPermissions; | 8384 | return (int)inv.Value.EveryonePermissions; |
8212 | case 3: | 8385 | case 4: |
8213 | return (int)inv.Value.EveryonePermissions; | 8386 | return (int)inv.Value.NextPermissions; |
8214 | case 4: | ||
8215 | return (int)inv.Value.NextPermissions; | ||
8216 | } | ||
8217 | } | 8387 | } |
8218 | } | 8388 | } |
8219 | } | 8389 | } |
8390 | m_host.TaskInventory.LockItemsForRead(false); | ||
8220 | 8391 | ||
8221 | return -1; | 8392 | return -1; |
8222 | } | 8393 | } |
@@ -8231,16 +8402,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
8231 | { | 8402 | { |
8232 | m_host.AddScriptLPS(1); | 8403 | m_host.AddScriptLPS(1); |
8233 | 8404 | ||
8234 | lock (m_host.TaskInventory) | 8405 | m_host.TaskInventory.LockItemsForRead(true); |
8406 | foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) | ||
8235 | { | 8407 | { |
8236 | foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) | 8408 | if (inv.Value.Name == item) |
8237 | { | 8409 | { |
8238 | if (inv.Value.Name == item) | 8410 | m_host.TaskInventory.LockItemsForRead(false); |
8239 | { | 8411 | return inv.Value.CreatorID.ToString(); |
8240 | return inv.Value.CreatorID.ToString(); | ||
8241 | } | ||
8242 | } | 8412 | } |
8243 | } | 8413 | } |
8414 | m_host.TaskInventory.LockItemsForRead(false); | ||
8244 | 8415 | ||
8245 | llSay(0, "No item name '" + item + "'"); | 8416 | llSay(0, "No item name '" + item + "'"); |
8246 | 8417 | ||
@@ -8764,16 +8935,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
8764 | { | 8935 | { |
8765 | m_host.AddScriptLPS(1); | 8936 | m_host.AddScriptLPS(1); |
8766 | 8937 | ||
8767 | lock (m_host.TaskInventory) | 8938 | m_host.TaskInventory.LockItemsForRead(true); |
8939 | foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) | ||
8768 | { | 8940 | { |
8769 | foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) | 8941 | if (inv.Value.Name == name) |
8770 | { | 8942 | { |
8771 | if (inv.Value.Name == name) | 8943 | m_host.TaskInventory.LockItemsForRead(false); |
8772 | { | 8944 | return inv.Value.Type; |
8773 | return inv.Value.Type; | ||
8774 | } | ||
8775 | } | 8945 | } |
8776 | } | 8946 | } |
8947 | m_host.TaskInventory.LockItemsForRead(false); | ||
8777 | 8948 | ||
8778 | return -1; | 8949 | return -1; |
8779 | } | 8950 | } |
@@ -8804,17 +8975,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
8804 | if (invItemID == UUID.Zero) | 8975 | if (invItemID == UUID.Zero) |
8805 | return new LSL_Vector(); | 8976 | return new LSL_Vector(); |
8806 | 8977 | ||
8807 | lock (m_host.TaskInventory) | 8978 | m_host.TaskInventory.LockItemsForRead(true); |
8979 | if (m_host.TaskInventory[invItemID].PermsGranter == UUID.Zero) | ||
8808 | { | 8980 | { |
8809 | if (m_host.TaskInventory[invItemID].PermsGranter == UUID.Zero) | 8981 | m_host.TaskInventory.LockItemsForRead(false); |
8810 | return new LSL_Vector(); | 8982 | return new LSL_Vector(); |
8983 | } | ||
8811 | 8984 | ||
8812 | if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0) | 8985 | if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0) |
8813 | { | 8986 | { |
8814 | ShoutError("No permissions to track the camera"); | 8987 | ShoutError("No permissions to track the camera"); |
8815 | return new LSL_Vector(); | 8988 | m_host.TaskInventory.LockItemsForRead(false); |
8816 | } | 8989 | return new LSL_Vector(); |
8817 | } | 8990 | } |
8991 | m_host.TaskInventory.LockItemsForRead(false); | ||
8818 | 8992 | ||
8819 | ScenePresence presence = World.GetScenePresence(m_host.OwnerID); | 8993 | ScenePresence presence = World.GetScenePresence(m_host.OwnerID); |
8820 | if (presence != null) | 8994 | if (presence != null) |
@@ -8832,17 +9006,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
8832 | if (invItemID == UUID.Zero) | 9006 | if (invItemID == UUID.Zero) |
8833 | return new LSL_Rotation(); | 9007 | return new LSL_Rotation(); |
8834 | 9008 | ||
8835 | lock (m_host.TaskInventory) | 9009 | m_host.TaskInventory.LockItemsForRead(true); |
9010 | if (m_host.TaskInventory[invItemID].PermsGranter == UUID.Zero) | ||
8836 | { | 9011 | { |
8837 | if (m_host.TaskInventory[invItemID].PermsGranter == UUID.Zero) | 9012 | m_host.TaskInventory.LockItemsForRead(false); |
8838 | return new LSL_Rotation(); | 9013 | return new LSL_Rotation(); |
8839 | |||
8840 | if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0) | ||
8841 | { | ||
8842 | ShoutError("No permissions to track the camera"); | ||
8843 | return new LSL_Rotation(); | ||
8844 | } | ||
8845 | } | 9014 | } |
9015 | if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0) | ||
9016 | { | ||
9017 | ShoutError("No permissions to track the camera"); | ||
9018 | m_host.TaskInventory.LockItemsForRead(false); | ||
9019 | return new LSL_Rotation(); | ||
9020 | } | ||
9021 | m_host.TaskInventory.LockItemsForRead(false); | ||
8846 | 9022 | ||
8847 | ScenePresence presence = World.GetScenePresence(m_host.OwnerID); | 9023 | ScenePresence presence = World.GetScenePresence(m_host.OwnerID); |
8848 | if (presence != null) | 9024 | if (presence != null) |
@@ -8992,14 +9168,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
8992 | if (objectID == UUID.Zero) return; | 9168 | if (objectID == UUID.Zero) return; |
8993 | 9169 | ||
8994 | UUID agentID; | 9170 | UUID agentID; |
8995 | lock (m_host.TaskInventory) | 9171 | m_host.TaskInventory.LockItemsForRead(true); |
8996 | { | 9172 | // we need the permission first, to know which avatar we want to set the camera for |
8997 | // we need the permission first, to know which avatar we want to set the camera for | 9173 | agentID = m_host.TaskInventory[invItemID].PermsGranter; |
8998 | agentID = m_host.TaskInventory[invItemID].PermsGranter; | ||
8999 | 9174 | ||
9000 | if (agentID == UUID.Zero) return; | 9175 | if (agentID == UUID.Zero) |
9001 | if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CONTROL_CAMERA) == 0) return; | 9176 | { |
9177 | m_host.TaskInventory.LockItemsForRead(false); | ||
9178 | return; | ||
9179 | } | ||
9180 | if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CONTROL_CAMERA) == 0) | ||
9181 | { | ||
9182 | m_host.TaskInventory.LockItemsForRead(false); | ||
9183 | return; | ||
9002 | } | 9184 | } |
9185 | m_host.TaskInventory.LockItemsForRead(false); | ||
9003 | 9186 | ||
9004 | ScenePresence presence = World.GetScenePresence(agentID); | 9187 | ScenePresence presence = World.GetScenePresence(agentID); |
9005 | 9188 | ||
@@ -9049,12 +9232,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
9049 | 9232 | ||
9050 | // we need the permission first, to know which avatar we want to clear the camera for | 9233 | // we need the permission first, to know which avatar we want to clear the camera for |
9051 | UUID agentID; | 9234 | UUID agentID; |
9052 | lock (m_host.TaskInventory) | 9235 | m_host.TaskInventory.LockItemsForRead(true); |
9236 | agentID = m_host.TaskInventory[invItemID].PermsGranter; | ||
9237 | if (agentID == UUID.Zero) | ||
9053 | { | 9238 | { |
9054 | agentID = m_host.TaskInventory[invItemID].PermsGranter; | 9239 | m_host.TaskInventory.LockItemsForRead(false); |
9055 | if (agentID == UUID.Zero) return; | 9240 | return; |
9056 | if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CONTROL_CAMERA) == 0) return; | 9241 | } |
9242 | if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CONTROL_CAMERA) == 0) | ||
9243 | { | ||
9244 | m_host.TaskInventory.LockItemsForRead(false); | ||
9245 | return; | ||
9057 | } | 9246 | } |
9247 | m_host.TaskInventory.LockItemsForRead(false); | ||
9058 | 9248 | ||
9059 | ScenePresence presence = World.GetScenePresence(agentID); | 9249 | ScenePresence presence = World.GetScenePresence(agentID); |
9060 | 9250 | ||
@@ -9511,15 +9701,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
9511 | 9701 | ||
9512 | internal UUID ScriptByName(string name) | 9702 | internal UUID ScriptByName(string name) |
9513 | { | 9703 | { |
9514 | lock (m_host.TaskInventory) | 9704 | m_host.TaskInventory.LockItemsForRead(true); |
9705 | |||
9706 | foreach (TaskInventoryItem item in m_host.TaskInventory.Values) | ||
9515 | { | 9707 | { |
9516 | foreach (TaskInventoryItem item in m_host.TaskInventory.Values) | 9708 | if (item.Type == 10 && item.Name == name) |
9517 | { | 9709 | { |
9518 | if (item.Type == 10 && item.Name == name) | 9710 | m_host.TaskInventory.LockItemsForRead(false); |
9519 | return item.ItemID; | 9711 | return item.ItemID; |
9520 | } | 9712 | } |
9521 | } | 9713 | } |
9522 | 9714 | ||
9715 | m_host.TaskInventory.LockItemsForRead(false); | ||
9716 | |||
9523 | return UUID.Zero; | 9717 | return UUID.Zero; |
9524 | } | 9718 | } |
9525 | 9719 | ||
@@ -9560,6 +9754,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
9560 | { | 9754 | { |
9561 | m_host.AddScriptLPS(1); | 9755 | m_host.AddScriptLPS(1); |
9562 | 9756 | ||
9757 | //Clone is thread safe | ||
9563 | TaskInventoryDictionary itemsDictionary = (TaskInventoryDictionary)m_host.TaskInventory.Clone(); | 9758 | TaskInventoryDictionary itemsDictionary = (TaskInventoryDictionary)m_host.TaskInventory.Clone(); |
9564 | 9759 | ||
9565 | UUID assetID = UUID.Zero; | 9760 | UUID assetID = UUID.Zero; |
@@ -9622,6 +9817,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
9622 | { | 9817 | { |
9623 | m_host.AddScriptLPS(1); | 9818 | m_host.AddScriptLPS(1); |
9624 | 9819 | ||
9820 | //Clone is thread safe | ||
9625 | TaskInventoryDictionary itemsDictionary = (TaskInventoryDictionary)m_host.TaskInventory.Clone(); | 9821 | TaskInventoryDictionary itemsDictionary = (TaskInventoryDictionary)m_host.TaskInventory.Clone(); |
9626 | 9822 | ||
9627 | UUID assetID = UUID.Zero; | 9823 | UUID assetID = UUID.Zero; |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index d8b9159..a5be251 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs | |||
@@ -728,18 +728,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
728 | if (target != null) | 728 | if (target != null) |
729 | { | 729 | { |
730 | UUID animID=UUID.Zero; | 730 | UUID animID=UUID.Zero; |
731 | lock (m_host.TaskInventory) | 731 | m_host.TaskInventory.LockItemsForRead(true); |
732 | foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) | ||
732 | { | 733 | { |
733 | foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) | 734 | if (inv.Value.Name == animation) |
734 | { | 735 | { |
735 | if (inv.Value.Name == animation) | 736 | if (inv.Value.Type == (int)AssetType.Animation) |
736 | { | 737 | animID = inv.Value.AssetID; |
737 | if (inv.Value.Type == (int)AssetType.Animation) | 738 | continue; |
738 | animID = inv.Value.AssetID; | ||
739 | continue; | ||
740 | } | ||
741 | } | 739 | } |
742 | } | 740 | } |
741 | m_host.TaskInventory.LockItemsForRead(false); | ||
743 | if (animID == UUID.Zero) | 742 | if (animID == UUID.Zero) |
744 | target.Animator.AddAnimation(animation, m_host.UUID); | 743 | target.Animator.AddAnimation(animation, m_host.UUID); |
745 | else | 744 | else |
@@ -761,18 +760,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
761 | if (target != null) | 760 | if (target != null) |
762 | { | 761 | { |
763 | UUID animID=UUID.Zero; | 762 | UUID animID=UUID.Zero; |
764 | lock (m_host.TaskInventory) | 763 | m_host.TaskInventory.LockItemsForRead(true); |
764 | foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) | ||
765 | { | 765 | { |
766 | foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) | 766 | if (inv.Value.Name == animation) |
767 | { | 767 | { |
768 | if (inv.Value.Name == animation) | 768 | if (inv.Value.Type == (int)AssetType.Animation) |
769 | { | 769 | animID = inv.Value.AssetID; |
770 | if (inv.Value.Type == (int)AssetType.Animation) | 770 | continue; |
771 | animID = inv.Value.AssetID; | ||
772 | continue; | ||
773 | } | ||
774 | } | 771 | } |
775 | } | 772 | } |
773 | m_host.TaskInventory.LockItemsForRead(false); | ||
776 | 774 | ||
777 | if (animID == UUID.Zero) | 775 | if (animID == UUID.Zero) |
778 | target.Animator.RemoveAnimation(animation); | 776 | target.Animator.RemoveAnimation(animation); |
@@ -1541,6 +1539,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1541 | 1539 | ||
1542 | if (!UUID.TryParse(name, out assetID)) | 1540 | if (!UUID.TryParse(name, out assetID)) |
1543 | { | 1541 | { |
1542 | m_host.TaskInventory.LockItemsForRead(true); | ||
1544 | foreach (TaskInventoryItem item in m_host.TaskInventory.Values) | 1543 | foreach (TaskInventoryItem item in m_host.TaskInventory.Values) |
1545 | { | 1544 | { |
1546 | if (item.Type == 7 && item.Name == name) | 1545 | if (item.Type == 7 && item.Name == name) |
@@ -1548,6 +1547,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1548 | assetID = item.AssetID; | 1547 | assetID = item.AssetID; |
1549 | } | 1548 | } |
1550 | } | 1549 | } |
1550 | m_host.TaskInventory.LockItemsForRead(false); | ||
1551 | } | 1551 | } |
1552 | 1552 | ||
1553 | if (assetID == UUID.Zero) | 1553 | if (assetID == UUID.Zero) |
@@ -1594,6 +1594,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1594 | 1594 | ||
1595 | if (!UUID.TryParse(name, out assetID)) | 1595 | if (!UUID.TryParse(name, out assetID)) |
1596 | { | 1596 | { |
1597 | m_host.TaskInventory.LockItemsForRead(true); | ||
1597 | foreach (TaskInventoryItem item in m_host.TaskInventory.Values) | 1598 | foreach (TaskInventoryItem item in m_host.TaskInventory.Values) |
1598 | { | 1599 | { |
1599 | if (item.Type == 7 && item.Name == name) | 1600 | if (item.Type == 7 && item.Name == name) |
@@ -1601,6 +1602,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1601 | assetID = item.AssetID; | 1602 | assetID = item.AssetID; |
1602 | } | 1603 | } |
1603 | } | 1604 | } |
1605 | m_host.TaskInventory.LockItemsForRead(false); | ||
1604 | } | 1606 | } |
1605 | 1607 | ||
1606 | if (assetID == UUID.Zero) | 1608 | if (assetID == UUID.Zero) |
@@ -1651,6 +1653,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1651 | 1653 | ||
1652 | if (!UUID.TryParse(name, out assetID)) | 1654 | if (!UUID.TryParse(name, out assetID)) |
1653 | { | 1655 | { |
1656 | m_host.TaskInventory.LockItemsForRead(true); | ||
1654 | foreach (TaskInventoryItem item in m_host.TaskInventory.Values) | 1657 | foreach (TaskInventoryItem item in m_host.TaskInventory.Values) |
1655 | { | 1658 | { |
1656 | if (item.Type == 7 && item.Name == name) | 1659 | if (item.Type == 7 && item.Name == name) |
@@ -1658,6 +1661,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1658 | assetID = item.AssetID; | 1661 | assetID = item.AssetID; |
1659 | } | 1662 | } |
1660 | } | 1663 | } |
1664 | m_host.TaskInventory.LockItemsForRead(false); | ||
1661 | } | 1665 | } |
1662 | 1666 | ||
1663 | if (assetID == UUID.Zero) | 1667 | if (assetID == UUID.Zero) |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/Timer.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/Timer.cs index eeb59d9..2fd33fe 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/Timer.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/Timer.cs | |||
@@ -109,25 +109,27 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins | |||
109 | if (Timers.Count == 0) | 109 | if (Timers.Count == 0) |
110 | return; | 110 | return; |
111 | 111 | ||
112 | Dictionary<string, TimerClass>.ValueCollection tvals; | ||
112 | lock (TimerListLock) | 113 | lock (TimerListLock) |
113 | { | 114 | { |
114 | // Go through all timers | 115 | // Go through all timers |
115 | Dictionary<string, TimerClass>.ValueCollection tvals = Timers.Values; | 116 | tvals = Timers.Values; |
116 | foreach (TimerClass ts in tvals) | 117 | } |
118 | |||
119 | foreach (TimerClass ts in tvals) | ||
120 | { | ||
121 | // Time has passed? | ||
122 | if (ts.next < DateTime.Now.Ticks) | ||
117 | { | 123 | { |
118 | // Time has passed? | 124 | //m_log.Debug("Time has passed: Now: " + DateTime.Now.Ticks + ", Passed: " + ts.next); |
119 | if (ts.next < DateTime.Now.Ticks) | 125 | // Add it to queue |
120 | { | 126 | m_CmdManager.m_ScriptEngine.PostScriptEvent(ts.itemID, |
121 | //m_log.Debug("Time has passed: Now: " + DateTime.Now.Ticks + ", Passed: " + ts.next); | 127 | new EventParams("timer", new Object[0], |
122 | // Add it to queue | 128 | new DetectParams[0])); |
123 | m_CmdManager.m_ScriptEngine.PostScriptEvent(ts.itemID, | 129 | // set next interval |
124 | new EventParams("timer", new Object[0], | 130 | |
125 | new DetectParams[0])); | 131 | //ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval); |
126 | // set next interval | 132 | ts.next = DateTime.Now.Ticks + ts.interval; |
127 | |||
128 | //ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval); | ||
129 | ts.next = DateTime.Now.Ticks + ts.interval; | ||
130 | } | ||
131 | } | 133 | } |
132 | } | 134 | } |
133 | } | 135 | } |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ICM_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ICM_Api.cs new file mode 100644 index 0000000..ef990a1 --- /dev/null +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ICM_Api.cs | |||
@@ -0,0 +1,21 @@ | |||
1 | using System.Collections; | ||
2 | using OpenSim.Region.ScriptEngine.Interfaces; | ||
3 | |||
4 | using key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; | ||
5 | using rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion; | ||
6 | using vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3; | ||
7 | using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list; | ||
8 | using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; | ||
9 | using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger; | ||
10 | using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat; | ||
11 | |||
12 | namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces | ||
13 | { | ||
14 | public interface ICM_Api | ||
15 | { | ||
16 | // Windlight Functions | ||
17 | LSL_List cmGetWindlightScene(LSL_List rules); | ||
18 | int cmSetWindlightScene(LSL_List rules); | ||
19 | int cmSetWindlightSceneTargeted(LSL_List rules, key target); | ||
20 | } | ||
21 | } | ||
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs index 60b8050..f5921e1 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs | |||
@@ -80,7 +80,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces | |||
80 | // Avatar Info Commands | 80 | // Avatar Info Commands |
81 | string osGetAgentIP(string agent); | 81 | string osGetAgentIP(string agent); |
82 | LSL_List osGetAgents(); | 82 | LSL_List osGetAgents(); |
83 | 83 | ||
84 | // Teleport commands | 84 | // Teleport commands |
85 | void osTeleportAgent(string agent, string regionName, LSL_Types.Vector3 position, LSL_Types.Vector3 lookat); | 85 | void osTeleportAgent(string agent, string regionName, LSL_Types.Vector3 position, LSL_Types.Vector3 lookat); |
86 | void osTeleportAgent(string agent, int regionX, int regionY, LSL_Types.Vector3 position, LSL_Types.Vector3 lookat); | 86 | void osTeleportAgent(string agent, int regionX, int regionY, LSL_Types.Vector3 position, LSL_Types.Vector3 lookat); |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/CM_Constants.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/CM_Constants.cs new file mode 100644 index 0000000..7b67fa3 --- /dev/null +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/CM_Constants.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 | |||
28 | using System; | ||
29 | using vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3; | ||
30 | using rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion; | ||
31 | using LSLInteger = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger; | ||
32 | |||
33 | namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase | ||
34 | { | ||
35 | public partial class ScriptBaseClass | ||
36 | { | ||
37 | // Constants for cmWindlight* | ||
38 | public const int WL_WATER_COLOR = 0; | ||
39 | public const int WL_WATER_FOG_DENSITY_EXPONENT = 1; | ||
40 | public const int WL_UNDERWATER_FOG_MODIFIER = 2; | ||
41 | public const int WL_REFLECTION_WAVELET_SCALE = 3; | ||
42 | public const int WL_FRESNEL_SCALE = 4; | ||
43 | public const int WL_FRESNEL_OFFSET = 5; | ||
44 | public const int WL_REFRACT_SCALE_ABOVE = 6; | ||
45 | public const int WL_REFRACT_SCALE_BELOW = 7; | ||
46 | public const int WL_BLUR_MULTIPLIER = 8; | ||
47 | public const int WL_BIG_WAVE_DIRECTION = 9; | ||
48 | public const int WL_LITTLE_WAVE_DIRECTION = 10; | ||
49 | public const int WL_NORMAL_MAP_TEXTURE = 11; | ||
50 | public const int WL_HORIZON = 12; | ||
51 | public const int WL_HAZE_HORIZON = 13; | ||
52 | public const int WL_BLUE_DENSITY = 14; | ||
53 | public const int WL_HAZE_DENSITY = 15; | ||
54 | public const int WL_DENSITY_MULTIPLIER = 16; | ||
55 | public const int WL_DISTANCE_MULTIPLIER = 17; | ||
56 | public const int WL_MAX_ALTITUDE = 18; | ||
57 | public const int WL_SUN_MOON_COLOR = 19; | ||
58 | public const int WL_AMBIENT = 20; | ||
59 | public const int WL_EAST_ANGLE = 21; | ||
60 | public const int WL_SUN_GLOW_FOCUS = 22; | ||
61 | public const int WL_SUN_GLOW_SIZE = 23; | ||
62 | public const int WL_SCENE_GAMMA = 24; | ||
63 | public const int WL_STAR_BRIGHTNESS = 25; | ||
64 | public const int WL_CLOUD_COLOR = 26; | ||
65 | public const int WL_CLOUD_XY_DENSITY = 27; | ||
66 | public const int WL_CLOUD_COVERAGE = 28; | ||
67 | public const int WL_CLOUD_SCALE = 29; | ||
68 | public const int WL_CLOUD_DETAIL_XY_DENSITY = 30; | ||
69 | public const int WL_CLOUD_SCROLL_X = 31; | ||
70 | public const int WL_CLOUD_SCROLL_Y = 32; | ||
71 | public const int WL_CLOUD_SCROLL_Y_LOCK = 33; | ||
72 | public const int WL_CLOUD_SCROLL_X_LOCK = 34; | ||
73 | public const int WL_DRAW_CLASSIC_CLOUDS = 35; | ||
74 | |||
75 | } | ||
76 | } | ||
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/CM_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/CM_Stub.cs new file mode 100644 index 0000000..5bc3a88 --- /dev/null +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/CM_Stub.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 | |||
28 | using System; | ||
29 | using System.Runtime.Remoting.Lifetime; | ||
30 | using System.Threading; | ||
31 | using System.Reflection; | ||
32 | using System.Collections; | ||
33 | using System.Collections.Generic; | ||
34 | using OpenSim.Framework; | ||
35 | using OpenSim.Region.Framework.Interfaces; | ||
36 | using OpenSim.Region.ScriptEngine.Interfaces; | ||
37 | using OpenSim.Region.ScriptEngine.Shared.Api.Interfaces; | ||
38 | using integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger; | ||
39 | using vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3; | ||
40 | using rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion; | ||
41 | using key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; | ||
42 | using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list; | ||
43 | using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; | ||
44 | using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat; | ||
45 | using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger; | ||
46 | |||
47 | namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase | ||
48 | { | ||
49 | public partial class ScriptBaseClass : MarshalByRefObject | ||
50 | { | ||
51 | public ICM_Api m_CM_Functions; | ||
52 | |||
53 | public void ApiTypeCM(IScriptApi api) | ||
54 | { | ||
55 | if (!(api is ICM_Api)) | ||
56 | return; | ||
57 | |||
58 | m_CM_Functions = (ICM_Api)api; | ||
59 | } | ||
60 | |||
61 | public LSL_List cmGetWindlightScene(LSL_List rules) | ||
62 | { | ||
63 | return m_CM_Functions.cmGetWindlightScene(rules); | ||
64 | } | ||
65 | |||
66 | public int cmSetWindlightScene(LSL_List rules) | ||
67 | { | ||
68 | return m_CM_Functions.cmSetWindlightScene(rules); | ||
69 | } | ||
70 | |||
71 | public int cmSetWindlightSceneTargeted(LSL_List rules, key target) | ||
72 | { | ||
73 | return m_CM_Functions.cmSetWindlightSceneTargeted(rules, target); | ||
74 | } | ||
75 | } | ||
76 | } | ||
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/Executor.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/Executor.cs index 7f67599..15e0408 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/Executor.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/Executor.cs | |||
@@ -27,6 +27,7 @@ | |||
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Diagnostics; //for [DebuggerNonUserCode] | ||
30 | using System.Reflection; | 31 | using System.Reflection; |
31 | using System.Runtime.Remoting.Lifetime; | 32 | using System.Runtime.Remoting.Lifetime; |
32 | using OpenSim.Region.ScriptEngine.Shared; | 33 | using OpenSim.Region.ScriptEngine.Shared; |
@@ -131,6 +132,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase | |||
131 | return (eventFlags); | 132 | return (eventFlags); |
132 | } | 133 | } |
133 | 134 | ||
135 | [DebuggerNonUserCode] | ||
134 | public void ExecuteEvent(string state, string FunctionName, object[] args) | 136 | public void ExecuteEvent(string state, string FunctionName, object[] args) |
135 | { | 137 | { |
136 | // IMPORTANT: Types and MemberInfo-derived objects require a LOT of memory. | 138 | // IMPORTANT: Types and MemberInfo-derived objects require a LOT of memory. |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OpenSim.Region.ScriptEngine.Shared.Api.Runtime.mdp b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OpenSim.Region.ScriptEngine.Shared.Api.Runtime.mdp index 98bbc68..23138ef 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OpenSim.Region.ScriptEngine.Shared.Api.Runtime.mdp +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OpenSim.Region.ScriptEngine.Shared.Api.Runtime.mdp | |||
@@ -17,6 +17,8 @@ | |||
17 | <excludeFiles /> | 17 | <excludeFiles /> |
18 | </DeploymentInformation> | 18 | </DeploymentInformation> |
19 | <Contents> | 19 | <Contents> |
20 | <File name="./CM_Constants.cs" subtype="Code" buildaction="Compile" dependson="" data="" /> | ||
21 | <File name="./CM_Stub.cs" subtype="Code" buildaction="Compile" dependson="" data="" /> | ||
20 | <File name="./Executor.cs" subtype="Code" buildaction="Compile" dependson="" data="" /> | 22 | <File name="./Executor.cs" subtype="Code" buildaction="Compile" dependson="" data="" /> |
21 | <File name="./LSL_Constants.cs" subtype="Code" buildaction="Compile" dependson="" data="" /> | 23 | <File name="./LSL_Constants.cs" subtype="Code" buildaction="Compile" dependson="" data="" /> |
22 | <File name="./LSL_Stub.cs" subtype="Code" buildaction="Compile" dependson="" data="" /> | 24 | <File name="./LSL_Stub.cs" subtype="Code" buildaction="Compile" dependson="" data="" /> |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/ScriptBase.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/ScriptBase.cs index edbbc2a..b138da3 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/ScriptBase.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/ScriptBase.cs | |||
@@ -33,6 +33,7 @@ using System.Threading; | |||
33 | using System.Reflection; | 33 | using System.Reflection; |
34 | using System.Collections; | 34 | using System.Collections; |
35 | using System.Collections.Generic; | 35 | using System.Collections.Generic; |
36 | using System.Diagnostics; //for [DebuggerNonUserCode] | ||
36 | using OpenSim.Region.ScriptEngine.Interfaces; | 37 | using OpenSim.Region.ScriptEngine.Interfaces; |
37 | using OpenSim.Region.ScriptEngine.Shared; | 38 | using OpenSim.Region.ScriptEngine.Shared; |
38 | using OpenSim.Region.ScriptEngine.Shared.Api.Runtime; | 39 | using OpenSim.Region.ScriptEngine.Shared.Api.Runtime; |
@@ -90,6 +91,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase | |||
90 | return (int)m_Executor.GetStateEventFlags(state); | 91 | return (int)m_Executor.GetStateEventFlags(state); |
91 | } | 92 | } |
92 | 93 | ||
94 | [DebuggerNonUserCode] | ||
93 | public void ExecuteEvent(string state, string FunctionName, object[] args) | 95 | public void ExecuteEvent(string state, string FunctionName, object[] args) |
94 | { | 96 | { |
95 | m_Executor.ExecuteEvent(state, FunctionName, args); | 97 | m_Executor.ExecuteEvent(state, FunctionName, args); |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs index d30d2dc..6ecafd4 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs | |||
@@ -27,6 +27,7 @@ | |||
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.IO; | 29 | using System.IO; |
30 | using System.Diagnostics; //for [DebuggerNonUserCode] | ||
30 | using System.Runtime.Remoting; | 31 | using System.Runtime.Remoting; |
31 | using System.Runtime.Remoting.Lifetime; | 32 | using System.Runtime.Remoting.Lifetime; |
32 | using System.Threading; | 33 | using System.Threading; |
@@ -237,13 +238,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
237 | 238 | ||
238 | if (part != null) | 239 | if (part != null) |
239 | { | 240 | { |
240 | lock (part.TaskInventory) | 241 | part.TaskInventory.LockItemsForRead(true); |
242 | if (part.TaskInventory.ContainsKey(m_ItemID)) | ||
241 | { | 243 | { |
242 | if (part.TaskInventory.ContainsKey(m_ItemID)) | 244 | m_thisScriptTask = part.TaskInventory[m_ItemID]; |
243 | { | ||
244 | m_thisScriptTask = part.TaskInventory[m_ItemID]; | ||
245 | } | ||
246 | } | 245 | } |
246 | part.TaskInventory.LockItemsForRead(false); | ||
247 | } | 247 | } |
248 | 248 | ||
249 | ApiManager am = new ApiManager(); | 249 | ApiManager am = new ApiManager(); |
@@ -428,14 +428,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
428 | { | 428 | { |
429 | int permsMask; | 429 | int permsMask; |
430 | UUID permsGranter; | 430 | UUID permsGranter; |
431 | lock (part.TaskInventory) | 431 | part.TaskInventory.LockItemsForRead(true); |
432 | if (!part.TaskInventory.ContainsKey(m_ItemID)) | ||
432 | { | 433 | { |
433 | if (!part.TaskInventory.ContainsKey(m_ItemID)) | 434 | part.TaskInventory.LockItemsForRead(false); |
434 | return; | 435 | return; |
435 | |||
436 | permsGranter = part.TaskInventory[m_ItemID].PermsGranter; | ||
437 | permsMask = part.TaskInventory[m_ItemID].PermsMask; | ||
438 | } | 436 | } |
437 | permsGranter = part.TaskInventory[m_ItemID].PermsGranter; | ||
438 | permsMask = part.TaskInventory[m_ItemID].PermsMask; | ||
439 | part.TaskInventory.LockItemsForRead(false); | ||
439 | 440 | ||
440 | if ((permsMask & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) != 0) | 441 | if ((permsMask & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) != 0) |
441 | { | 442 | { |
@@ -544,6 +545,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
544 | return true; | 545 | return true; |
545 | } | 546 | } |
546 | 547 | ||
548 | [DebuggerNonUserCode] //Prevents the debugger from farting in this function | ||
547 | public void SetState(string state) | 549 | public void SetState(string state) |
548 | { | 550 | { |
549 | if (state == State) | 551 | if (state == State) |
@@ -555,7 +557,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
555 | new DetectParams[0])); | 557 | new DetectParams[0])); |
556 | PostEvent(new EventParams("state_entry", new Object[0], | 558 | PostEvent(new EventParams("state_entry", new Object[0], |
557 | new DetectParams[0])); | 559 | new DetectParams[0])); |
558 | 560 | ||
559 | throw new EventAbortException(); | 561 | throw new EventAbortException(); |
560 | } | 562 | } |
561 | 563 | ||
@@ -638,154 +640,158 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
638 | /// <returns></returns> | 640 | /// <returns></returns> |
639 | public object EventProcessor() | 641 | public object EventProcessor() |
640 | { | 642 | { |
643 | |||
644 | EventParams data = null; | ||
645 | |||
646 | lock (m_EventQueue) | ||
647 | { | ||
641 | lock (m_Script) | 648 | lock (m_Script) |
642 | { | 649 | { |
643 | EventParams data = null; | 650 | data = (EventParams) m_EventQueue.Dequeue(); |
644 | 651 | if (data == null) // Shouldn't happen | |
645 | lock (m_EventQueue) | ||
646 | { | 652 | { |
647 | data = (EventParams) m_EventQueue.Dequeue(); | 653 | if ((m_EventQueue.Count > 0) && m_RunEvents && (!m_ShuttingDown)) |
648 | if (data == null) // Shouldn't happen | ||
649 | { | 654 | { |
650 | if ((m_EventQueue.Count > 0) && m_RunEvents && (!m_ShuttingDown)) | 655 | m_CurrentResult = m_Engine.QueueEventHandler(this); |
651 | { | ||
652 | m_CurrentResult = m_Engine.QueueEventHandler(this); | ||
653 | } | ||
654 | else | ||
655 | { | ||
656 | m_CurrentResult = null; | ||
657 | } | ||
658 | return 0; | ||
659 | } | 656 | } |
660 | 657 | else | |
661 | if (data.EventName == "timer") | ||
662 | m_TimerQueued = false; | ||
663 | if (data.EventName == "control") | ||
664 | { | 658 | { |
665 | if (m_ControlEventsInQueue > 0) | 659 | m_CurrentResult = null; |
666 | m_ControlEventsInQueue--; | ||
667 | } | 660 | } |
668 | if (data.EventName == "collision") | 661 | return 0; |
669 | m_CollisionInQueue = false; | ||
670 | } | 662 | } |
671 | |||
672 | //m_log.DebugFormat("[XENGINE]: Processing event {0} for {1}", data.EventName, this); | ||
673 | 663 | ||
674 | m_DetectParams = data.DetectParams; | 664 | if (data.EventName == "timer") |
675 | 665 | m_TimerQueued = false; | |
676 | if (data.EventName == "state") // Hardcoded state change | 666 | if (data.EventName == "control") |
677 | { | 667 | { |
678 | // m_log.DebugFormat("[Script] Script {0}.{1} state set to {2}", | 668 | if (m_ControlEventsInQueue > 0) |
679 | // m_PrimName, m_ScriptName, data.Params[0].ToString()); | 669 | m_ControlEventsInQueue--; |
680 | m_State=data.Params[0].ToString(); | 670 | } |
681 | AsyncCommandManager.RemoveScript(m_Engine, | 671 | if (data.EventName == "collision") |
682 | m_LocalID, m_ItemID); | 672 | m_CollisionInQueue = false; |
673 | } | ||
674 | } | ||
675 | lock(m_Script) | ||
676 | { | ||
677 | |||
678 | //m_log.DebugFormat("[XENGINE]: Processing event {0} for {1}", data.EventName, this); | ||
683 | 679 | ||
684 | SceneObjectPart part = m_Engine.World.GetSceneObjectPart( | 680 | m_DetectParams = data.DetectParams; |
685 | m_LocalID); | 681 | |
686 | if (part != null) | 682 | if (data.EventName == "state") // Hardcoded state change |
687 | { | 683 | { |
688 | part.SetScriptEvents(m_ItemID, | 684 | // m_log.DebugFormat("[Script] Script {0}.{1} state set to {2}", |
689 | (int)m_Script.GetStateEventFlags(State)); | 685 | // m_PrimName, m_ScriptName, data.Params[0].ToString()); |
690 | } | 686 | m_State=data.Params[0].ToString(); |
687 | AsyncCommandManager.RemoveScript(m_Engine, | ||
688 | m_LocalID, m_ItemID); | ||
689 | |||
690 | SceneObjectPart part = m_Engine.World.GetSceneObjectPart( | ||
691 | m_LocalID); | ||
692 | if (part != null) | ||
693 | { | ||
694 | part.SetScriptEvents(m_ItemID, | ||
695 | (int)m_Script.GetStateEventFlags(State)); | ||
691 | } | 696 | } |
692 | else | 697 | } |
698 | else | ||
699 | { | ||
700 | if (m_Engine.World.PipeEventsForScript(m_LocalID) || | ||
701 | data.EventName == "control") // Don't freeze avies! | ||
693 | { | 702 | { |
694 | if (m_Engine.World.PipeEventsForScript(m_LocalID) || | 703 | SceneObjectPart part = m_Engine.World.GetSceneObjectPart( |
695 | data.EventName == "control") // Don't freeze avies! | 704 | m_LocalID); |
696 | { | 705 | // m_log.DebugFormat("[Script] Delivered event {2} in state {3} to {0}.{1}", |
697 | SceneObjectPart part = m_Engine.World.GetSceneObjectPart( | 706 | // m_PrimName, m_ScriptName, data.EventName, m_State); |
698 | m_LocalID); | ||
699 | // m_log.DebugFormat("[Script] Delivered event {2} in state {3} to {0}.{1}", | ||
700 | // m_PrimName, m_ScriptName, data.EventName, m_State); | ||
701 | 707 | ||
702 | try | 708 | try |
703 | { | 709 | { |
704 | m_CurrentEvent = data.EventName; | 710 | m_CurrentEvent = data.EventName; |
705 | m_EventStart = DateTime.Now; | 711 | m_EventStart = DateTime.Now; |
706 | m_InEvent = true; | 712 | m_InEvent = true; |
707 | 713 | ||
708 | m_Script.ExecuteEvent(State, data.EventName, data.Params); | 714 | m_Script.ExecuteEvent(State, data.EventName, data.Params); |
709 | 715 | ||
710 | m_InEvent = false; | 716 | m_InEvent = false; |
711 | m_CurrentEvent = String.Empty; | 717 | m_CurrentEvent = String.Empty; |
712 | 718 | ||
713 | if (m_SaveState) | 719 | if (m_SaveState) |
714 | { | 720 | { |
715 | // This will be the very first event we deliver | 721 | // This will be the very first event we deliver |
716 | // (state_entry) in default state | 722 | // (state_entry) in default state |
717 | // | 723 | // |
718 | 724 | ||
719 | SaveState(m_Assembly); | 725 | SaveState(m_Assembly); |
720 | 726 | ||
721 | m_SaveState = false; | 727 | m_SaveState = false; |
722 | } | ||
723 | } | 728 | } |
724 | catch (Exception e) | 729 | } |
725 | { | 730 | catch (Exception e) |
726 | // m_log.DebugFormat("[SCRIPT] Exception: {0}", e.Message); | 731 | { |
727 | m_InEvent = false; | 732 | // m_log.DebugFormat("[SCRIPT] Exception: {0}", e.Message); |
728 | m_CurrentEvent = String.Empty; | 733 | m_InEvent = false; |
734 | m_CurrentEvent = String.Empty; | ||
729 | 735 | ||
730 | if ((!(e is TargetInvocationException) || (!(e.InnerException is SelfDeleteException) && !(e.InnerException is ScriptDeleteException))) && !(e is ThreadAbortException)) | 736 | if ((!(e is TargetInvocationException) || (!(e.InnerException is SelfDeleteException) && !(e.InnerException is ScriptDeleteException))) && !(e is ThreadAbortException)) |
731 | { | 737 | { |
732 | try | 738 | try |
733 | { | ||
734 | // DISPLAY ERROR INWORLD | ||
735 | string text = FormatException(e); | ||
736 | |||
737 | if (text.Length > 1000) | ||
738 | text = text.Substring(0, 1000); | ||
739 | m_Engine.World.SimChat(Utils.StringToBytes(text), | ||
740 | ChatTypeEnum.DebugChannel, 2147483647, | ||
741 | part.AbsolutePosition, | ||
742 | part.Name, part.UUID, false); | ||
743 | } | ||
744 | catch (Exception) | ||
745 | { | ||
746 | } | ||
747 | // catch (Exception e2) // LEGIT: User Scripting | ||
748 | // { | ||
749 | // m_log.Error("[SCRIPT]: "+ | ||
750 | // "Error displaying error in-world: " + | ||
751 | // e2.ToString()); | ||
752 | // m_log.Error("[SCRIPT]: " + | ||
753 | // "Errormessage: Error compiling script:\r\n" + | ||
754 | // e.ToString()); | ||
755 | // } | ||
756 | } | ||
757 | else if ((e is TargetInvocationException) && (e.InnerException is SelfDeleteException)) | ||
758 | { | 739 | { |
759 | m_InSelfDelete = true; | 740 | // DISPLAY ERROR INWORLD |
760 | if (part != null && part.ParentGroup != null) | 741 | string text = FormatException(e); |
761 | m_Engine.World.DeleteSceneObject(part.ParentGroup, false); | 742 | |
743 | if (text.Length > 1000) | ||
744 | text = text.Substring(0, 1000); | ||
745 | m_Engine.World.SimChat(Utils.StringToBytes(text), | ||
746 | ChatTypeEnum.DebugChannel, 2147483647, | ||
747 | part.AbsolutePosition, | ||
748 | part.Name, part.UUID, false); | ||
762 | } | 749 | } |
763 | else if ((e is TargetInvocationException) && (e.InnerException is ScriptDeleteException)) | 750 | catch (Exception) |
764 | { | 751 | { |
765 | m_InSelfDelete = true; | ||
766 | if (part != null && part.ParentGroup != null) | ||
767 | part.Inventory.RemoveInventoryItem(m_ItemID); | ||
768 | } | 752 | } |
753 | // catch (Exception e2) // LEGIT: User Scripting | ||
754 | // { | ||
755 | // m_log.Error("[SCRIPT]: "+ | ||
756 | // "Error displaying error in-world: " + | ||
757 | // e2.ToString()); | ||
758 | // m_log.Error("[SCRIPT]: " + | ||
759 | // "Errormessage: Error compiling script:\r\n" + | ||
760 | // e.ToString()); | ||
761 | // } | ||
762 | } | ||
763 | else if ((e is TargetInvocationException) && (e.InnerException is SelfDeleteException)) | ||
764 | { | ||
765 | m_InSelfDelete = true; | ||
766 | if (part != null && part.ParentGroup != null) | ||
767 | m_Engine.World.DeleteSceneObject(part.ParentGroup, false); | ||
768 | } | ||
769 | else if ((e is TargetInvocationException) && (e.InnerException is ScriptDeleteException)) | ||
770 | { | ||
771 | m_InSelfDelete = true; | ||
772 | if (part != null && part.ParentGroup != null) | ||
773 | part.Inventory.RemoveInventoryItem(m_ItemID); | ||
769 | } | 774 | } |
770 | } | 775 | } |
771 | } | 776 | } |
777 | } | ||
772 | 778 | ||
773 | lock (m_EventQueue) | 779 | lock (m_EventQueue) |
780 | { | ||
781 | if ((m_EventQueue.Count > 0) && m_RunEvents && (!m_ShuttingDown)) | ||
774 | { | 782 | { |
775 | if ((m_EventQueue.Count > 0) && m_RunEvents && (!m_ShuttingDown)) | 783 | m_CurrentResult = m_Engine.QueueEventHandler(this); |
776 | { | 784 | } |
777 | m_CurrentResult = m_Engine.QueueEventHandler(this); | 785 | else |
778 | } | 786 | { |
779 | else | 787 | m_CurrentResult = null; |
780 | { | ||
781 | m_CurrentResult = null; | ||
782 | } | ||
783 | } | 788 | } |
789 | } | ||
784 | 790 | ||
785 | m_DetectParams = null; | 791 | m_DetectParams = null; |
786 | 792 | ||
787 | return 0; | 793 | return 0; |
788 | } | 794 | } |
789 | } | 795 | } |
790 | 796 | ||
791 | public int EventTime() | 797 | public int EventTime() |
@@ -824,6 +830,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
824 | new Object[0], new DetectParams[0])); | 830 | new Object[0], new DetectParams[0])); |
825 | } | 831 | } |
826 | 832 | ||
833 | [DebuggerNonUserCode] //Stops the VS debugger from farting in this function | ||
827 | public void ApiResetScript() | 834 | public void ApiResetScript() |
828 | { | 835 | { |
829 | // bool running = Running; | 836 | // bool running = Running; |
diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index 6dd94bb..d65107e 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs | |||
@@ -30,6 +30,7 @@ using System.IO; | |||
30 | using System.Threading; | 30 | using System.Threading; |
31 | using System.Collections; | 31 | using System.Collections; |
32 | using System.Collections.Generic; | 32 | using System.Collections.Generic; |
33 | using System.Diagnostics; //for [DebuggerNonUserCode] | ||
33 | using System.Security; | 34 | using System.Security; |
34 | using System.Security.Policy; | 35 | using System.Security.Policy; |
35 | using System.Reflection; | 36 | using System.Reflection; |
@@ -102,6 +103,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
102 | private Dictionary<UUID, IScriptInstance> m_Scripts = | 103 | private Dictionary<UUID, IScriptInstance> m_Scripts = |
103 | new Dictionary<UUID, IScriptInstance>(); | 104 | new Dictionary<UUID, IScriptInstance>(); |
104 | 105 | ||
106 | private OpenMetaverse.ReaderWriterLockSlim m_scriptsLock = new OpenMetaverse.ReaderWriterLockSlim(); | ||
107 | |||
105 | // Maps the asset ID to the assembly | 108 | // Maps the asset ID to the assembly |
106 | 109 | ||
107 | private Dictionary<UUID, string> m_Assemblies = | 110 | private Dictionary<UUID, string> m_Assemblies = |
@@ -123,6 +126,71 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
123 | private ScriptCompileQueue m_CompileQueue = new ScriptCompileQueue(); | 126 | private ScriptCompileQueue m_CompileQueue = new ScriptCompileQueue(); |
124 | IWorkItemResult m_CurrentCompile = null; | 127 | IWorkItemResult m_CurrentCompile = null; |
125 | 128 | ||
129 | private void lockScriptsForRead(bool locked) | ||
130 | { | ||
131 | if (locked) | ||
132 | { | ||
133 | if (m_scriptsLock.RecursiveReadCount > 0) | ||
134 | { | ||
135 | m_log.Error("[XEngine.m_Scripts] Recursive read lock requested. This should not happen and means something needs to be fixed. For now though, it's safe to continue."); | ||
136 | m_scriptsLock.ExitReadLock(); | ||
137 | } | ||
138 | if (m_scriptsLock.RecursiveWriteCount > 0) | ||
139 | { | ||
140 | m_log.Error("[XEngine.m_Scripts] Recursive write lock requested. This should not happen and means something needs to be fixed."); | ||
141 | m_scriptsLock.ExitWriteLock(); | ||
142 | } | ||
143 | |||
144 | while (!m_scriptsLock.TryEnterReadLock(60000)) | ||
145 | { | ||
146 | m_log.Error("[XEngine.m_Scripts] Thread lock detected while trying to aquire READ lock of m_scripts in XEngine. I'm going to try to solve the thread lock automatically to preserve region stability, but this needs to be fixed."); | ||
147 | if (m_scriptsLock.IsWriteLockHeld) | ||
148 | { | ||
149 | m_scriptsLock = new OpenMetaverse.ReaderWriterLockSlim(); | ||
150 | } | ||
151 | } | ||
152 | } | ||
153 | else | ||
154 | { | ||
155 | if (m_scriptsLock.RecursiveReadCount > 0) | ||
156 | { | ||
157 | m_scriptsLock.ExitReadLock(); | ||
158 | } | ||
159 | } | ||
160 | } | ||
161 | private void lockScriptsForWrite(bool locked) | ||
162 | { | ||
163 | if (locked) | ||
164 | { | ||
165 | if (m_scriptsLock.RecursiveReadCount > 0) | ||
166 | { | ||
167 | m_log.Error("[XEngine.m_Scripts] Recursive read lock requested. This should not happen and means something needs to be fixed. For now though, it's safe to continue."); | ||
168 | m_scriptsLock.ExitReadLock(); | ||
169 | } | ||
170 | if (m_scriptsLock.RecursiveWriteCount > 0) | ||
171 | { | ||
172 | m_log.Error("[XEngine.m_Scripts] Recursive write lock requested. This should not happen and means something needs to be fixed."); | ||
173 | m_scriptsLock.ExitWriteLock(); | ||
174 | } | ||
175 | |||
176 | while (!m_scriptsLock.TryEnterWriteLock(60000)) | ||
177 | { | ||
178 | m_log.Error("[XEngine.m_Scripts] Thread lock detected while trying to aquire WRITE lock of m_scripts in XEngine. I'm going to try to solve the thread lock automatically to preserve region stability, but this needs to be fixed."); | ||
179 | if (m_scriptsLock.IsWriteLockHeld) | ||
180 | { | ||
181 | m_scriptsLock = new OpenMetaverse.ReaderWriterLockSlim(); | ||
182 | } | ||
183 | } | ||
184 | } | ||
185 | else | ||
186 | { | ||
187 | if (m_scriptsLock.RecursiveWriteCount > 0) | ||
188 | { | ||
189 | m_scriptsLock.ExitWriteLock(); | ||
190 | } | ||
191 | } | ||
192 | } | ||
193 | |||
126 | public string ScriptEngineName | 194 | public string ScriptEngineName |
127 | { | 195 | { |
128 | get { return "XEngine"; } | 196 | get { return "XEngine"; } |
@@ -262,43 +330,45 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
262 | 330 | ||
263 | public void RemoveRegion(Scene scene) | 331 | public void RemoveRegion(Scene scene) |
264 | { | 332 | { |
265 | lock (m_Scripts) | 333 | lockScriptsForRead(true); |
334 | foreach (IScriptInstance instance in m_Scripts.Values) | ||
266 | { | 335 | { |
267 | foreach (IScriptInstance instance in m_Scripts.Values) | 336 | // Force a final state save |
337 | // | ||
338 | if (m_Assemblies.ContainsKey(instance.AssetID)) | ||
268 | { | 339 | { |
269 | // Force a final state save | 340 | string assembly = m_Assemblies[instance.AssetID]; |
270 | // | 341 | instance.SaveState(assembly); |
271 | if (m_Assemblies.ContainsKey(instance.AssetID)) | 342 | } |
272 | { | ||
273 | string assembly = m_Assemblies[instance.AssetID]; | ||
274 | instance.SaveState(assembly); | ||
275 | } | ||
276 | 343 | ||
277 | // Clear the event queue and abort the instance thread | 344 | // Clear the event queue and abort the instance thread |
278 | // | 345 | // |
279 | instance.ClearQueue(); | 346 | instance.ClearQueue(); |
280 | instance.Stop(0); | 347 | instance.Stop(0); |
281 | 348 | ||
282 | // Release events, timer, etc | 349 | // Release events, timer, etc |
283 | // | 350 | // |
284 | instance.DestroyScriptInstance(); | 351 | instance.DestroyScriptInstance(); |
285 | 352 | ||
286 | // Unload scripts and app domains | 353 | // Unload scripts and app domains |
287 | // Must be done explicitly because they have infinite | 354 | // Must be done explicitly because they have infinite |
288 | // lifetime | 355 | // lifetime |
289 | // | 356 | // |
290 | m_DomainScripts[instance.AppDomain].Remove(instance.ItemID); | 357 | m_DomainScripts[instance.AppDomain].Remove(instance.ItemID); |
291 | if (m_DomainScripts[instance.AppDomain].Count == 0) | 358 | if (m_DomainScripts[instance.AppDomain].Count == 0) |
292 | { | 359 | { |
293 | m_DomainScripts.Remove(instance.AppDomain); | 360 | m_DomainScripts.Remove(instance.AppDomain); |
294 | UnloadAppDomain(instance.AppDomain); | 361 | UnloadAppDomain(instance.AppDomain); |
295 | } | ||
296 | } | 362 | } |
297 | m_Scripts.Clear(); | ||
298 | m_PrimObjects.Clear(); | ||
299 | m_Assemblies.Clear(); | ||
300 | m_DomainScripts.Clear(); | ||
301 | } | 363 | } |
364 | lockScriptsForRead(false); | ||
365 | lockScriptsForWrite(true); | ||
366 | m_Scripts.Clear(); | ||
367 | lockScriptsForWrite(false); | ||
368 | m_PrimObjects.Clear(); | ||
369 | m_Assemblies.Clear(); | ||
370 | m_DomainScripts.Clear(); | ||
371 | |||
302 | lock (m_ScriptEngines) | 372 | lock (m_ScriptEngines) |
303 | { | 373 | { |
304 | m_ScriptEngines.Remove(this); | 374 | m_ScriptEngines.Remove(this); |
@@ -357,22 +427,20 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
357 | 427 | ||
358 | List<IScriptInstance> instances = new List<IScriptInstance>(); | 428 | List<IScriptInstance> instances = new List<IScriptInstance>(); |
359 | 429 | ||
360 | lock (m_Scripts) | 430 | lockScriptsForRead(true); |
361 | { | 431 | foreach (IScriptInstance instance in m_Scripts.Values) |
362 | foreach (IScriptInstance instance in m_Scripts.Values) | ||
363 | instances.Add(instance); | 432 | instances.Add(instance); |
364 | } | 433 | lockScriptsForRead(false); |
365 | 434 | ||
366 | foreach (IScriptInstance i in instances) | 435 | foreach (IScriptInstance i in instances) |
367 | { | 436 | { |
368 | string assembly = String.Empty; | 437 | string assembly = String.Empty; |
369 | 438 | ||
370 | lock (m_Scripts) | 439 | |
371 | { | ||
372 | if (!m_Assemblies.ContainsKey(i.AssetID)) | 440 | if (!m_Assemblies.ContainsKey(i.AssetID)) |
373 | continue; | 441 | continue; |
374 | assembly = m_Assemblies[i.AssetID]; | 442 | assembly = m_Assemblies[i.AssetID]; |
375 | } | 443 | |
376 | 444 | ||
377 | i.SaveState(assembly); | 445 | i.SaveState(assembly); |
378 | } | 446 | } |
@@ -684,172 +752,183 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
684 | } | 752 | } |
685 | } | 753 | } |
686 | 754 | ||
687 | lock (m_Scripts) | 755 | |
756 | |||
757 | ScriptInstance instance = null; | ||
758 | // Create the object record | ||
759 | lockScriptsForRead(true); | ||
760 | if ((!m_Scripts.ContainsKey(itemID)) || | ||
761 | (m_Scripts[itemID].AssetID != assetID)) | ||
688 | { | 762 | { |
689 | ScriptInstance instance = null; | 763 | lockScriptsForRead(false); |
690 | // Create the object record | ||
691 | 764 | ||
692 | if ((!m_Scripts.ContainsKey(itemID)) || | 765 | UUID appDomain = assetID; |
693 | (m_Scripts[itemID].AssetID != assetID)) | ||
694 | { | ||
695 | UUID appDomain = assetID; | ||
696 | 766 | ||
697 | if (part.ParentGroup.IsAttachment) | 767 | if (part.ParentGroup.IsAttachment) |
698 | appDomain = part.ParentGroup.RootPart.UUID; | 768 | appDomain = part.ParentGroup.RootPart.UUID; |
699 | 769 | ||
700 | if (!m_AppDomains.ContainsKey(appDomain)) | 770 | if (!m_AppDomains.ContainsKey(appDomain)) |
771 | { | ||
772 | try | ||
701 | { | 773 | { |
702 | try | 774 | AppDomainSetup appSetup = new AppDomainSetup(); |
703 | { | 775 | // appSetup.ApplicationBase = Path.Combine( |
704 | AppDomainSetup appSetup = new AppDomainSetup(); | 776 | // "ScriptEngines", |
705 | // appSetup.ApplicationBase = Path.Combine( | 777 | // m_Scene.RegionInfo.RegionID.ToString()); |
706 | // "ScriptEngines", | 778 | |
707 | // m_Scene.RegionInfo.RegionID.ToString()); | 779 | Evidence baseEvidence = AppDomain.CurrentDomain.Evidence; |
708 | 780 | Evidence evidence = new Evidence(baseEvidence); | |
709 | Evidence baseEvidence = AppDomain.CurrentDomain.Evidence; | 781 | |
710 | Evidence evidence = new Evidence(baseEvidence); | 782 | AppDomain sandbox; |
711 | 783 | if (m_AppDomainLoading) | |
712 | AppDomain sandbox; | 784 | sandbox = AppDomain.CreateDomain( |
713 | if (m_AppDomainLoading) | 785 | m_Scene.RegionInfo.RegionID.ToString(), |
714 | sandbox = AppDomain.CreateDomain( | 786 | evidence, appSetup); |
715 | m_Scene.RegionInfo.RegionID.ToString(), | 787 | else |
716 | evidence, appSetup); | 788 | sandbox = AppDomain.CurrentDomain; |
717 | else | 789 | |
718 | sandbox = AppDomain.CurrentDomain; | 790 | //PolicyLevel sandboxPolicy = PolicyLevel.CreateAppDomainLevel(); |
719 | 791 | //AllMembershipCondition sandboxMembershipCondition = new AllMembershipCondition(); | |
720 | //PolicyLevel sandboxPolicy = PolicyLevel.CreateAppDomainLevel(); | 792 | //PermissionSet sandboxPermissionSet = sandboxPolicy.GetNamedPermissionSet("Internet"); |
721 | //AllMembershipCondition sandboxMembershipCondition = new AllMembershipCondition(); | 793 | //PolicyStatement sandboxPolicyStatement = new PolicyStatement(sandboxPermissionSet); |
722 | //PermissionSet sandboxPermissionSet = sandboxPolicy.GetNamedPermissionSet("Internet"); | 794 | //CodeGroup sandboxCodeGroup = new UnionCodeGroup(sandboxMembershipCondition, sandboxPolicyStatement); |
723 | //PolicyStatement sandboxPolicyStatement = new PolicyStatement(sandboxPermissionSet); | 795 | //sandboxPolicy.RootCodeGroup = sandboxCodeGroup; |
724 | //CodeGroup sandboxCodeGroup = new UnionCodeGroup(sandboxMembershipCondition, sandboxPolicyStatement); | 796 | //sandbox.SetAppDomainPolicy(sandboxPolicy); |
725 | //sandboxPolicy.RootCodeGroup = sandboxCodeGroup; | 797 | |
726 | //sandbox.SetAppDomainPolicy(sandboxPolicy); | 798 | m_AppDomains[appDomain] = sandbox; |
727 | 799 | ||
728 | m_AppDomains[appDomain] = sandbox; | 800 | m_AppDomains[appDomain].AssemblyResolve += |
729 | 801 | new ResolveEventHandler( | |
730 | m_AppDomains[appDomain].AssemblyResolve += | 802 | AssemblyResolver.OnAssemblyResolve); |
731 | new ResolveEventHandler( | 803 | m_DomainScripts[appDomain] = new List<UUID>(); |
732 | AssemblyResolver.OnAssemblyResolve); | ||
733 | m_DomainScripts[appDomain] = new List<UUID>(); | ||
734 | } | ||
735 | catch (Exception e) | ||
736 | { | ||
737 | m_log.ErrorFormat("[XEngine] Exception creating app domain:\n {0}", e.ToString()); | ||
738 | m_ScriptErrorMessage += "Exception creating app domain:\n"; | ||
739 | m_ScriptFailCount++; | ||
740 | lock (m_AddingAssemblies) | ||
741 | { | ||
742 | m_AddingAssemblies[assembly]--; | ||
743 | } | ||
744 | return false; | ||
745 | } | ||
746 | } | 804 | } |
747 | m_DomainScripts[appDomain].Add(itemID); | 805 | catch (Exception e) |
748 | |||
749 | instance = new ScriptInstance(this, part, | ||
750 | itemID, assetID, assembly, | ||
751 | m_AppDomains[appDomain], | ||
752 | part.ParentGroup.RootPart.Name, | ||
753 | item.Name, startParam, postOnRez, | ||
754 | stateSource, m_MaxScriptQueue); | ||
755 | |||
756 | m_log.DebugFormat("[XEngine] Loaded script {0}.{1}, script UUID {2}, prim UUID {3} @ {4}", | ||
757 | part.ParentGroup.RootPart.Name, item.Name, assetID, part.UUID, part.ParentGroup.RootPart.AbsolutePosition.ToString()); | ||
758 | |||
759 | if (presence != null) | ||
760 | { | 806 | { |
761 | ShowScriptSaveResponse(item.OwnerID, | 807 | m_log.ErrorFormat("[XEngine] Exception creating app domain:\n {0}", e.ToString()); |
762 | assetID, "Compile successful", true); | 808 | m_ScriptErrorMessage += "Exception creating app domain:\n"; |
809 | m_ScriptFailCount++; | ||
810 | lock (m_AddingAssemblies) | ||
811 | { | ||
812 | m_AddingAssemblies[assembly]--; | ||
813 | } | ||
814 | return false; | ||
763 | } | 815 | } |
816 | } | ||
817 | m_DomainScripts[appDomain].Add(itemID); | ||
764 | 818 | ||
765 | instance.AppDomain = appDomain; | 819 | instance = new ScriptInstance(this, part, |
766 | instance.LineMap = linemap; | 820 | itemID, assetID, assembly, |
821 | m_AppDomains[appDomain], | ||
822 | part.ParentGroup.RootPart.Name, | ||
823 | item.Name, startParam, postOnRez, | ||
824 | stateSource, m_MaxScriptQueue); | ||
767 | 825 | ||
768 | m_Scripts[itemID] = instance; | 826 | m_log.DebugFormat("[XEngine] Loaded script {0}.{1}, script UUID {2}, prim UUID {3} @ {4}", |
769 | } | 827 | part.ParentGroup.RootPart.Name, item.Name, assetID, part.UUID, part.ParentGroup.RootPart.AbsolutePosition.ToString()); |
770 | 828 | ||
771 | lock (m_PrimObjects) | 829 | if (presence != null) |
772 | { | 830 | { |
773 | if (!m_PrimObjects.ContainsKey(localID)) | 831 | ShowScriptSaveResponse(item.OwnerID, |
774 | m_PrimObjects[localID] = new List<UUID>(); | 832 | assetID, "Compile successful", true); |
833 | } | ||
775 | 834 | ||
776 | if (!m_PrimObjects[localID].Contains(itemID)) | 835 | instance.AppDomain = appDomain; |
777 | m_PrimObjects[localID].Add(itemID); | 836 | instance.LineMap = linemap; |
837 | lockScriptsForWrite(true); | ||
838 | m_Scripts[itemID] = instance; | ||
839 | lockScriptsForWrite(false); | ||
840 | } | ||
841 | else | ||
842 | { | ||
843 | lockScriptsForRead(false); | ||
844 | } | ||
845 | lock (m_PrimObjects) | ||
846 | { | ||
847 | if (!m_PrimObjects.ContainsKey(localID)) | ||
848 | m_PrimObjects[localID] = new List<UUID>(); | ||
778 | 849 | ||
779 | } | 850 | if (!m_PrimObjects[localID].Contains(itemID)) |
851 | m_PrimObjects[localID].Add(itemID); | ||
780 | 852 | ||
781 | if (!m_Assemblies.ContainsKey(assetID)) | 853 | } |
782 | m_Assemblies[assetID] = assembly; | ||
783 | 854 | ||
784 | lock (m_AddingAssemblies) | 855 | if (!m_Assemblies.ContainsKey(assetID)) |
785 | { | 856 | m_Assemblies[assetID] = assembly; |
786 | m_AddingAssemblies[assembly]--; | ||
787 | } | ||
788 | 857 | ||
789 | if (instance!=null) | 858 | lock (m_AddingAssemblies) |
790 | instance.Init(); | 859 | { |
860 | m_AddingAssemblies[assembly]--; | ||
791 | } | 861 | } |
862 | |||
863 | if (instance!=null) | ||
864 | instance.Init(); | ||
865 | |||
792 | return true; | 866 | return true; |
793 | } | 867 | } |
794 | 868 | ||
795 | public void OnRemoveScript(uint localID, UUID itemID) | 869 | public void OnRemoveScript(uint localID, UUID itemID) |
796 | { | 870 | { |
797 | lock (m_Scripts) | 871 | lockScriptsForRead(true); |
872 | // Do we even have it? | ||
873 | if (!m_Scripts.ContainsKey(itemID)) | ||
798 | { | 874 | { |
799 | // Do we even have it? | 875 | lockScriptsForRead(false); |
800 | if (!m_Scripts.ContainsKey(itemID)) | 876 | return; |
801 | return; | 877 | } |
802 | 878 | ||
803 | IScriptInstance instance=m_Scripts[itemID]; | ||
804 | m_Scripts.Remove(itemID); | ||
805 | 879 | ||
806 | instance.ClearQueue(); | 880 | IScriptInstance instance=m_Scripts[itemID]; |
807 | instance.Stop(0); | 881 | lockScriptsForRead(false); |
882 | lockScriptsForWrite(true); | ||
883 | m_Scripts.Remove(itemID); | ||
884 | lockScriptsForWrite(false); | ||
885 | instance.ClearQueue(); | ||
886 | instance.Stop(0); | ||
808 | 887 | ||
809 | SceneObjectPart part = | 888 | SceneObjectPart part = |
810 | m_Scene.GetSceneObjectPart(localID); | 889 | m_Scene.GetSceneObjectPart(localID); |
811 | 890 | ||
812 | if (part != null) | 891 | if (part != null) |
813 | part.RemoveScriptEvents(itemID); | 892 | part.RemoveScriptEvents(itemID); |
814 | 893 | ||
815 | // bool objectRemoved = false; | 894 | // bool objectRemoved = false; |
816 | 895 | ||
817 | lock (m_PrimObjects) | 896 | lock (m_PrimObjects) |
897 | { | ||
898 | // Remove the script from it's prim | ||
899 | if (m_PrimObjects.ContainsKey(localID)) | ||
818 | { | 900 | { |
819 | // Remove the script from it's prim | 901 | // Remove inventory item record |
820 | if (m_PrimObjects.ContainsKey(localID)) | 902 | if (m_PrimObjects[localID].Contains(itemID)) |
821 | { | 903 | m_PrimObjects[localID].Remove(itemID); |
822 | // Remove inventory item record | ||
823 | if (m_PrimObjects[localID].Contains(itemID)) | ||
824 | m_PrimObjects[localID].Remove(itemID); | ||
825 | 904 | ||
826 | // If there are no more scripts, remove prim | 905 | // If there are no more scripts, remove prim |
827 | if (m_PrimObjects[localID].Count == 0) | 906 | if (m_PrimObjects[localID].Count == 0) |
828 | { | 907 | { |
829 | m_PrimObjects.Remove(localID); | 908 | m_PrimObjects.Remove(localID); |
830 | // objectRemoved = true; | 909 | // objectRemoved = true; |
831 | } | ||
832 | } | 910 | } |
833 | } | 911 | } |
912 | } | ||
834 | 913 | ||
835 | instance.RemoveState(); | 914 | instance.RemoveState(); |
836 | instance.DestroyScriptInstance(); | 915 | instance.DestroyScriptInstance(); |
837 | 916 | ||
838 | m_DomainScripts[instance.AppDomain].Remove(instance.ItemID); | 917 | m_DomainScripts[instance.AppDomain].Remove(instance.ItemID); |
839 | if (m_DomainScripts[instance.AppDomain].Count == 0) | 918 | if (m_DomainScripts[instance.AppDomain].Count == 0) |
840 | { | 919 | { |
841 | m_DomainScripts.Remove(instance.AppDomain); | 920 | m_DomainScripts.Remove(instance.AppDomain); |
842 | UnloadAppDomain(instance.AppDomain); | 921 | UnloadAppDomain(instance.AppDomain); |
843 | } | 922 | } |
844 | 923 | ||
845 | instance = null; | 924 | instance = null; |
846 | 925 | ||
847 | ObjectRemoved handlerObjectRemoved = OnObjectRemoved; | 926 | ObjectRemoved handlerObjectRemoved = OnObjectRemoved; |
848 | if (handlerObjectRemoved != null) | 927 | if (handlerObjectRemoved != null) |
849 | handlerObjectRemoved(part.UUID); | 928 | handlerObjectRemoved(part.UUID); |
850 | 929 | ||
851 | CleanAssemblies(); | 930 | CleanAssemblies(); |
852 | } | 931 | |
853 | 932 | ||
854 | ScriptRemoved handlerScriptRemoved = OnScriptRemoved; | 933 | ScriptRemoved handlerScriptRemoved = OnScriptRemoved; |
855 | if (handlerScriptRemoved != null) | 934 | if (handlerScriptRemoved != null) |
@@ -1102,12 +1181,14 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1102 | private IScriptInstance GetInstance(UUID itemID) | 1181 | private IScriptInstance GetInstance(UUID itemID) |
1103 | { | 1182 | { |
1104 | IScriptInstance instance; | 1183 | IScriptInstance instance; |
1105 | lock (m_Scripts) | 1184 | lockScriptsForRead(true); |
1185 | if (!m_Scripts.ContainsKey(itemID)) | ||
1106 | { | 1186 | { |
1107 | if (!m_Scripts.ContainsKey(itemID)) | 1187 | lockScriptsForRead(false); |
1108 | return null; | 1188 | return null; |
1109 | instance = m_Scripts[itemID]; | ||
1110 | } | 1189 | } |
1190 | instance = m_Scripts[itemID]; | ||
1191 | lockScriptsForRead(false); | ||
1111 | return instance; | 1192 | return instance; |
1112 | } | 1193 | } |
1113 | 1194 | ||
@@ -1131,6 +1212,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1131 | return false; | 1212 | return false; |
1132 | } | 1213 | } |
1133 | 1214 | ||
1215 | [DebuggerNonUserCode] | ||
1134 | public void ApiResetScript(UUID itemID) | 1216 | public void ApiResetScript(UUID itemID) |
1135 | { | 1217 | { |
1136 | IScriptInstance instance = GetInstance(itemID); | 1218 | IScriptInstance instance = GetInstance(itemID); |
@@ -1182,6 +1264,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1182 | return UUID.Zero; | 1264 | return UUID.Zero; |
1183 | } | 1265 | } |
1184 | 1266 | ||
1267 | [DebuggerNonUserCode] | ||
1185 | public void SetState(UUID itemID, string newState) | 1268 | public void SetState(UUID itemID, string newState) |
1186 | { | 1269 | { |
1187 | IScriptInstance instance = GetInstance(itemID); | 1270 | IScriptInstance instance = GetInstance(itemID); |
@@ -1202,11 +1285,10 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1202 | { | 1285 | { |
1203 | List<IScriptInstance> instances = new List<IScriptInstance>(); | 1286 | List<IScriptInstance> instances = new List<IScriptInstance>(); |
1204 | 1287 | ||
1205 | lock (m_Scripts) | 1288 | lockScriptsForRead(true); |
1206 | { | 1289 | foreach (IScriptInstance instance in m_Scripts.Values) |
1207 | foreach (IScriptInstance instance in m_Scripts.Values) | ||
1208 | instances.Add(instance); | 1290 | instances.Add(instance); |
1209 | } | 1291 | lockScriptsForRead(false); |
1210 | 1292 | ||
1211 | foreach (IScriptInstance i in instances) | 1293 | foreach (IScriptInstance i in instances) |
1212 | { | 1294 | { |