aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim')
-rw-r--r--OpenSim/Framework/IScene.cs5
-rw-r--r--OpenSim/Region/Application/OpenSim.cs2
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs59
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs29
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs4
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs20
-rw-r--r--OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs19
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs5
-rw-r--r--OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs2
-rwxr-xr-xOpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs161
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs19
-rw-r--r--OpenSim/Region/CoreModules/World/Access/AccessModule.cs10
-rw-r--r--OpenSim/Region/Framework/Interfaces/IRegionReadyModule.cs11
-rw-r--r--OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs8
-rw-r--r--OpenSim/Region/Framework/Scenes/EventManager.cs51
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs95
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneBase.cs18
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneGraph.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresence.cs27
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs302
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs2
-rwxr-xr-xOpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs2
-rw-r--r--OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs130
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs69
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs187
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs331
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs137
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs51
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs28
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs16
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs14
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs5
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs7
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs1
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs5
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Helpers.cs34
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs14
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/XEngine.cs22
-rw-r--r--OpenSim/Tests/Common/Helpers/SceneHelpers.cs2
41 files changed, 1287 insertions, 623 deletions
diff --git a/OpenSim/Framework/IScene.cs b/OpenSim/Framework/IScene.cs
index a9432c2..2c38e0f 100644
--- a/OpenSim/Framework/IScene.cs
+++ b/OpenSim/Framework/IScene.cs
@@ -66,6 +66,11 @@ namespace OpenSim.Framework
66 66
67 IConfigSource Config { get; } 67 IConfigSource Config { get; }
68 68
69 /// <summary>
70 /// Are logins enabled on this simulator?
71 /// </summary>
72 bool LoginsEnabled { get; set; }
73
69 float TimeDilation { get; } 74 float TimeDilation { get; }
70 75
71 bool AllowScriptCrossings { get; } 76 bool AllowScriptCrossings { get; }
diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs
index e6b57c2..8a0b4ab 100644
--- a/OpenSim/Region/Application/OpenSim.cs
+++ b/OpenSim/Region/Application/OpenSim.cs
@@ -1145,8 +1145,8 @@ namespace OpenSim
1145 c => cdt.AddRow( 1145 c => cdt.AddRow(
1146 s.Name, 1146 s.Name,
1147 c.Name, 1147 c.Name,
1148 c.RemoteEndPoint.ToString(),
1149 c.CircuitCode.ToString(), 1148 c.CircuitCode.ToString(),
1149 c.RemoteEndPoint.ToString(),
1150 c.IsActive.ToString()))); 1150 c.IsActive.ToString())));
1151 1151
1152 MainConsole.Instance.Output(cdt.ToString()); 1152 MainConsole.Instance.Output(cdt.ToString());
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
index ad9074c..098e4eb 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -355,8 +355,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
355 private int m_animationSequenceNumber = 1; 355 private int m_animationSequenceNumber = 1;
356 private bool m_SendLogoutPacketWhenClosing = true; 356 private bool m_SendLogoutPacketWhenClosing = true;
357 private AgentUpdateArgs lastarg; 357 private AgentUpdateArgs lastarg;
358 private bool m_IsActive = true;
359 private bool m_IsLoggingOut = false;
360 358
361 protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>(); 359 protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>();
362 protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers 360 protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers
@@ -428,16 +426,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
428 public uint CircuitCode { get { return m_circuitCode; } } 426 public uint CircuitCode { get { return m_circuitCode; } }
429 public int MoneyBalance { get { return m_moneyBalance; } } 427 public int MoneyBalance { get { return m_moneyBalance; } }
430 public int NextAnimationSequenceNumber { get { return m_animationSequenceNumber++; } } 428 public int NextAnimationSequenceNumber { get { return m_animationSequenceNumber++; } }
431 public bool IsActive 429
432 { 430 /// <summary>
433 get { return m_IsActive; } 431 /// As well as it's function in IClientAPI, in LLClientView we are locking on this property in order to
434 set { m_IsActive = value; } 432 /// prevent race conditions by different threads calling Close().
435 } 433 /// </summary>
436 public bool IsLoggingOut 434 public bool IsActive { get; set; }
437 { 435
438 get { return m_IsLoggingOut; } 436 /// <summary>
439 set { m_IsLoggingOut = value; } 437 /// Used to synchronise threads when client is being closed.
440 } 438 /// </summary>
439 public Object CloseSyncLock { get; private set; }
440
441 public bool IsLoggingOut { get; set; }
441 442
442 public bool DisableFacelights 443 public bool DisableFacelights
443 { 444 {
@@ -462,6 +463,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
462 { 463 {
463// DebugPacketLevel = 1; 464// DebugPacketLevel = 1;
464 465
466 CloseSyncLock = new Object();
467
465 RegisterInterface<IClientIM>(this); 468 RegisterInterface<IClientIM>(this);
466 RegisterInterface<IClientInventory>(this); 469 RegisterInterface<IClientInventory>(this);
467 RegisterInterface<IClientChat>(this); 470 RegisterInterface<IClientChat>(this);
@@ -494,13 +497,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
494 m_prioritizer = new Prioritizer(m_scene); 497 m_prioritizer = new Prioritizer(m_scene);
495 498
496 RegisterLocalPacketHandlers(); 499 RegisterLocalPacketHandlers();
500
501 IsActive = true;
497 } 502 }
498 503
499 #region Client Methods 504 #region Client Methods
500 505
501 506
502 /// <summary> 507 /// <summary>
503 /// Shut down the client view 508 /// Close down the client view
504 /// </summary> 509 /// </summary>
505 public void Close() 510 public void Close()
506 { 511 {
@@ -513,7 +518,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP
513 public void Close(bool sendStop) 518 public void Close(bool sendStop)
514 { 519 {
515 IsActive = false; 520 IsActive = false;
521 // We lock here to prevent race conditions between two threads calling close simultaneously (e.g.
522 // a simultaneous relog just as a client is being closed out due to no packet ack from the old connection.
523 lock (CloseSyncLock)
524 {
525 if (!IsActive)
526 return;
527
528 IsActive = false;
529 CloseWithoutChecks(sendStop);
530 }
531 }
516 532
533 /// <summary>
534 /// Closes down the client view without first checking whether it is active.
535 /// </summary>
536 /// <remarks>
537 /// This exists because LLUDPServer has to set IsActive = false in earlier synchronous code before calling
538 /// CloseWithoutIsActiveCheck asynchronously.
539 ///
540 /// Callers must lock ClosingSyncLock before calling.
541 /// </remarks>
542 public void CloseWithoutChecks(bool sendStop)
543 {
517 m_log.DebugFormat( 544 m_log.DebugFormat(
518 "[CLIENT]: Close has been called for {0} attached to scene {1}", 545 "[CLIENT]: Close has been called for {0} attached to scene {1}",
519 Name, m_scene.RegionInfo.RegionName); 546 Name, m_scene.RegionInfo.RegionName);
@@ -3634,7 +3661,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3634 3661
3635 public void SendCoarseLocationUpdate(List<UUID> users, List<Vector3> CoarseLocations) 3662 public void SendCoarseLocationUpdate(List<UUID> users, List<Vector3> CoarseLocations)
3636 { 3663 {
3637 if (!IsActive) return; // We don't need to update inactive clients. 3664 // We don't need to update inactive clients.
3665 if (!IsActive)
3666 return;
3638 3667
3639 CoarseLocationUpdatePacket loc = (CoarseLocationUpdatePacket)PacketPool.Instance.GetPacket(PacketType.CoarseLocationUpdate); 3668 CoarseLocationUpdatePacket loc = (CoarseLocationUpdatePacket)PacketPool.Instance.GetPacket(PacketType.CoarseLocationUpdate);
3640 loc.Header.Reliable = false; 3669 loc.Header.Reliable = false;
@@ -5267,7 +5296,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5267 AddLocalPacketHandler(PacketType.ChatFromViewer, HandleChatFromViewer); 5296 AddLocalPacketHandler(PacketType.ChatFromViewer, HandleChatFromViewer);
5268 AddLocalPacketHandler(PacketType.AvatarPropertiesUpdate, HandlerAvatarPropertiesUpdate); 5297 AddLocalPacketHandler(PacketType.AvatarPropertiesUpdate, HandlerAvatarPropertiesUpdate);
5269 AddLocalPacketHandler(PacketType.ScriptDialogReply, HandlerScriptDialogReply); 5298 AddLocalPacketHandler(PacketType.ScriptDialogReply, HandlerScriptDialogReply);
5270 AddLocalPacketHandler(PacketType.ImprovedInstantMessage, HandlerImprovedInstantMessage, false); 5299 AddLocalPacketHandler(PacketType.ImprovedInstantMessage, HandlerImprovedInstantMessage);
5271 AddLocalPacketHandler(PacketType.AcceptFriendship, HandlerAcceptFriendship); 5300 AddLocalPacketHandler(PacketType.AcceptFriendship, HandlerAcceptFriendship);
5272 AddLocalPacketHandler(PacketType.DeclineFriendship, HandlerDeclineFriendship); 5301 AddLocalPacketHandler(PacketType.DeclineFriendship, HandlerDeclineFriendship);
5273 AddLocalPacketHandler(PacketType.TerminateFriendship, HandlerTerminateFriendship); 5302 AddLocalPacketHandler(PacketType.TerminateFriendship, HandlerTerminateFriendship);
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
index f5f9c02..86d8f62 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
@@ -1181,22 +1181,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1181 /// regular client pings. 1181 /// regular client pings.
1182 /// </remarks> 1182 /// </remarks>
1183 /// <param name='client'></param> 1183 /// <param name='client'></param>
1184 private void DeactivateClientDueToTimeout(IClientAPI client) 1184 private void DeactivateClientDueToTimeout(LLClientView client)
1185 { 1185 {
1186 // We must set IsActive synchronously so that we can stop the packet loop reinvoking this method, even 1186 lock (client.CloseSyncLock)
1187 // though it's set later on by LLClientView.Close() 1187 {
1188 client.IsActive = false; 1188 m_log.WarnFormat(
1189 1189 "[LLUDPSERVER]: Ack timeout, disconnecting {0} agent for {1} in {2}",
1190 m_log.WarnFormat( 1190 client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, m_scene.RegionInfo.RegionName);
1191 "[LLUDPSERVER]: Ack timeout, disconnecting {0} agent for {1} in {2}", 1191
1192 client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, m_scene.RegionInfo.RegionName); 1192 StatsManager.SimExtraStats.AddAbnormalClientThreadTermination();
1193 1193
1194 StatsManager.SimExtraStats.AddAbnormalClientThreadTermination(); 1194 if (!client.SceneAgent.IsChildAgent)
1195 1195 client.Kick("Simulator logged you out due to connection timeout");
1196 if (!client.SceneAgent.IsChildAgent) 1196
1197 client.Kick("Simulator logged you out due to connection timeout"); 1197 client.CloseWithoutChecks(true);
1198 1198 }
1199 Util.FireAndForget(o => client.Close());
1200 } 1199 }
1201 1200
1202 private void IncomingPacketHandler() 1201 private void IncomingPacketHandler()
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
index 31e8a2e..b588704 100644
--- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
@@ -626,10 +626,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
626 626
627 m_scene.InventoryService.UpdateItem(item); 627 m_scene.InventoryService.UpdateItem(item);
628 628
629 // this gets called when the agent logs off! 629 // If the name of the object has been changed whilst attached then we want to update the inventory
630 // item in the viewer.
630 if (sp.ControllingClient != null) 631 if (sp.ControllingClient != null)
631 sp.ControllingClient.SendInventoryItemCreateUpdate(item, 0); 632 sp.ControllingClient.SendInventoryItemCreateUpdate(item, 0);
632 } 633 }
634
633 grp.HasGroupChanged = false; // Prevent it being saved over and over 635 grp.HasGroupChanged = false; // Prevent it being saved over and over
634 } 636 }
635// else 637// else
diff --git a/OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs b/OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs
index 31363e5..b258e13 100644
--- a/OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs
@@ -96,7 +96,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Groups
96 96
97 scene.EventManager.OnNewClient += OnNewClient; 97 scene.EventManager.OnNewClient += OnNewClient;
98 scene.EventManager.OnClientClosed += OnClientClosed; 98 scene.EventManager.OnClientClosed += OnClientClosed;
99 scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage; 99// scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage;
100 } 100 }
101 101
102 public void PostInitialise() 102 public void PostInitialise()
@@ -133,7 +133,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Groups
133 private void OnNewClient(IClientAPI client) 133 private void OnNewClient(IClientAPI client)
134 { 134 {
135 // Subscribe to instant messages 135 // Subscribe to instant messages
136 client.OnInstantMessage += OnInstantMessage; 136// client.OnInstantMessage += OnInstantMessage;
137 client.OnAgentDataUpdateRequest += OnAgentDataUpdateRequest; 137 client.OnAgentDataUpdateRequest += OnAgentDataUpdateRequest;
138 client.OnUUIDGroupNameRequest += HandleUUIDGroupNameRequest; 138 client.OnUUIDGroupNameRequest += HandleUUIDGroupNameRequest;
139 lock (m_ClientMap) 139 lock (m_ClientMap)
@@ -171,15 +171,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Groups
171 ActiveGroupTitle); 171 ActiveGroupTitle);
172 } 172 }
173 173
174 private void OnInstantMessage(IClientAPI client, GridInstantMessage im) 174// private void OnInstantMessage(IClientAPI client, GridInstantMessage im)
175 { 175// {
176 } 176// }
177 177
178 private void OnGridInstantMessage(GridInstantMessage msg) 178// private void OnGridInstantMessage(GridInstantMessage msg)
179 { 179// {
180 // Trigger the above event handler 180// // Trigger the above event handler
181 OnInstantMessage(null, msg); 181// OnInstantMessage(null, msg);
182 } 182// }
183 183
184 private void HandleUUIDGroupNameRequest(UUID id,IClientAPI remote_client) 184 private void HandleUUIDGroupNameRequest(UUID id,IClientAPI remote_client)
185 { 185 {
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs
index 6064ddc..1406aae 100644
--- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs
@@ -141,13 +141,15 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
141 foreach (Scene scene in m_Scenes) 141 foreach (Scene scene in m_Scenes)
142 { 142 {
143// m_log.DebugFormat( 143// m_log.DebugFormat(
144// "[INSTANT MESSAGE]: Looking for root agent {0} in {1}", 144// "[INSTANT MESSAGE]: Looking for root agent {0} in {1}",
145// toAgentID.ToString(), scene.RegionInfo.RegionName); 145// toAgentID.ToString(), scene.RegionInfo.RegionName);
146
146 ScenePresence sp = scene.GetScenePresence(toAgentID); 147 ScenePresence sp = scene.GetScenePresence(toAgentID);
147 if (sp != null && !sp.IsChildAgent) 148 if (sp != null && !sp.IsChildAgent)
148 { 149 {
149 // Local message 150 // Local message
150// m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to root agent {0} {1}", user.Name, toAgentID); 151 m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to root agent {0} {1}", sp.Name, toAgentID);
152
151 sp.ControllingClient.SendInstantMessage(im); 153 sp.ControllingClient.SendInstantMessage(im);
152 154
153 // Message sent 155 // Message sent
@@ -159,13 +161,15 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
159 // try child avatar second 161 // try child avatar second
160 foreach (Scene scene in m_Scenes) 162 foreach (Scene scene in m_Scenes)
161 { 163 {
162// m_log.DebugFormat( 164 m_log.DebugFormat(
163// "[INSTANT MESSAGE]: Looking for child of {0} in {1}", toAgentID, scene.RegionInfo.RegionName); 165 "[INSTANT MESSAGE]: Looking for child of {0} in {1}", toAgentID, scene.RegionInfo.RegionName);
166
164 ScenePresence sp = scene.GetScenePresence(toAgentID); 167 ScenePresence sp = scene.GetScenePresence(toAgentID);
165 if (sp != null) 168 if (sp != null)
166 { 169 {
167 // Local message 170 // Local message
168// m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to child agent {0} {1}", user.Name, toAgentID); 171 m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to child agent {0} {1}", sp.Name, toAgentID);
172
169 sp.ControllingClient.SendInstantMessage(im); 173 sp.ControllingClient.SendInstantMessage(im);
170 174
171 // Message sent 175 // Message sent
@@ -174,10 +178,9 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
174 } 178 }
175 } 179 }
176 180
177// m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to {0} via XMLRPC", im.toAgentID); 181 m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to {0} via XMLRPC", im.toAgentID);
178 SendGridInstantMessageViaXMLRPC(im, result);
179 182
180 return; 183 SendGridInstantMessageViaXMLRPC(im, result);
181 } 184 }
182 185
183 private void HandleUndeliveredMessage(GridInstantMessage im, MessageResultNotification result) 186 private void HandleUndeliveredMessage(GridInstantMessage im, MessageResultNotification result)
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs
index 80554fb..81de29c 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs
@@ -313,8 +313,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
313 m_TransferModule.SendInstantMessage(im, delegate(bool success) {}); 313 m_TransferModule.SendInstantMessage(im, delegate(bool success) {});
314 } 314 }
315 } 315 }
316 else if (im.dialog == (byte) InstantMessageDialog.InventoryDeclined || 316 else if (
317 im.dialog == (byte) InstantMessageDialog.TaskInventoryDeclined) 317 im.dialog == (byte)InstantMessageDialog.InventoryDeclined
318 || im.dialog == (byte)InstantMessageDialog.TaskInventoryDeclined)
318 { 319 {
319 // Here, the recipient is local and we can assume that the 320 // Here, the recipient is local and we can assume that the
320 // inventory is loaded. Courtesy of the above bulk update, 321 // inventory is loaded. Courtesy of the above bulk update,
diff --git a/OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs b/OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs
index a75ff62..fb74cc6 100644
--- a/OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs
@@ -39,7 +39,7 @@ using OpenSim.Region.Framework;
39using OpenSim.Region.Framework.Interfaces; 39using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Region.Framework.Scenes; 40using OpenSim.Region.Framework.Scenes;
41 41
42namespace OpenSim.Region.CoreModules.Avatar.Attachments 42namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging
43{ 43{
44 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "BinaryLoggingModule")] 44 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "BinaryLoggingModule")]
45 public class BinaryLoggingModule : INonSharedRegionModule 45 public class BinaryLoggingModule : INonSharedRegionModule
diff --git a/OpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs b/OpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs
new file mode 100755
index 0000000..65e4c90
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs
@@ -0,0 +1,161 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.IO;
30using System.Text;
31using log4net;
32
33namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging
34{
35 /// <summary>
36 /// Class for writing a high performance, high volume log file.
37 /// Sometimes, to debug, one has a high volume logging to do and the regular
38 /// log file output is not appropriate.
39 /// Create a new instance with the parameters needed and
40 /// call Write() to output a line. Call Close() when finished.
41 /// If created with no parameters, it will not log anything.
42 /// </summary>
43 public class LogWriter : IDisposable
44 {
45 public bool Enabled { get; private set; }
46
47 private string m_logDirectory = ".";
48 private int m_logMaxFileTimeMin = 5; // 5 minutes
49 public String LogFileHeader { get; set; }
50
51 private StreamWriter m_logFile = null;
52 private TimeSpan m_logFileLife;
53 private DateTime m_logFileEndTime;
54 private Object m_logFileWriteLock = new Object();
55
56 // set externally when debugging. If let 'null', this does not write any error messages.
57 public ILog ErrorLogger = null;
58 private string LogHeader = "[LOG WRITER]";
59
60 /// <summary>
61 /// Create a log writer that will not write anything. Good for when not enabled
62 /// but the write statements are still in the code.
63 /// </summary>
64 public LogWriter()
65 {
66 Enabled = false;
67 m_logFile = null;
68 }
69
70 /// <summary>
71 /// Create a log writer instance.
72 /// </summary>
73 /// <param name="dir">The directory to create the log file in. May be 'null' for default.</param>
74 /// <param name="headr">The characters that begin the log file name. May be 'null' for default.</param>
75 /// <param name="maxFileTime">Maximum age of a log file in minutes. If zero, will set default.</param>
76 public LogWriter(string dir, string headr, int maxFileTime)
77 {
78 m_logDirectory = dir == null ? "." : dir;
79
80 LogFileHeader = headr == null ? "log-" : headr;
81
82 m_logMaxFileTimeMin = maxFileTime;
83 if (m_logMaxFileTimeMin < 1)
84 m_logMaxFileTimeMin = 5;
85
86 m_logFileLife = new TimeSpan(0, m_logMaxFileTimeMin, 0);
87 m_logFileEndTime = DateTime.Now + m_logFileLife;
88
89 Enabled = true;
90 }
91
92 public void Dispose()
93 {
94 this.Close();
95 }
96
97 public void Close()
98 {
99 Enabled = false;
100 if (m_logFile != null)
101 {
102 m_logFile.Close();
103 m_logFile.Dispose();
104 m_logFile = null;
105 }
106 }
107
108 public void Write(string line, params object[] args)
109 {
110 if (!Enabled) return;
111 Write(String.Format(line, args));
112 }
113
114 public void Write(string line)
115 {
116 if (!Enabled) return;
117 try
118 {
119 lock (m_logFileWriteLock)
120 {
121 DateTime now = DateTime.Now;
122 if (m_logFile == null || now > m_logFileEndTime)
123 {
124 if (m_logFile != null)
125 {
126 m_logFile.Close();
127 m_logFile.Dispose();
128 m_logFile = null;
129 }
130
131 // First log file or time has expired, start writing to a new log file
132 m_logFileEndTime = now + m_logFileLife;
133 string path = (m_logDirectory.Length > 0 ? m_logDirectory
134 + System.IO.Path.DirectorySeparatorChar.ToString() : "")
135 + String.Format("{0}{1}.log", LogFileHeader, now.ToString("yyyyMMddHHmmss"));
136 m_logFile = new StreamWriter(File.Open(path, FileMode.Append, FileAccess.Write));
137 }
138 if (m_logFile != null)
139 {
140 StringBuilder buff = new StringBuilder(line.Length + 25);
141 buff.Append(now.ToString("yyyyMMddHHmmssfff"));
142 // buff.Append(now.ToString("yyyyMMddHHmmss"));
143 buff.Append(",");
144 buff.Append(line);
145 buff.Append("\r\n");
146 m_logFile.Write(buff.ToString());
147 }
148 }
149 }
150 catch (Exception e)
151 {
152 if (ErrorLogger != null)
153 {
154 ErrorLogger.ErrorFormat("{0}: FAILURE WRITING TO LOGFILE: {1}", LogHeader, e);
155 }
156 Enabled = false;
157 }
158 return;
159 }
160 }
161} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs
index 6cd077a..7ed1320 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs
@@ -149,10 +149,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage
149 lock (m_scenes) 149 lock (m_scenes)
150 m_scenes[scene.RegionInfo.RegionID] = scene; 150 m_scenes[scene.RegionInfo.RegionID] = scene;
151 151
152 scene.EventManager.OnLoginsEnabled += OnLoginsEnabled; 152 scene.EventManager.OnRegionReady += s => UploadMapTile(s);
153 } 153 }
154 154
155
156 ///<summary> 155 ///<summary>
157 /// 156 ///
158 ///</summary> 157 ///</summary>
@@ -166,21 +165,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage
166 } 165 }
167 166
168 #endregion ISharedRegionModule 167 #endregion ISharedRegionModule
169 168
170 void OnLoginsEnabled(string regionName)
171 {
172 Scene scene = null;
173 foreach (Scene s in m_scenes.Values)
174 if (s.RegionInfo.RegionName == regionName)
175 {
176 scene = s;
177 break;
178 }
179 if (scene != null)
180 UploadMapTile(scene);
181 }
182
183
184 ///<summary> 169 ///<summary>
185 /// 170 ///
186 ///</summary> 171 ///</summary>
diff --git a/OpenSim/Region/CoreModules/World/Access/AccessModule.cs b/OpenSim/Region/CoreModules/World/Access/AccessModule.cs
index 553a32d..e7b1454 100644
--- a/OpenSim/Region/CoreModules/World/Access/AccessModule.cs
+++ b/OpenSim/Region/CoreModules/World/Access/AccessModule.cs
@@ -129,18 +129,18 @@ namespace OpenSim.Region.CoreModules.World
129 switch (cmd[1]) 129 switch (cmd[1])
130 { 130 {
131 case "enable": 131 case "enable":
132 scene.LoginsDisabled = false; 132 scene.LoginsEnabled = true;
133 MainConsole.Instance.Output(String.Format("Logins are enabled for region {0}", scene.RegionInfo.RegionName)); 133 MainConsole.Instance.Output(String.Format("Logins are enabled for region {0}", scene.RegionInfo.RegionName));
134 break; 134 break;
135 case "disable": 135 case "disable":
136 scene.LoginsDisabled = true; 136 scene.LoginsEnabled = false;
137 MainConsole.Instance.Output(String.Format("Logins are disabled for region {0}", scene.RegionInfo.RegionName)); 137 MainConsole.Instance.Output(String.Format("Logins are disabled for region {0}", scene.RegionInfo.RegionName));
138 break; 138 break;
139 case "status": 139 case "status":
140 if (scene.LoginsDisabled) 140 if (scene.LoginsEnabled)
141 MainConsole.Instance.Output(String.Format("Login in {0} are disabled", scene.RegionInfo.RegionName));
142 else
143 MainConsole.Instance.Output(String.Format("Login in {0} are enabled", scene.RegionInfo.RegionName)); 141 MainConsole.Instance.Output(String.Format("Login in {0} are enabled", scene.RegionInfo.RegionName));
142 else
143 MainConsole.Instance.Output(String.Format("Login in {0} are disabled", scene.RegionInfo.RegionName));
144 break; 144 break;
145 default: 145 default:
146 MainConsole.Instance.Output("Syntax: login enable|disable|status"); 146 MainConsole.Instance.Output("Syntax: login enable|disable|status");
diff --git a/OpenSim/Region/Framework/Interfaces/IRegionReadyModule.cs b/OpenSim/Region/Framework/Interfaces/IRegionReadyModule.cs
index aa4a757..136ca92 100644
--- a/OpenSim/Region/Framework/Interfaces/IRegionReadyModule.cs
+++ b/OpenSim/Region/Framework/Interfaces/IRegionReadyModule.cs
@@ -25,14 +25,23 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28
29using System; 28using System;
29using OpenSim.Framework;
30 30
31namespace OpenSim.Region.Framework.Interfaces 31namespace OpenSim.Region.Framework.Interfaces
32{ 32{
33 public interface IRegionReadyModule 33 public interface IRegionReadyModule
34 { 34 {
35 void OarLoadingAlert(string msg); 35 void OarLoadingAlert(string msg);
36
37 /// <summary>
38 /// Trigger region ready status manually.
39 /// </summary>
40 /// <remarks>
41 /// This should be called by the scene if the IRegionReadyModule has set Scene.LoginLock == true
42 /// </remarks>
43 /// <param name='scene'></param>
44 void TriggerRegionReady(IScene scene);
36 } 45 }
37} 46}
38 47
diff --git a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs
index 9ddac19..50a176b 100644
--- a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs
+++ b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs
@@ -551,11 +551,5 @@ namespace OpenSim.Region.Framework.Scenes.Animation
551 551
552 SendAnimPack(animIDs, sequenceNums, objectIDs); 552 SendAnimPack(animIDs, sequenceNums, objectIDs);
553 } 553 }
554
555 public void Close()
556 {
557 m_animations = null;
558 m_scenePresence = null;
559 }
560 } 554 }
561} 555} \ No newline at end of file
diff --git a/OpenSim/Region/Framework/Scenes/EventManager.cs b/OpenSim/Region/Framework/Scenes/EventManager.cs
index d783e57..418904f 100644
--- a/OpenSim/Region/Framework/Scenes/EventManager.cs
+++ b/OpenSim/Region/Framework/Scenes/EventManager.cs
@@ -500,15 +500,25 @@ namespace OpenSim.Region.Framework.Scenes
500 public delegate void RegionHeartbeatEnd(Scene scene); 500 public delegate void RegionHeartbeatEnd(Scene scene);
501 public event RegionHeartbeatEnd OnRegionHeartbeatEnd; 501 public event RegionHeartbeatEnd OnRegionHeartbeatEnd;
502 502
503 public delegate void LoginsEnabled(string regionName); 503 /// <summary>
504 /// Fired when logins to a region are enabled or disabled.
505 /// </summary>
506 /// <remarks>
507 ///
508 /// </remarks>
509 /// Fired
510 public event RegionLoginsStatusChange OnRegionLoginsStatusChange;
511 public delegate void RegionLoginsStatusChange(IScene scene);
504 512
505 /// <summary> 513 /// <summary>
506 /// This should only fire in all circumstances if the RegionReady module is active. 514 /// Fired when a region is considered ready for use.
507 /// </summary> 515 /// </summary>
508 /// <remarks> 516 /// <remarks>
509 /// TODO: Fire this even when the RegionReady module is not active. 517 /// A region is considered ready when startup operations such as loading of scripts already on the region
518 /// have been completed.
510 /// </remarks> 519 /// </remarks>
511 public event LoginsEnabled OnLoginsEnabled; 520 public event RegionReady OnRegionReady;
521 public delegate void RegionReady(IScene scene);
512 522
513 public delegate void PrimsLoaded(Scene s); 523 public delegate void PrimsLoaded(Scene s);
514 public event PrimsLoaded OnPrimsLoaded; 524 public event PrimsLoaded OnPrimsLoaded;
@@ -2502,21 +2512,42 @@ namespace OpenSim.Region.Framework.Scenes
2502 } 2512 }
2503 } 2513 }
2504 2514
2505 public void TriggerLoginsEnabled (string regionName) 2515 public void TriggerRegionLoginsStatusChange(IScene scene)
2506 { 2516 {
2507 LoginsEnabled handler = OnLoginsEnabled; 2517 RegionLoginsStatusChange handler = OnRegionLoginsStatusChange;
2508 2518
2509 if ( handler != null) 2519 if (handler != null)
2510 { 2520 {
2511 foreach (LoginsEnabled d in handler.GetInvocationList()) 2521 foreach (RegionLoginsStatusChange d in handler.GetInvocationList())
2512 { 2522 {
2513 try 2523 try
2514 { 2524 {
2515 d(regionName); 2525 d(scene);
2526 }
2527 catch (Exception e)
2528 {
2529 m_log.ErrorFormat("[EVENT MANAGER]: Delegate for OnRegionLoginsStatusChange failed - continuing {0} - {1}",
2530 e.Message, e.StackTrace);
2531 }
2532 }
2533 }
2534 }
2535
2536 public void TriggerRegionReady(IScene scene)
2537 {
2538 RegionReady handler = OnRegionReady;
2539
2540 if (handler != null)
2541 {
2542 foreach (RegionReady d in handler.GetInvocationList())
2543 {
2544 try
2545 {
2546 d(scene);
2516 } 2547 }
2517 catch (Exception e) 2548 catch (Exception e)
2518 { 2549 {
2519 m_log.ErrorFormat("[EVENT MANAGER]: Delegate for LoginsEnabled failed - continuing {0} - {1}", 2550 m_log.ErrorFormat("[EVENT MANAGER]: Delegate for OnRegionReady failed - continuing {0} - {1}",
2520 e.Message, e.StackTrace); 2551 e.Message, e.StackTrace);
2521 } 2552 }
2522 } 2553 }
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index ad9e91d..0bf2259 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -129,9 +129,10 @@ namespace OpenSim.Region.Framework.Scenes
129 public bool m_strictAccessControl = true; 129 public bool m_strictAccessControl = true;
130 public bool m_seeIntoBannedRegion = false; 130 public bool m_seeIntoBannedRegion = false;
131 public int MaxUndoCount = 5; 131 public int MaxUndoCount = 5;
132
132 // Using this for RegionReady module to prevent LoginsDisabled from changing under our feet; 133 // Using this for RegionReady module to prevent LoginsDisabled from changing under our feet;
133 public bool LoginLock = false; 134 public bool LoginLock = false;
134 public bool LoginsDisabled = true; 135
135 public bool StartDisabled = false; 136 public bool StartDisabled = false;
136 public bool LoadingPrims; 137 public bool LoadingPrims;
137 public IXfer XferManager; 138 public IXfer XferManager;
@@ -727,6 +728,8 @@ namespace OpenSim.Region.Framework.Scenes
727 { 728 {
728 IConfig startupConfig = m_config.Configs["Startup"]; 729 IConfig startupConfig = m_config.Configs["Startup"];
729 730
731 StartDisabled = startupConfig.GetBoolean("StartDisabled", false);
732
730 m_defaultDrawDistance = startupConfig.GetFloat("DefaultDrawDistance",m_defaultDrawDistance); 733 m_defaultDrawDistance = startupConfig.GetFloat("DefaultDrawDistance",m_defaultDrawDistance);
731 m_useBackup = startupConfig.GetBoolean("UseSceneBackup", m_useBackup); 734 m_useBackup = startupConfig.GetBoolean("UseSceneBackup", m_useBackup);
732 if (!m_useBackup) 735 if (!m_useBackup)
@@ -1530,7 +1533,7 @@ namespace OpenSim.Region.Framework.Scenes
1530 // landMS = Util.EnvironmentTickCountSubtract(ldMS); 1533 // landMS = Util.EnvironmentTickCountSubtract(ldMS);
1531 //} 1534 //}
1532 1535
1533 if (LoginsDisabled && Frame == 20) 1536 if (!LoginsEnabled && Frame == 20)
1534 { 1537 {
1535 // m_log.DebugFormat("{0} {1} {2}", LoginsDisabled, m_sceneGraph.GetActiveScriptsCount(), LoginLock); 1538 // m_log.DebugFormat("{0} {1} {2}", LoginsDisabled, m_sceneGraph.GetActiveScriptsCount(), LoginLock);
1536 1539
@@ -1538,31 +1541,34 @@ namespace OpenSim.Region.Framework.Scenes
1538 // this is a rare case where we know we have just went through a long cycle of heap 1541 // this is a rare case where we know we have just went through a long cycle of heap
1539 // allocations, and there is no more work to be done until someone logs in 1542 // allocations, and there is no more work to be done until someone logs in
1540 GC.Collect(); 1543 GC.Collect();
1541 1544
1542 IConfig startupConfig = m_config.Configs["Startup"]; 1545 if (!LoginLock)
1543 if (startupConfig == null || !startupConfig.GetBoolean("StartDisabled", false))
1544 { 1546 {
1545 // This handles a case of a region having no scripts for the RegionReady module 1547 if (!StartDisabled)
1546 if (m_sceneGraph.GetActiveScriptsCount() == 0)
1547 {
1548 // need to be able to tell these have changed in RegionReady
1549 LoginLock = false;
1550 EventManager.TriggerLoginsEnabled(RegionInfo.RegionName);
1551 }
1552
1553 // For RegionReady lockouts
1554 if (!LoginLock)
1555 { 1548 {
1556 m_log.InfoFormat("[REGION]: Enabling logins for {0}", RegionInfo.RegionName); 1549 m_log.InfoFormat("[REGION]: Enabling logins for {0}", RegionInfo.RegionName);
1557 LoginsDisabled = false; 1550 LoginsEnabled = true;
1558 } 1551 }
1559 1552
1560 m_sceneGridService.InformNeighborsThatRegionisUp(RequestModuleInterface<INeighbourService>(), RegionInfo); 1553 m_sceneGridService.InformNeighborsThatRegionisUp(
1554 RequestModuleInterface<INeighbourService>(), RegionInfo);
1555
1556 // Region ready should always be triggered whether logins are immediately enabled or not.
1557 EventManager.TriggerRegionReady(this);
1561 } 1558 }
1562 else 1559 else
1563 { 1560 {
1564 StartDisabled = true; 1561 // This handles a case of a region having no scripts for the RegionReady module
1565 LoginsDisabled = true; 1562 if (m_sceneGraph.GetActiveScriptsCount() == 0)
1563 {
1564 // In this case, we leave it to the IRegionReadyModule to enable logins
1565
1566 // LoginLock can currently only be set by a region module implementation.
1567 // If somehow this hasn't been done then the quickest way to bugfix is to see the
1568 // NullReferenceException
1569 IRegionReadyModule rrm = RequestModuleInterface<IRegionReadyModule>();
1570 rrm.TriggerRegionReady(this);
1571 }
1566 } 1572 }
1567 } 1573 }
1568 } 1574 }
@@ -3477,25 +3483,31 @@ namespace OpenSim.Region.Framework.Scenes
3477 if (AgentTransactionsModule != null) 3483 if (AgentTransactionsModule != null)
3478 AgentTransactionsModule.RemoveAgentAssetTransactions(agentID); 3484 AgentTransactionsModule.RemoveAgentAssetTransactions(agentID);
3479 3485
3480 avatar.Close();
3481
3482 m_authenticateHandler.RemoveCircuit(avatar.ControllingClient.CircuitCode); 3486 m_authenticateHandler.RemoveCircuit(avatar.ControllingClient.CircuitCode);
3483 m_log.Debug("[Scene] The avatar has left the building"); 3487 m_log.Debug("[Scene] The avatar has left the building");
3484 } 3488 }
3485 catch (Exception e) 3489 catch (Exception e)
3486 { 3490 {
3487 m_log.Error( 3491 m_log.Error(
3488 string.Format("[SCENE]: Exception removing {0} from {1}, ", avatar.Name, RegionInfo.RegionName), e); 3492 string.Format("[SCENE]: Exception removing {0} from {1}. Cleaning up. Exception ", avatar.Name, Name), e);
3489 } 3493 }
3490 finally 3494 finally
3491 { 3495 {
3492 // Always clean these structures up so that any failure above doesn't cause them to remain in the 3496 try
3493 // scene with possibly bad effects (e.g. continually timing out on unacked packets and triggering 3497 {
3494 // the same cleanup exception continually. 3498 // Always clean these structures up so that any failure above doesn't cause them to remain in the
3495 // TODO: This should probably extend to the whole method, but we don't want to also catch the NRE 3499 // scene with possibly bad effects (e.g. continually timing out on unacked packets and triggering
3496 // since this would hide the underlying failure and other associated problems. 3500 // the same cleanup exception continually.
3497 m_sceneGraph.RemoveScenePresence(agentID); 3501 m_sceneGraph.RemoveScenePresence(agentID);
3498 m_clientManager.Remove(agentID); 3502 m_clientManager.Remove(agentID);
3503
3504 avatar.Close();
3505 }
3506 catch (Exception e)
3507 {
3508 m_log.Error(
3509 string.Format("[SCENE]: Exception in final clean up of {0} in {1}. Exception ", avatar.Name, Name), e);
3510 }
3499 } 3511 }
3500 3512
3501 //m_log.InfoFormat("[SCENE] Memory pre GC {0}", System.GC.GetTotalMemory(false)); 3513 //m_log.InfoFormat("[SCENE] Memory pre GC {0}", System.GC.GetTotalMemory(false));
@@ -3609,7 +3621,7 @@ namespace OpenSim.Region.Framework.Scenes
3609 agent.startpos 3621 agent.startpos
3610 ); 3622 );
3611 3623
3612 if (LoginsDisabled) 3624 if (!LoginsEnabled)
3613 { 3625 {
3614 reason = "Logins Disabled"; 3626 reason = "Logins Disabled";
3615 return false; 3627 return false;
@@ -3666,8 +3678,8 @@ namespace OpenSim.Region.Framework.Scenes
3666 // We have a zombie from a crashed session. 3678 // We have a zombie from a crashed session.
3667 // Or the same user is trying to be root twice here, won't work. 3679 // Or the same user is trying to be root twice here, won't work.
3668 // Kill it. 3680 // Kill it.
3669 m_log.DebugFormat( 3681 m_log.WarnFormat(
3670 "[SCENE]: Zombie scene presence detected for {0} {1} in {2}", 3682 "[SCENE]: Existing root scene presence detected for {0} {1} in {2} when connecting. Removing existing presence.",
3671 sp.Name, sp.UUID, RegionInfo.RegionName); 3683 sp.Name, sp.UUID, RegionInfo.RegionName);
3672 3684
3673 sp.ControllingClient.Close(); 3685 sp.ControllingClient.Close();
@@ -4658,6 +4670,23 @@ namespace OpenSim.Region.Framework.Scenes
4658 } 4670 }
4659 4671
4660 /// <summary> 4672 /// <summary>
4673 /// Gets all the scene presences in this scene.
4674 /// </summary>
4675 /// <remarks>
4676 /// This method will return both root and child scene presences.
4677 ///
4678 /// Consider using ForEachScenePresence() or ForEachRootScenePresence() if possible since these will not
4679 /// involving creating a new List object.
4680 /// </remarks>
4681 /// <returns>
4682 /// A list of the scene presences. Adding or removing from the list will not affect the presences in the scene.
4683 /// </returns>
4684 public List<ScenePresence> GetScenePresences()
4685 {
4686 return new List<ScenePresence>(m_sceneGraph.GetScenePresences());
4687 }
4688
4689 /// <summary>
4661 /// Performs action on all avatars in the scene (root scene presences) 4690 /// Performs action on all avatars in the scene (root scene presences)
4662 /// Avatars may be an NPC or a 'real' client. 4691 /// Avatars may be an NPC or a 'real' client.
4663 /// </summary> 4692 /// </summary>
diff --git a/OpenSim/Region/Framework/Scenes/SceneBase.cs b/OpenSim/Region/Framework/Scenes/SceneBase.cs
index 8db4397..d55b082 100644
--- a/OpenSim/Region/Framework/Scenes/SceneBase.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneBase.cs
@@ -106,6 +106,24 @@ namespace OpenSim.Region.Framework.Scenes
106 106
107 protected readonly ClientManager m_clientManager = new ClientManager(); 107 protected readonly ClientManager m_clientManager = new ClientManager();
108 108
109 public bool LoginsEnabled
110 {
111 get
112 {
113 return m_loginsEnabled;
114 }
115
116 set
117 {
118 if (m_loginsEnabled != value)
119 {
120 m_loginsEnabled = value;
121 EventManager.TriggerRegionLoginsStatusChange(this);
122 }
123 }
124 }
125 private bool m_loginsEnabled;
126
109 public float TimeDilation 127 public float TimeDilation
110 { 128 {
111 get { return 1.0f; } 129 get { return 1.0f; }
diff --git a/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs b/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs
index 5d8447b..775a4c2 100644
--- a/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs
@@ -100,7 +100,7 @@ namespace OpenSim.Region.Framework.Scenes
100 { 100 {
101 m_log.WarnFormat( 101 m_log.WarnFormat(
102 "[SCENE COMMUNICATION SERVICE]: Region {0} failed to inform neighbour at {1}-{2} that it is up.", 102 "[SCENE COMMUNICATION SERVICE]: Region {0} failed to inform neighbour at {1}-{2} that it is up.",
103 x / Constants.RegionSize, y / Constants.RegionSize); 103 m_scene.Name, x / Constants.RegionSize, y / Constants.RegionSize);
104 } 104 }
105 } 105 }
106 106
diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
index c3d66eb..e0260e2 100644
--- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
@@ -848,7 +848,7 @@ namespace OpenSim.Region.Framework.Scenes
848 /// pass a delegate to ForEachScenePresence. 848 /// pass a delegate to ForEachScenePresence.
849 /// </summary> 849 /// </summary>
850 /// <returns></returns> 850 /// <returns></returns>
851 private List<ScenePresence> GetScenePresences() 851 protected internal List<ScenePresence> GetScenePresences()
852 { 852 {
853 return m_scenePresenceArray; 853 return m_scenePresenceArray;
854 } 854 }
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 6ab0027..08c7a58 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -1991,7 +1991,7 @@ namespace OpenSim.Region.Framework.Scenes
1991 try 1991 try
1992 { 1992 {
1993 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart 1993 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
1994 m_scene.LoginsDisabled || // We're starting up or doing maintenance, don't mess with things 1994 !m_scene.LoginsEnabled || // We're starting up or doing maintenance, don't mess with things
1995 m_scene.LoadingPrims) // Land may not be valid yet 1995 m_scene.LoadingPrims) // Land may not be valid yet
1996 1996
1997 { 1997 {
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index e27d309..5cff3f0 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -110,15 +110,10 @@ namespace OpenSim.Region.Framework.Scenes
110 110
111 public UUID currentParcelUUID = UUID.Zero; 111 public UUID currentParcelUUID = UUID.Zero;
112 112
113 protected ScenePresenceAnimator m_animator;
114 /// <value> 113 /// <value>
115 /// The animator for this avatar 114 /// The animator for this avatar
116 /// </value> 115 /// </value>
117 public ScenePresenceAnimator Animator 116 public ScenePresenceAnimator Animator { get; private set; }
118 {
119 get { return m_animator; }
120 private set { m_animator = value; }
121 }
122 117
123 /// <summary> 118 /// <summary>
124 /// Attachments recorded on this avatar. 119 /// Attachments recorded on this avatar.
@@ -2761,8 +2756,7 @@ namespace OpenSim.Region.Framework.Scenes
2761 //m_log.DebugFormat("[SCENE PRESENCE] SendAvatarDataToAgent from {0} ({1}) to {2} ({3})", Name, UUID, avatar.Name, avatar.UUID); 2756 //m_log.DebugFormat("[SCENE PRESENCE] SendAvatarDataToAgent from {0} ({1}) to {2} ({3})", Name, UUID, avatar.Name, avatar.UUID);
2762 2757
2763 avatar.ControllingClient.SendAvatarDataImmediate(this); 2758 avatar.ControllingClient.SendAvatarDataImmediate(this);
2764 if (Animator != null) 2759 Animator.SendAnimPackToClient(avatar.ControllingClient);
2765 Animator.SendAnimPackToClient(avatar.ControllingClient);
2766 } 2760 }
2767 2761
2768 /// <summary> 2762 /// <summary>
@@ -3438,6 +3432,16 @@ namespace OpenSim.Region.Framework.Scenes
3438 if (IsChildAgent) 3432 if (IsChildAgent)
3439 return; 3433 return;
3440 3434
3435 //if ((Math.Abs(Velocity.X) > 0.1e-9f) || (Math.Abs(Velocity.Y) > 0.1e-9f))
3436 // The Physics Scene will send updates every 500 ms grep: PhysicsActor.SubscribeEvents(
3437 // as of this comment the interval is set in AddToPhysicalScene
3438
3439// if (m_updateCount > 0)
3440// {
3441 Animator.UpdateMovementAnimations();
3442// m_updateCount--;
3443// }
3444
3441 CollisionEventUpdate collisionData = (CollisionEventUpdate)e; 3445 CollisionEventUpdate collisionData = (CollisionEventUpdate)e;
3442 Dictionary<uint, ContactPoint> coldata = collisionData.m_objCollisionList; 3446 Dictionary<uint, ContactPoint> coldata = collisionData.m_objCollisionList;
3443 3447
@@ -3451,7 +3455,7 @@ namespace OpenSim.Region.Framework.Scenes
3451// m_lastColCount = coldata.Count; 3455// m_lastColCount = coldata.Count;
3452// } 3456// }
3453 3457
3454 if (coldata.Count != 0 && Animator != null) 3458 if (coldata.Count != 0)
3455 { 3459 {
3456 switch (Animator.CurrentMovementAnimation) 3460 switch (Animator.CurrentMovementAnimation)
3457 { 3461 {
@@ -3563,7 +3567,7 @@ namespace OpenSim.Region.Framework.Scenes
3563 ControllingClient.SendHealth(Health); 3567 ControllingClient.SendHealth(Health);
3564 } 3568 }
3565 3569
3566 public void Close() 3570 protected internal void Close()
3567 { 3571 {
3568 // Clear known regions 3572 // Clear known regions
3569 KnownRegions = new Dictionary<ulong, string>(); 3573 KnownRegions = new Dictionary<ulong, string>();
@@ -3579,9 +3583,6 @@ namespace OpenSim.Region.Framework.Scenes
3579 // m_reprioritizationTimer.Dispose(); 3583 // m_reprioritizationTimer.Dispose();
3580 3584
3581 RemoveFromPhysicalScene(); 3585 RemoveFromPhysicalScene();
3582 if(Animator != null)
3583 Animator.Close();
3584 Animator = null;
3585 } 3586 }
3586 3587
3587 public void AddAttachment(SceneObjectGroup gobj) 3588 public void AddAttachment(SceneObjectGroup gobj)
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs
index 02c45ef..5758869 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs
@@ -53,62 +53,94 @@ namespace OpenSim.Region.Framework.Scenes.Tests
53 /// Scene presence tests 53 /// Scene presence tests
54 /// </summary> 54 /// </summary>
55 [TestFixture] 55 [TestFixture]
56 public class ScenePresenceAgentTests 56 public class ScenePresenceAgentTests : OpenSimTestCase
57 { 57 {
58 public Scene scene, scene2, scene3; 58// public Scene scene, scene2, scene3;
59 public UUID agent1, agent2, agent3; 59// public UUID agent1, agent2, agent3;
60 public static Random random; 60// public static Random random;
61 public ulong region1,region2,region3; 61// public ulong region1, region2, region3;
62 public AgentCircuitData acd1; 62// public AgentCircuitData acd1;
63 public SceneObjectGroup sog1, sog2, sog3; 63// public TestClient testclient;
64 public TestClient testclient; 64
65 65// [TestFixtureSetUp]
66 [TestFixtureSetUp] 66// public void Init()
67 public void Init() 67// {
68//// TestHelpers.InMethod();
69////
70//// SceneHelpers sh = new SceneHelpers();
71////
72//// scene = sh.SetupScene("Neighbour x", UUID.Random(), 1000, 1000);
73//// scene2 = sh.SetupScene("Neighbour x+1", UUID.Random(), 1001, 1000);
74//// scene3 = sh.SetupScene("Neighbour x-1", UUID.Random(), 999, 1000);
75////
76//// ISharedRegionModule interregionComms = new LocalSimulationConnectorModule();
77//// interregionComms.Initialise(new IniConfigSource());
78//// interregionComms.PostInitialise();
79//// SceneHelpers.SetupSceneModules(scene, new IniConfigSource(), interregionComms);
80//// SceneHelpers.SetupSceneModules(scene2, new IniConfigSource(), interregionComms);
81//// SceneHelpers.SetupSceneModules(scene3, new IniConfigSource(), interregionComms);
82//
83//// agent1 = UUID.Random();
84//// agent2 = UUID.Random();
85//// agent3 = UUID.Random();
86//
87//// region1 = scene.RegionInfo.RegionHandle;
88//// region2 = scene2.RegionInfo.RegionHandle;
89//// region3 = scene3.RegionInfo.RegionHandle;
90// }
91
92 [Test]
93 public void TestCreateRootScenePresence()
68 { 94 {
69 TestHelpers.InMethod(); 95 TestHelpers.InMethod();
96// TestHelpers.EnableLogging();
97
98 UUID spUuid = TestHelpers.ParseTail(0x1);
70 99
71 SceneHelpers sh = new SceneHelpers(); 100 TestScene scene = new SceneHelpers().SetupScene();
72 101 SceneHelpers.AddScenePresence(scene, spUuid);
73 scene = sh.SetupScene("Neighbour x", UUID.Random(), 1000, 1000); 102
74 scene2 = sh.SetupScene("Neighbour x+1", UUID.Random(), 1001, 1000); 103 Assert.That(scene.AuthenticateHandler.GetAgentCircuitData(spUuid), Is.Not.Null);
75 scene3 = sh.SetupScene("Neighbour x-1", UUID.Random(), 999, 1000); 104 Assert.That(scene.AuthenticateHandler.GetAgentCircuits().Count, Is.EqualTo(1));
76 105
77 ISharedRegionModule interregionComms = new LocalSimulationConnectorModule(); 106 ScenePresence sp = scene.GetScenePresence(spUuid);
78 interregionComms.Initialise(new IniConfigSource()); 107 Assert.That(sp, Is.Not.Null);
79 interregionComms.PostInitialise(); 108 Assert.That(sp.IsChildAgent, Is.False);
80 SceneHelpers.SetupSceneModules(scene, new IniConfigSource(), interregionComms); 109 Assert.That(sp.UUID, Is.EqualTo(spUuid));
81 SceneHelpers.SetupSceneModules(scene2, new IniConfigSource(), interregionComms); 110
82 SceneHelpers.SetupSceneModules(scene3, new IniConfigSource(), interregionComms); 111 Assert.That(scene.GetScenePresences().Count, Is.EqualTo(1));
83
84 agent1 = UUID.Random();
85 agent2 = UUID.Random();
86 agent3 = UUID.Random();
87 random = new Random();
88 sog1 = SceneHelpers.CreateSceneObject(1, agent1);
89 scene.AddSceneObject(sog1);
90 sog2 = SceneHelpers.CreateSceneObject(1, agent1);
91 scene.AddSceneObject(sog2);
92 sog3 = SceneHelpers.CreateSceneObject(1, agent1);
93 scene.AddSceneObject(sog3);
94
95 region1 = scene.RegionInfo.RegionHandle;
96 region2 = scene2.RegionInfo.RegionHandle;
97 region3 = scene3.RegionInfo.RegionHandle;
98 } 112 }
99 113
100 [Test] 114 [Test]
101 public void TestCloseAgent() 115 public void TestCreateDuplicateRootScenePresence()
102 { 116 {
103 TestHelpers.InMethod(); 117 TestHelpers.InMethod();
104// TestHelpers.EnableLogging(); 118// TestHelpers.EnableLogging();
105 119
120 UUID spUuid = TestHelpers.ParseTail(0x1);
121
106 TestScene scene = new SceneHelpers().SetupScene(); 122 TestScene scene = new SceneHelpers().SetupScene();
107 ScenePresence sp = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseTail(0x1)); 123 SceneHelpers.AddScenePresence(scene, spUuid);
124 SceneHelpers.AddScenePresence(scene, spUuid);
108 125
109 Assert.That(scene.AuthenticateHandler.GetAgentCircuitData(sp.UUID), Is.Not.Null); 126 Assert.That(scene.AuthenticateHandler.GetAgentCircuitData(spUuid), Is.Not.Null);
110 Assert.That(scene.AuthenticateHandler.GetAgentCircuits().Count, Is.EqualTo(1)); 127 Assert.That(scene.AuthenticateHandler.GetAgentCircuits().Count, Is.EqualTo(1));
111 128
129 ScenePresence sp = scene.GetScenePresence(spUuid);
130 Assert.That(sp, Is.Not.Null);
131 Assert.That(sp.IsChildAgent, Is.False);
132 Assert.That(sp.UUID, Is.EqualTo(spUuid));
133 }
134
135 [Test]
136 public void TestCloseAgent()
137 {
138 TestHelpers.InMethod();
139// TestHelpers.EnableLogging();
140
141 TestScene scene = new SceneHelpers().SetupScene();
142 ScenePresence sp = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseTail(0x1));
143
112 scene.IncomingCloseAgent(sp.UUID); 144 scene.IncomingCloseAgent(sp.UUID);
113 145
114 Assert.That(scene.GetScenePresence(sp.UUID), Is.Null); 146 Assert.That(scene.GetScenePresence(sp.UUID), Is.Null);
@@ -266,99 +298,99 @@ namespace OpenSim.Region.Framework.Scenes.Tests
266 // but things are synchronous among them. So there should be 298 // but things are synchronous among them. So there should be
267 // 3 threads in here. 299 // 3 threads in here.
268 //[Test] 300 //[Test]
269 public void T021_TestCrossToNewRegion() 301// public void T021_TestCrossToNewRegion()
270 { 302// {
271 TestHelpers.InMethod(); 303// TestHelpers.InMethod();
272 304//
273 scene.RegisterRegionWithGrid(); 305// scene.RegisterRegionWithGrid();
274 scene2.RegisterRegionWithGrid(); 306// scene2.RegisterRegionWithGrid();
275 307//
276 // Adding child agent to region 1001 308// // Adding child agent to region 1001
277 string reason; 309// string reason;
278 scene2.NewUserConnection(acd1,0, out reason); 310// scene2.NewUserConnection(acd1,0, out reason);
279 scene2.AddNewClient(testclient, PresenceType.User); 311// scene2.AddNewClient(testclient, PresenceType.User);
280 312//
281 ScenePresence presence = scene.GetScenePresence(agent1); 313// ScenePresence presence = scene.GetScenePresence(agent1);
282 presence.MakeRootAgent(new Vector3(0,unchecked(Constants.RegionSize-1),0), true); 314// presence.MakeRootAgent(new Vector3(0,unchecked(Constants.RegionSize-1),0), true);
283 315//
284 ScenePresence presence2 = scene2.GetScenePresence(agent1); 316// ScenePresence presence2 = scene2.GetScenePresence(agent1);
285 317//
286 // Adding neighbour region caps info to presence2 318// // Adding neighbour region caps info to presence2
287 319//
288 string cap = presence.ControllingClient.RequestClientInfo().CapsPath; 320// string cap = presence.ControllingClient.RequestClientInfo().CapsPath;
289 presence2.AddNeighbourRegion(region1, cap); 321// presence2.AddNeighbourRegion(region1, cap);
290 322//
291 Assert.That(presence.IsChildAgent, Is.False, "Did not start root in origin region."); 323// Assert.That(presence.IsChildAgent, Is.False, "Did not start root in origin region.");
292 Assert.That(presence2.IsChildAgent, Is.True, "Is not a child on destination region."); 324// Assert.That(presence2.IsChildAgent, Is.True, "Is not a child on destination region.");
293 325//
294 // Cross to x+1 326// // Cross to x+1
295 presence.AbsolutePosition = new Vector3(Constants.RegionSize+1,3,100); 327// presence.AbsolutePosition = new Vector3(Constants.RegionSize+1,3,100);
296 presence.Update(); 328// presence.Update();
297 329//
298 EventWaitHandle wh = new EventWaitHandle (false, EventResetMode.AutoReset, "Crossing"); 330// EventWaitHandle wh = new EventWaitHandle (false, EventResetMode.AutoReset, "Crossing");
299 331//
300 // Mimicking communication between client and server, by waiting OK from client 332// // Mimicking communication between client and server, by waiting OK from client
301 // sent by TestClient.CrossRegion call. Originally, this is network comm. 333// // sent by TestClient.CrossRegion call. Originally, this is network comm.
302 if (!wh.WaitOne(5000,false)) 334// if (!wh.WaitOne(5000,false))
303 { 335// {
304 presence.Update(); 336// presence.Update();
305 if (!wh.WaitOne(8000,false)) 337// if (!wh.WaitOne(8000,false))
306 throw new ArgumentException("1 - Timeout waiting for signal/variable."); 338// throw new ArgumentException("1 - Timeout waiting for signal/variable.");
307 } 339// }
308 340//
309 // This is a TestClient specific method that fires OnCompleteMovementToRegion event, which 341// // This is a TestClient specific method that fires OnCompleteMovementToRegion event, which
310 // would normally be fired after receiving the reply packet from comm. done on the last line. 342// // would normally be fired after receiving the reply packet from comm. done on the last line.
311 testclient.CompleteMovement(); 343// testclient.CompleteMovement();
312 344//
313 // Crossings are asynchronous 345// // Crossings are asynchronous
314 int timer = 10; 346// int timer = 10;
315 347//
316 // Make sure cross hasn't already finished 348// // Make sure cross hasn't already finished
317 if (!presence.IsInTransit && !presence.IsChildAgent) 349// if (!presence.IsInTransit && !presence.IsChildAgent)
318 { 350// {
319 // If not and not in transit yet, give it some more time 351// // If not and not in transit yet, give it some more time
320 Thread.Sleep(5000); 352// Thread.Sleep(5000);
321 } 353// }
322 354//
323 // Enough time, should at least be in transit by now. 355// // Enough time, should at least be in transit by now.
324 while (presence.IsInTransit && timer > 0) 356// while (presence.IsInTransit && timer > 0)
325 { 357// {
326 Thread.Sleep(1000); 358// Thread.Sleep(1000);
327 timer-=1; 359// timer-=1;
328 } 360// }
329 361//
330 Assert.That(timer,Is.GreaterThan(0),"Timed out waiting to cross 2->1."); 362// Assert.That(timer,Is.GreaterThan(0),"Timed out waiting to cross 2->1.");
331 Assert.That(presence.IsChildAgent, Is.True, "Did not complete region cross as expected."); 363// Assert.That(presence.IsChildAgent, Is.True, "Did not complete region cross as expected.");
332 Assert.That(presence2.IsChildAgent, Is.False, "Did not receive root status after receiving agent."); 364// Assert.That(presence2.IsChildAgent, Is.False, "Did not receive root status after receiving agent.");
333 365//
334 // Cross Back 366// // Cross Back
335 presence2.AbsolutePosition = new Vector3(-10, 3, 100); 367// presence2.AbsolutePosition = new Vector3(-10, 3, 100);
336 presence2.Update(); 368// presence2.Update();
337 369//
338 if (!wh.WaitOne(5000,false)) 370// if (!wh.WaitOne(5000,false))
339 { 371// {
340 presence2.Update(); 372// presence2.Update();
341 if (!wh.WaitOne(8000,false)) 373// if (!wh.WaitOne(8000,false))
342 throw new ArgumentException("2 - Timeout waiting for signal/variable."); 374// throw new ArgumentException("2 - Timeout waiting for signal/variable.");
343 } 375// }
344 testclient.CompleteMovement(); 376// testclient.CompleteMovement();
345 377//
346 if (!presence2.IsInTransit && !presence2.IsChildAgent) 378// if (!presence2.IsInTransit && !presence2.IsChildAgent)
347 { 379// {
348 // If not and not in transit yet, give it some more time 380// // If not and not in transit yet, give it some more time
349 Thread.Sleep(5000); 381// Thread.Sleep(5000);
350 } 382// }
351 383//
352 // Enough time, should at least be in transit by now. 384// // Enough time, should at least be in transit by now.
353 while (presence2.IsInTransit && timer > 0) 385// while (presence2.IsInTransit && timer > 0)
354 { 386// {
355 Thread.Sleep(1000); 387// Thread.Sleep(1000);
356 timer-=1; 388// timer-=1;
357 } 389// }
358 390//
359 Assert.That(timer,Is.GreaterThan(0),"Timed out waiting to cross 1->2."); 391// Assert.That(timer,Is.GreaterThan(0),"Timed out waiting to cross 1->2.");
360 Assert.That(presence2.IsChildAgent, Is.True, "Did not return from region as expected."); 392// Assert.That(presence2.IsChildAgent, Is.True, "Did not return from region as expected.");
361 Assert.That(presence.IsChildAgent, Is.False, "Presence was not made root in old region again."); 393// Assert.That(presence.IsChildAgent, Is.False, "Presence was not made root in old region again.");
362 } 394// }
363 } 395 }
364} \ No newline at end of file 396} \ No newline at end of file
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs
index a407f01..37b5184 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs
@@ -301,7 +301,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
301 sp.AbsolutePosition = preTeleportPosition; 301 sp.AbsolutePosition = preTeleportPosition;
302 302
303 // Make sceneB refuse CreateAgent 303 // Make sceneB refuse CreateAgent
304 sceneB.LoginsDisabled = true; 304 sceneB.LoginsEnabled = false;
305 305
306 sceneA.RequestTeleportLocation( 306 sceneA.RequestTeleportLocation(
307 sp.ControllingClient, 307 sp.ControllingClient,
diff --git a/OpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs b/OpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs
index e452124..40f7fbc 100755
--- a/OpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs
+++ b/OpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs
@@ -47,7 +47,7 @@ namespace OpenSim.Region.OptionalModules.PhysicsParameters
47 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "PhysicsParameters")] 47 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "PhysicsParameters")]
48 public class PhysicsParameters : ISharedRegionModule 48 public class PhysicsParameters : ISharedRegionModule
49 { 49 {
50 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 50// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51// private static string LogHeader = "[PHYSICS PARAMETERS]"; 51// private static string LogHeader = "[PHYSICS PARAMETERS]";
52 52
53 private List<Scene> m_scenes = new List<Scene>(); 53 private List<Scene> m_scenes = new List<Scene>();
diff --git a/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs b/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs
index 600cafb..f459b8c 100644
--- a/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs
+++ b/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs
@@ -31,16 +31,14 @@ using System.Reflection;
31using System.Net; 31using System.Net;
32using System.IO; 32using System.IO;
33using System.Text; 33using System.Text;
34
35using log4net; 34using log4net;
36using Nini.Config; 35using Nini.Config;
37using OpenMetaverse; 36using OpenMetaverse;
38using OpenMetaverse.StructuredData; 37using OpenMetaverse.StructuredData;
39using OpenSim.Services.Interfaces;
40
41using OpenSim.Framework; 38using OpenSim.Framework;
42using OpenSim.Region.Framework.Interfaces; 39using OpenSim.Region.Framework.Interfaces;
43using OpenSim.Region.Framework.Scenes; 40using OpenSim.Region.Framework.Scenes;
41using OpenSim.Services.Interfaces;
44 42
45namespace OpenSim.Region.OptionalModules.Scripting.RegionReady 43namespace OpenSim.Region.OptionalModules.Scripting.RegionReady
46{ 44{
@@ -50,16 +48,15 @@ namespace OpenSim.Region.OptionalModules.Scripting.RegionReady
50 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 48 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51 49
52 private IConfig m_config = null; 50 private IConfig m_config = null;
53 private bool m_ScriptRez;
54 private bool m_firstEmptyCompileQueue; 51 private bool m_firstEmptyCompileQueue;
55 private bool m_oarFileLoading; 52 private bool m_oarFileLoading;
56 private bool m_lastOarLoadedOk; 53 private bool m_lastOarLoadedOk;
57 private int m_channelNotify = -1000; 54 private int m_channelNotify = -1000;
58 private bool m_enabled = false; 55 private bool m_enabled = false;
59 private bool m_disable_logins = false; 56 private bool m_disable_logins;
60 private string m_uri = string.Empty; 57 private string m_uri = string.Empty;
61 58
62 Scene m_scene = null; 59 Scene m_scene;
63 60
64 #region INonSharedRegionModule interface 61 #region INonSharedRegionModule interface
65 62
@@ -93,53 +90,40 @@ namespace OpenSim.Region.OptionalModules.Scripting.RegionReady
93 90
94 m_scene.RegisterModuleInterface<IRegionReadyModule>(this); 91 m_scene.RegisterModuleInterface<IRegionReadyModule>(this);
95 92
96 m_ScriptRez = false;
97 m_firstEmptyCompileQueue = true; 93 m_firstEmptyCompileQueue = true;
98 m_oarFileLoading = false; 94 m_oarFileLoading = false;
99 m_lastOarLoadedOk = true; 95 m_lastOarLoadedOk = true;
100 96
101 m_scene.EventManager.OnOarFileLoaded += OnOarFileLoaded; 97 m_scene.EventManager.OnOarFileLoaded += OnOarFileLoaded;
102 m_scene.EventManager.OnRezScript += OnRezScript;
103 m_scene.EventManager.OnLoginsEnabled += OnLoginsEnabled;
104 98
105 m_log.DebugFormat("[RegionReady]: Enabled for region {0}", scene.RegionInfo.RegionName); 99 m_log.DebugFormat("[RegionReady]: Enabled for region {0}", scene.RegionInfo.RegionName);
106 100
107 if (m_disable_logins == true) 101 if (m_disable_logins)
108 { 102 {
109 scene.LoginLock = true; 103 m_scene.LoginLock = true;
110 scene.LoginsDisabled = true; 104 m_scene.EventManager.OnEmptyScriptCompileQueue += OnEmptyScriptCompileQueue;
111 m_log.InfoFormat("[RegionReady]: Region {0} - logins disabled during initialization.",m_scene.RegionInfo.RegionName); 105
106 m_log.InfoFormat("[RegionReady]: Region {0} - LOGINS DISABLED DURING INITIALIZATION.", m_scene.Name);
112 107
113 if(m_uri != string.Empty) 108 if (m_uri != string.Empty)
114 { 109 {
115 RRAlert("disabled"); 110 RRAlert("disabled");
116 } 111 }
117 } 112 }
118 } 113 }
119 114
120 void OnRezScript (uint localID, UUID itemID, string script, int startParam, bool postOnRez, string engine, int stateSource)
121 {
122 if (!m_ScriptRez)
123 {
124 m_ScriptRez = true;
125 m_scene.EventManager.OnEmptyScriptCompileQueue += OnEmptyScriptCompileQueue;
126 m_scene.EventManager.OnRezScript -= OnRezScript;
127 }
128 }
129
130 public void RemoveRegion(Scene scene) 115 public void RemoveRegion(Scene scene)
131 { 116 {
132 if (!m_enabled) 117 if (!m_enabled)
133 return; 118 return;
134 119
135 m_scene.EventManager.OnEmptyScriptCompileQueue -= OnEmptyScriptCompileQueue;
136 m_scene.EventManager.OnOarFileLoaded -= OnOarFileLoaded; 120 m_scene.EventManager.OnOarFileLoaded -= OnOarFileLoaded;
137 m_scene.EventManager.OnLoginsEnabled -= OnLoginsEnabled;
138 121
139 if(m_uri != string.Empty) 122 if (m_disable_logins)
140 { 123 m_scene.EventManager.OnEmptyScriptCompileQueue -= OnEmptyScriptCompileQueue;
124
125 if (m_uri != string.Empty)
141 RRAlert("shutdown"); 126 RRAlert("shutdown");
142 }
143 127
144 m_scene = null; 128 m_scene = null;
145 } 129 }
@@ -159,7 +143,6 @@ namespace OpenSim.Region.OptionalModules.Scripting.RegionReady
159 143
160 #endregion 144 #endregion
161 145
162
163 void OnEmptyScriptCompileQueue(int numScriptsFailed, string message) 146 void OnEmptyScriptCompileQueue(int numScriptsFailed, string message)
164 { 147 {
165 m_log.DebugFormat("[RegionReady]: Script compile queue empty!"); 148 m_log.DebugFormat("[RegionReady]: Script compile queue empty!");
@@ -193,75 +176,80 @@ namespace OpenSim.Region.OptionalModules.Scripting.RegionReady
193 m_scene.RegionInfo.RegionName, c.Message, m_channelNotify); 176 m_scene.RegionInfo.RegionName, c.Message, m_channelNotify);
194 177
195 m_scene.EventManager.TriggerOnChatBroadcast(this, c); 178 m_scene.EventManager.TriggerOnChatBroadcast(this, c);
196 m_scene.EventManager.TriggerLoginsEnabled(m_scene.RegionInfo.RegionName); 179
197 m_scene.SceneGridService.InformNeighborsThatRegionisUp(m_scene.RequestModuleInterface<INeighbourService>(), m_scene.RegionInfo); 180 TriggerRegionReady(m_scene);
198 } 181 }
199 } 182 }
200 183
201 void OnOarFileLoaded(Guid requestId, string message) 184 void OnOarFileLoaded(Guid requestId, string message)
202 { 185 {
203 m_oarFileLoading = true; 186 m_oarFileLoading = true;
187
204 if (message==String.Empty) 188 if (message==String.Empty)
205 { 189 {
206 m_lastOarLoadedOk = true; 190 m_lastOarLoadedOk = true;
207 } else { 191 }
192 else
193 {
208 m_log.WarnFormat("[RegionReady]: Oar file load errors: {0}", message); 194 m_log.WarnFormat("[RegionReady]: Oar file load errors: {0}", message);
209 m_lastOarLoadedOk = false; 195 m_lastOarLoadedOk = false;
210 } 196 }
211 } 197 }
212 198
213 // This will be triggerd by Scene if we have no scripts 199 /// <summary>
214 // m_ScriptsRezzing will be false if there were none 200 /// This will be triggered by Scene directly if it contains no scripts on startup. Otherwise it is triggered
215 // else it will be true and we should wait on the 201 /// when the script compile queue is empty after initial region startup.
216 // empty compile queue 202 /// </summary>
217 void OnLoginsEnabled(string regionName) 203 /// <param name='scene'></param>
204 public void TriggerRegionReady(IScene scene)
218 { 205 {
219 if (m_disable_logins == true) 206 m_scene.EventManager.OnEmptyScriptCompileQueue -= OnEmptyScriptCompileQueue;
207 m_scene.LoginLock = false;
208
209 if (!m_scene.StartDisabled)
220 { 210 {
221 if (m_scene.StartDisabled == false) 211 m_scene.LoginsEnabled = true;
222 {
223 m_scene.LoginsDisabled = false;
224 m_scene.LoginLock = false;
225 212
226 m_scene.EventManager.OnEmptyScriptCompileQueue -= OnEmptyScriptCompileQueue; 213 // m_log.InfoFormat("[RegionReady]: Logins enabled for {0}, Oar {1}",
214 // m_scene.RegionInfo.RegionName, m_oarFileLoading.ToString());
227 215
228 // m_log.InfoFormat("[RegionReady]: Logins enabled for {0}, Oar {1}", 216 m_log.InfoFormat(
229 // m_scene.RegionInfo.RegionName, m_oarFileLoading.ToString()); 217 "[RegionReady]: INITIALIZATION COMPLETE FOR {0} - LOGINS ENABLED", m_scene.Name);
218 }
230 219
231 m_log.InfoFormat( 220 m_scene.SceneGridService.InformNeighborsThatRegionisUp(
232 "[RegionReady]: INITIALIZATION COMPLETE FOR {0} - LOGINS ENABLED", m_scene.Name); 221 m_scene.RequestModuleInterface<INeighbourService>(), m_scene.RegionInfo);
233 222
234 if (m_uri != string.Empty) 223 if (m_uri != string.Empty)
235 { 224 {
236 RRAlert("enabled"); 225 RRAlert("enabled");
237 }
238 }
239 } 226 }
227
228 m_scene.EventManager.TriggerRegionReady(m_scene);
240 } 229 }
241 230
242 public void OarLoadingAlert(string msg) 231 public void OarLoadingAlert(string msg)
243 { 232 {
244 // Let's bypass this for now until some better feedback can be established 233 // Let's bypass this for now until some better feedback can be established
245 // 234 //
246 return;
247 235
248 if (msg == "load") 236// if (msg == "load")
249 { 237// {
250 m_scene.EventManager.OnEmptyScriptCompileQueue += OnEmptyScriptCompileQueue; 238// m_scene.EventManager.OnEmptyScriptCompileQueue += OnEmptyScriptCompileQueue;
251 m_scene.EventManager.OnOarFileLoaded += OnOarFileLoaded; 239// m_scene.EventManager.OnOarFileLoaded += OnOarFileLoaded;
252 m_scene.EventManager.OnLoginsEnabled += OnLoginsEnabled; 240// m_scene.EventManager.OnLoginsEnabled += OnLoginsEnabled;
253 m_scene.EventManager.OnRezScript += OnRezScript; 241// m_scene.EventManager.OnRezScript += OnRezScript;
254 m_oarFileLoading = true; 242// m_oarFileLoading = true;
255 m_firstEmptyCompileQueue = true; 243// m_firstEmptyCompileQueue = true;
256 244//
257 m_scene.LoginsDisabled = true; 245// m_scene.LoginsDisabled = true;
258 m_scene.LoginLock = true; 246// m_scene.LoginLock = true;
259 if ( m_uri != string.Empty ) 247// if ( m_uri != string.Empty )
260 { 248// {
261 RRAlert("loading oar"); 249// RRAlert("loading oar");
262 RRAlert("disabled"); 250// RRAlert("disabled");
263 } 251// }
264 } 252// }
265 } 253 }
266 254
267 public void RRAlert(string status) 255 public void RRAlert(string status)
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index dc0c008..09e1f0c 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -41,7 +41,7 @@ public class BSCharacter : PhysicsActor
41 41
42 private BSScene _scene; 42 private BSScene _scene;
43 private String _avName; 43 private String _avName;
44 private bool _stopped; 44 // private bool _stopped;
45 private Vector3 _size; 45 private Vector3 _size;
46 private Vector3 _scale; 46 private Vector3 _scale;
47 private PrimitiveBaseShape _pbs; 47 private PrimitiveBaseShape _pbs;
@@ -134,9 +134,9 @@ public class BSCharacter : PhysicsActor
134 { 134 {
135 base.RequestPhysicsterseUpdate(); 135 base.RequestPhysicsterseUpdate();
136 } 136 }
137 137 // No one calls this method so I don't know what it could possibly mean
138 public override bool Stopped { 138 public override bool Stopped {
139 get { return _stopped; } 139 get { return false; }
140 } 140 }
141 public override Vector3 Size { 141 public override Vector3 Size {
142 get { return _size; } 142 get { return _size; }
@@ -391,52 +391,47 @@ public class BSCharacter : PhysicsActor
391 _mass = _density * _avatarVolume; 391 _mass = _density * _avatarVolume;
392 } 392 }
393 393
394 // Set to 'true' if the individual changed items should be checked
395 // (someday RequestPhysicsTerseUpdate() will take a bitmap of changed properties)
396 const bool SHOULD_CHECK_FOR_INDIVIDUAL_CHANGES = false;
397
398 // The physics engine says that properties have updated. Update same and inform 394 // The physics engine says that properties have updated. Update same and inform
399 // the world that things have changed. 395 // the world that things have changed.
400 public void UpdateProperties(EntityProperties entprop) 396 public void UpdateProperties(EntityProperties entprop)
401 { 397 {
398 /*
402 bool changed = false; 399 bool changed = false;
403 if (SHOULD_CHECK_FOR_INDIVIDUAL_CHANGES) { 400 // we assign to the local variables so the normal set action does not happen
404 // we assign to the local variables so the normal set action does not happen 401 if (_position != entprop.Position) {
405 if (_position != entprop.Position) {
406 _position = entprop.Position;
407 changed = true;
408 }
409 if (_orientation != entprop.Rotation) {
410 _orientation = entprop.Rotation;
411 changed = true;
412 }
413 if (_velocity != entprop.Velocity) {
414 _velocity = entprop.Velocity;
415 changed = true;
416 }
417 if (_acceleration != entprop.Acceleration) {
418 _acceleration = entprop.Acceleration;
419 changed = true;
420 }
421 if (_rotationalVelocity != entprop.RotationalVelocity) {
422 _rotationalVelocity = entprop.RotationalVelocity;
423 changed = true;
424 }
425 if (changed) {
426 // m_log.DebugFormat("{0}: UpdateProperties: id={1}, c={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation);
427 // Avatar movement is not done by generating this event. There is code in the heartbeat
428 // loop that updates avatars.
429 // base.RequestPhysicsterseUpdate();
430 }
431 }
432 else {
433 _position = entprop.Position; 402 _position = entprop.Position;
403 changed = true;
404 }
405 if (_orientation != entprop.Rotation) {
434 _orientation = entprop.Rotation; 406 _orientation = entprop.Rotation;
407 changed = true;
408 }
409 if (_velocity != entprop.Velocity) {
435 _velocity = entprop.Velocity; 410 _velocity = entprop.Velocity;
411 changed = true;
412 }
413 if (_acceleration != entprop.Acceleration) {
436 _acceleration = entprop.Acceleration; 414 _acceleration = entprop.Acceleration;
415 changed = true;
416 }
417 if (_rotationalVelocity != entprop.RotationalVelocity) {
437 _rotationalVelocity = entprop.RotationalVelocity; 418 _rotationalVelocity = entprop.RotationalVelocity;
419 changed = true;
420 }
421 if (changed) {
422 // m_log.DebugFormat("{0}: UpdateProperties: id={1}, c={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation);
423 // Avatar movement is not done by generating this event. There is code in the heartbeat
424 // loop that updates avatars.
438 // base.RequestPhysicsterseUpdate(); 425 // base.RequestPhysicsterseUpdate();
439 } 426 }
427 */
428 _position = entprop.Position;
429 _orientation = entprop.Rotation;
430 _velocity = entprop.Velocity;
431 _acceleration = entprop.Acceleration;
432 _rotationalVelocity = entprop.RotationalVelocity;
433 // Avatars don't report theirr changes the usual way. Changes are checked for in the heartbeat loop.
434 // base.RequestPhysicsterseUpdate();
440 } 435 }
441 436
442 // Called by the scene when a collision with this object is reported 437 // Called by the scene when a collision with this object is reported
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index eb20eb3..c197e61 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -57,7 +57,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin
57 private int frcount = 0; // Used to limit dynamics debug output to 57 private int frcount = 0; // Used to limit dynamics debug output to
58 // every 100th frame 58 // every 100th frame
59 59
60 // private BSScene m_parentScene = null;
61 private BSPrim m_prim; // the prim this dynamic controller belongs to 60 private BSPrim m_prim; // the prim this dynamic controller belongs to
62 61
63 // Vehicle properties 62 // Vehicle properties
@@ -131,8 +130,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin
131 m_type = Vehicle.TYPE_NONE; 130 m_type = Vehicle.TYPE_NONE;
132 } 131 }
133 132
134 internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue) 133 internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue, float timestep)
135 { 134 {
135 DetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", m_prim.LocalID, pParam, pValue);
136 switch (pParam) 136 switch (pParam)
137 { 137 {
138 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: 138 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY:
@@ -229,8 +229,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin
229 } 229 }
230 }//end ProcessFloatVehicleParam 230 }//end ProcessFloatVehicleParam
231 231
232 internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue) 232 internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue, float timestep)
233 { 233 {
234 DetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", m_prim.LocalID, pParam, pValue);
234 switch (pParam) 235 switch (pParam)
235 { 236 {
236 case Vehicle.ANGULAR_FRICTION_TIMESCALE: 237 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
@@ -265,6 +266,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
265 266
266 internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue) 267 internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue)
267 { 268 {
269 DetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", m_prim.LocalID, pParam, pValue);
268 switch (pParam) 270 switch (pParam)
269 { 271 {
270 case Vehicle.REFERENCE_FRAME: 272 case Vehicle.REFERENCE_FRAME:
@@ -278,6 +280,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
278 280
279 internal void ProcessVehicleFlags(int pParam, bool remove) 281 internal void ProcessVehicleFlags(int pParam, bool remove)
280 { 282 {
283 DetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", m_prim.LocalID, pParam, remove);
281 if (remove) 284 if (remove)
282 { 285 {
283 if (pParam == -1) 286 if (pParam == -1)
@@ -434,6 +437,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
434 437
435 internal void ProcessTypeChange(Vehicle pType) 438 internal void ProcessTypeChange(Vehicle pType)
436 { 439 {
440 DetailLog("{0},ProcessTypeChange,type={1}", m_prim.LocalID, pType);
437 // Set Defaults For Type 441 // Set Defaults For Type
438 m_type = pType; 442 m_type = pType;
439 switch (pType) 443 switch (pType)
@@ -594,11 +598,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
594 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY); 598 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY);
595 m_Hoverflags |= (VehicleFlag.HOVER_GLOBAL_HEIGHT); 599 m_Hoverflags |= (VehicleFlag.HOVER_GLOBAL_HEIGHT);
596 break; 600 break;
597
598 } 601 }
599 }//end SetDefaultsForType 602 }//end SetDefaultsForType
600 603
601 internal void Step(float pTimestep, BSScene pParentScene) 604 internal void Step(float pTimestep)
602 { 605 {
603 if (m_type == Vehicle.TYPE_NONE) return; 606 if (m_type == Vehicle.TYPE_NONE) return;
604 607
@@ -606,21 +609,34 @@ namespace OpenSim.Region.Physics.BulletSPlugin
606 if (frcount > 100) 609 if (frcount > 100)
607 frcount = 0; 610 frcount = 0;
608 611
609 MoveLinear(pTimestep, pParentScene); 612 MoveLinear(pTimestep);
610 MoveAngular(pTimestep); 613 MoveAngular(pTimestep);
611 LimitRotation(pTimestep); 614 LimitRotation(pTimestep);
615
616 DetailLog("{0},Dynamics,done,pos={1},force={2},velocity={3},angvel={4}",
617 m_prim.LocalID, m_prim.Position, m_prim.Force, m_prim.Velocity, m_prim.RotationalVelocity);
612 }// end Step 618 }// end Step
613 619
614 private void MoveLinear(float pTimestep, BSScene _pParentScene) 620 private void MoveLinear(float pTimestep)
615 { 621 {
616 if (!m_linearMotorDirection.ApproxEquals(Vector3.Zero, 0.01f)) // requested m_linearMotorDirection is significant 622 // requested m_linearMotorDirection is significant
623 // if (!m_linearMotorDirection.ApproxEquals(Vector3.Zero, 0.01f))
624 if (m_linearMotorDirection.LengthSquared() > 0.0001f)
617 { 625 {
626 Vector3 origDir = m_linearMotorDirection;
627 Vector3 origVel = m_lastLinearVelocityVector;
628
618 // add drive to body 629 // add drive to body
619 Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale/pTimestep); 630 // Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale/pTimestep);
620 m_lastLinearVelocityVector += (addAmount*10); // lastLinearVelocityVector is the current body velocity vector? 631 Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale);
632 // lastLinearVelocityVector is the current body velocity vector?
633 // RA: Not sure what the *10 is for. A correction for pTimestep?
634 // m_lastLinearVelocityVector += (addAmount*10);
635 m_lastLinearVelocityVector += addAmount;
621 636
622 // This will work temporarily, but we really need to compare speed on an axis 637 // This will work temporarily, but we really need to compare speed on an axis
623 // KF: Limit body velocity to applied velocity? 638 // KF: Limit body velocity to applied velocity?
639 // Limit the velocity vector to less than the last set linear motor direction
624 if (Math.Abs(m_lastLinearVelocityVector.X) > Math.Abs(m_linearMotorDirectionLASTSET.X)) 640 if (Math.Abs(m_lastLinearVelocityVector.X) > Math.Abs(m_linearMotorDirectionLASTSET.X))
625 m_lastLinearVelocityVector.X = m_linearMotorDirectionLASTSET.X; 641 m_lastLinearVelocityVector.X = m_linearMotorDirectionLASTSET.X;
626 if (Math.Abs(m_lastLinearVelocityVector.Y) > Math.Abs(m_linearMotorDirectionLASTSET.Y)) 642 if (Math.Abs(m_lastLinearVelocityVector.Y) > Math.Abs(m_linearMotorDirectionLASTSET.Y))
@@ -630,76 +646,93 @@ namespace OpenSim.Region.Physics.BulletSPlugin
630 646
631 // decay applied velocity 647 // decay applied velocity
632 Vector3 decayfraction = ((Vector3.One/(m_linearMotorDecayTimescale/pTimestep))); 648 Vector3 decayfraction = ((Vector3.One/(m_linearMotorDecayTimescale/pTimestep)));
633 //Console.WriteLine("decay: " + decayfraction);
634 m_linearMotorDirection -= m_linearMotorDirection * decayfraction * 0.5f; 649 m_linearMotorDirection -= m_linearMotorDirection * decayfraction * 0.5f;
635 //Console.WriteLine("actual: " + m_linearMotorDirection); 650
651 /*
652 Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/m_linearMotorTimescale;
653 m_lastLinearVelocityVector += addAmount;
654
655 float decayfraction = (1.0f - 1.0f / m_linearMotorDecayTimescale);
656 m_linearMotorDirection *= decayfraction;
657
658 */
659
660 DetailLog("{0},MoveLinear,nonZero,origdir={1},origvel={2},add={3},decay={4},dir={5},vel={6}",
661 m_prim.LocalID, origDir, origVel, addAmount, decayfraction, m_linearMotorDirection, m_lastLinearVelocityVector);
636 } 662 }
637 else 663 else
638 { // requested is not significant 664 {
639 // if what remains of applied is small, zero it. 665 // if what remains of applied is small, zero it.
640 if (m_lastLinearVelocityVector.ApproxEquals(Vector3.Zero, 0.01f)) 666 // if (m_lastLinearVelocityVector.ApproxEquals(Vector3.Zero, 0.01f))
641 m_lastLinearVelocityVector = Vector3.Zero; 667 // m_lastLinearVelocityVector = Vector3.Zero;
668 m_linearMotorDirection = Vector3.Zero;
669 m_lastLinearVelocityVector = Vector3.Zero;
642 } 670 }
643 671
644 // convert requested object velocity to world-referenced vector 672 // convert requested object velocity to world-referenced vector
645 m_dir = m_lastLinearVelocityVector; 673 Quaternion rotq = m_prim.Orientation;
646 Quaternion rot = m_prim.Orientation; 674 m_dir = m_lastLinearVelocityVector * rotq;
647 Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); // rotq = rotation of object 675
648 m_dir *= rotq; // apply obj rotation to velocity vector 676 // Add the various forces into m_dir which will be our new direction vector (velocity)
649 677
650 // add Gravity andBuoyancy 678 // add Gravity and Buoyancy
651 // KF: So far I have found no good method to combine a script-requested 679 // KF: So far I have found no good method to combine a script-requested
652 // .Z velocity and gravity. Therefore only 0g will used script-requested 680 // .Z velocity and gravity. Therefore only 0g will used script-requested
653 // .Z velocity. >0g (m_VehicleBuoyancy < 1) will used modified gravity only. 681 // .Z velocity. >0g (m_VehicleBuoyancy < 1) will used modified gravity only.
654 Vector3 grav = Vector3.Zero; 682 Vector3 grav = Vector3.Zero;
655 // There is some gravity, make a gravity force vector 683 // There is some gravity, make a gravity force vector that is applied after object velocity.
656 // that is applied after object velocity.
657 float objMass = m_prim.Mass;
658 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; 684 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
659 grav.Z = _pParentScene.DefaultGravity.Z * objMass * (1f - m_VehicleBuoyancy); 685 grav.Z = m_prim.Scene.DefaultGravity.Z * m_prim.Mass * (1f - m_VehicleBuoyancy);
660 // Preserve the current Z velocity 686 // Preserve the current Z velocity
661 Vector3 vel_now = m_prim.Velocity; 687 Vector3 vel_now = m_prim.Velocity;
662 m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity 688 m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity
663 689
664 Vector3 pos = m_prim.Position; 690 Vector3 pos = m_prim.Position;
691 Vector3 posChange = pos;
665// Vector3 accel = new Vector3(-(m_dir.X - m_lastLinearVelocityVector.X / 0.1f), -(m_dir.Y - m_lastLinearVelocityVector.Y / 0.1f), m_dir.Z - m_lastLinearVelocityVector.Z / 0.1f); 692// Vector3 accel = new Vector3(-(m_dir.X - m_lastLinearVelocityVector.X / 0.1f), -(m_dir.Y - m_lastLinearVelocityVector.Y / 0.1f), m_dir.Z - m_lastLinearVelocityVector.Z / 0.1f);
666 Vector3 posChange = new Vector3();
667 posChange.X = pos.X - m_lastPositionVector.X;
668 posChange.Y = pos.Y - m_lastPositionVector.Y;
669 posChange.Z = pos.Z - m_lastPositionVector.Z;
670 double Zchange = Math.Abs(posChange.Z); 693 double Zchange = Math.Abs(posChange.Z);
671 if (m_BlockingEndPoint != Vector3.Zero) 694 if (m_BlockingEndPoint != Vector3.Zero)
672 { 695 {
696 bool changed = false;
673 if (pos.X >= (m_BlockingEndPoint.X - (float)1)) 697 if (pos.X >= (m_BlockingEndPoint.X - (float)1))
674 { 698 {
675 pos.X -= posChange.X + 1; 699 pos.X -= posChange.X + 1;
676 m_prim.Position = pos; 700 changed = true;
677 } 701 }
678 if (pos.Y >= (m_BlockingEndPoint.Y - (float)1)) 702 if (pos.Y >= (m_BlockingEndPoint.Y - (float)1))
679 { 703 {
680 pos.Y -= posChange.Y + 1; 704 pos.Y -= posChange.Y + 1;
681 m_prim.Position = pos; 705 changed = true;
682 } 706 }
683 if (pos.Z >= (m_BlockingEndPoint.Z - (float)1)) 707 if (pos.Z >= (m_BlockingEndPoint.Z - (float)1))
684 { 708 {
685 pos.Z -= posChange.Z + 1; 709 pos.Z -= posChange.Z + 1;
686 m_prim.Position = pos; 710 changed = true;
687 } 711 }
688 if (pos.X <= 0) 712 if (pos.X <= 0)
689 { 713 {
690 pos.X += posChange.X + 1; 714 pos.X += posChange.X + 1;
691 m_prim.Position = pos; 715 changed = true;
692 } 716 }
693 if (pos.Y <= 0) 717 if (pos.Y <= 0)
694 { 718 {
695 pos.Y += posChange.Y + 1; 719 pos.Y += posChange.Y + 1;
720 changed = true;
721 }
722 if (changed)
723 {
696 m_prim.Position = pos; 724 m_prim.Position = pos;
725 DetailLog("{0},MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}",
726 m_prim.LocalID, m_BlockingEndPoint, posChange, pos);
697 } 727 }
698 } 728 }
699 if (pos.Z < _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y)) 729
730 // If below the terrain, move us above the ground a little.
731 if (pos.Z < m_prim.Scene.GetTerrainHeightAtXYZ(pos))
700 { 732 {
701 pos.Z = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y) + 2; 733 pos.Z = m_prim.Scene.GetTerrainHeightAtXYZ(pos) + 2;
702 m_prim.Position = pos; 734 m_prim.Position = pos;
735 DetailLog("{0},MoveLinear,terrainHeight,pos={1}", m_prim.LocalID, pos);
703 } 736 }
704 737
705 // Check if hovering 738 // Check if hovering
@@ -708,11 +741,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
708 // We should hover, get the target height 741 // We should hover, get the target height
709 if ((m_Hoverflags & VehicleFlag.HOVER_WATER_ONLY) != 0) 742 if ((m_Hoverflags & VehicleFlag.HOVER_WATER_ONLY) != 0)
710 { 743 {
711 m_VhoverTargetHeight = _pParentScene.GetWaterLevel() + m_VhoverHeight; 744 m_VhoverTargetHeight = m_prim.Scene.GetWaterLevel() + m_VhoverHeight;
712 } 745 }
713 if ((m_Hoverflags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) 746 if ((m_Hoverflags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0)
714 { 747 {
715 m_VhoverTargetHeight = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y) + m_VhoverHeight; 748 m_VhoverTargetHeight = m_prim.Scene.GetTerrainHeightAtXY(pos.X, pos.Y) + m_VhoverHeight;
716 } 749 }
717 if ((m_Hoverflags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) 750 if ((m_Hoverflags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0)
718 { 751 {
@@ -746,6 +779,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
746 } 779 }
747 } 780 }
748 781
782 DetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", m_prim.LocalID, pos, m_dir, m_VhoverHeight, m_VhoverTargetHeight);
783
749// m_VhoverEfficiency = 0f; // 0=boucy, 1=Crit.damped 784// m_VhoverEfficiency = 0f; // 0=boucy, 1=Crit.damped
750// m_VhoverTimescale = 0f; // time to acheive height 785// m_VhoverTimescale = 0f; // time to acheive height
751// pTimestep is time since last frame,in secs 786// pTimestep is time since last frame,in secs
@@ -774,12 +809,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
774 { 809 {
775 grav.Z = (float)(grav.Z * 1.125); 810 grav.Z = (float)(grav.Z * 1.125);
776 } 811 }
777 float terraintemp = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y); 812 float terraintemp = m_prim.Scene.GetTerrainHeightAtXYZ(pos);
778 float postemp = (pos.Z - terraintemp); 813 float postemp = (pos.Z - terraintemp);
779 if (postemp > 2.5f) 814 if (postemp > 2.5f)
780 { 815 {
781 grav.Z = (float)(grav.Z * 1.037125); 816 grav.Z = (float)(grav.Z * 1.037125);
782 } 817 }
818 DetailLog("{0},MoveLinear,limitMotorUp,grav={1}", m_prim.LocalID, grav);
783 //End Experimental Values 819 //End Experimental Values
784 } 820 }
785 if ((m_flags & (VehicleFlag.NO_X)) != 0) 821 if ((m_flags & (VehicleFlag.NO_X)) != 0)
@@ -800,32 +836,39 @@ namespace OpenSim.Region.Physics.BulletSPlugin
800 // Apply velocity 836 // Apply velocity
801 m_prim.Velocity = m_dir; 837 m_prim.Velocity = m_dir;
802 // apply gravity force 838 // apply gravity force
803 m_prim.Force = grav; 839 // Why is this set here? The physics engine already does gravity.
804 840 // m_prim.AddForce(grav, false);
841 // m_prim.Force = grav;
805 842
806 // apply friction 843 // Apply friction
807 Vector3 decayamount = Vector3.One / (m_linearFrictionTimescale / pTimestep); 844 Vector3 decayamount = Vector3.One / (m_linearFrictionTimescale / pTimestep);
808 m_lastLinearVelocityVector -= m_lastLinearVelocityVector * decayamount; 845 m_lastLinearVelocityVector -= m_lastLinearVelocityVector * decayamount;
846
847 DetailLog("{0},MoveLinear,done,pos={1},vel={2},force={3},decay={4}",
848 m_prim.LocalID, m_lastPositionVector, m_dir, grav, decayamount);
849
809 } // end MoveLinear() 850 } // end MoveLinear()
810 851
811 private void MoveAngular(float pTimestep) 852 private void MoveAngular(float pTimestep)
812 { 853 {
813 /* 854 // m_angularMotorDirection // angular velocity requested by LSL motor
814 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor 855 // m_angularMotorApply // application frame counter
815 private int m_angularMotorApply = 0; // application frame counter 856 // m_angularMotorVelocity // current angular motor velocity (ramps up and down)
816 private float m_angularMotorVelocity = 0; // current angular motor velocity (ramps up and down) 857 // m_angularMotorTimescale // motor angular velocity ramp up rate
817 private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate 858 // m_angularMotorDecayTimescale // motor angular velocity decay rate
818 private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate 859 // m_angularFrictionTimescale // body angular velocity decay rate
819 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate 860 // m_lastAngularVelocity // what was last applied to body
820 private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body
821 */
822 861
823 // Get what the body is doing, this includes 'external' influences 862 // Get what the body is doing, this includes 'external' influences
824 Vector3 angularVelocity = m_prim.RotationalVelocity; 863 Vector3 angularVelocity = m_prim.RotationalVelocity;
825 // Vector3 angularVelocity = Vector3.Zero;
826 864
827 if (m_angularMotorApply > 0) 865 if (m_angularMotorApply > 0)
828 { 866 {
867 // Rather than snapping the angular motor velocity from the old value to
868 // a newly set velocity, this routine steps the value from the previous
869 // value (m_angularMotorVelocity) to the requested value (m_angularMotorDirection).
870 // There are m_angularMotorApply steps.
871 Vector3 origAngularVelocity = m_angularMotorVelocity;
829 // ramp up to new value 872 // ramp up to new value
830 // current velocity += error / (time to get there / step interval) 873 // current velocity += error / (time to get there / step interval)
831 // requested speed - last motor speed 874 // requested speed - last motor speed
@@ -833,23 +876,21 @@ namespace OpenSim.Region.Physics.BulletSPlugin
833 m_angularMotorVelocity.Y += (m_angularMotorDirection.Y - m_angularMotorVelocity.Y) / (m_angularMotorTimescale / pTimestep); 876 m_angularMotorVelocity.Y += (m_angularMotorDirection.Y - m_angularMotorVelocity.Y) / (m_angularMotorTimescale / pTimestep);
834 m_angularMotorVelocity.Z += (m_angularMotorDirection.Z - m_angularMotorVelocity.Z) / (m_angularMotorTimescale / pTimestep); 877 m_angularMotorVelocity.Z += (m_angularMotorDirection.Z - m_angularMotorVelocity.Z) / (m_angularMotorTimescale / pTimestep);
835 878
879 DetailLog("{0},MoveAngular,angularMotorApply,apply={1},origvel={2},dir={3},vel={4}",
880 m_prim.LocalID,m_angularMotorApply,origAngularVelocity, m_angularMotorDirection, m_angularMotorVelocity);
881
836 m_angularMotorApply--; // This is done so that if script request rate is less than phys frame rate the expected 882 m_angularMotorApply--; // This is done so that if script request rate is less than phys frame rate the expected
837 // velocity may still be acheived. 883 // velocity may still be acheived.
838 } 884 }
839 else 885 else
840 { 886 {
841 // no motor recently applied, keep the body velocity 887 // No motor recently applied, keep the body velocity
842 /* m_angularMotorVelocity.X = angularVelocity.X;
843 m_angularMotorVelocity.Y = angularVelocity.Y;
844 m_angularMotorVelocity.Z = angularVelocity.Z; */
845
846 // and decay the velocity 888 // and decay the velocity
847 m_angularMotorVelocity -= m_angularMotorVelocity / (m_angularMotorDecayTimescale / pTimestep); 889 m_angularMotorVelocity -= m_angularMotorVelocity / (m_angularMotorDecayTimescale / pTimestep);
848 } // end motor section 890 } // end motor section
849 891
850 // Vertical attractor section 892 // Vertical attractor section
851 Vector3 vertattr = Vector3.Zero; 893 Vector3 vertattr = Vector3.Zero;
852
853 if (m_verticalAttractionTimescale < 300) 894 if (m_verticalAttractionTimescale < 300)
854 { 895 {
855 float VAservo = 0.2f / (m_verticalAttractionTimescale * pTimestep); 896 float VAservo = 0.2f / (m_verticalAttractionTimescale * pTimestep);
@@ -871,7 +912,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin
871 // Error is 0 (no error) to +/- 2 (max error) 912 // Error is 0 (no error) to +/- 2 (max error)
872 // scale it by VAservo 913 // scale it by VAservo
873 verterr = verterr * VAservo; 914 verterr = verterr * VAservo;
874//if (frcount == 0) Console.WriteLine("VAerr=" + verterr);
875 915
876 // As the body rotates around the X axis, then verterr.Y increases; Rotated around Y then .X increases, so 916 // As the body rotates around the X axis, then verterr.Y increases; Rotated around Y then .X increases, so
877 // Change Body angular velocity X based on Y, and Y based on X. Z is not changed. 917 // Change Body angular velocity X based on Y, and Y based on X. Z is not changed.
@@ -884,11 +924,15 @@ namespace OpenSim.Region.Physics.BulletSPlugin
884 vertattr.X += bounce * angularVelocity.X; 924 vertattr.X += bounce * angularVelocity.X;
885 vertattr.Y += bounce * angularVelocity.Y; 925 vertattr.Y += bounce * angularVelocity.Y;
886 926
927 DetailLog("{0},MoveAngular,verticalAttraction,verterr={1},bounce={2},vertattr={3}",
928 m_prim.LocalID, verterr, bounce, vertattr);
929
887 } // else vertical attractor is off 930 } // else vertical attractor is off
888 931
889 // m_lastVertAttractor = vertattr; 932 // m_lastVertAttractor = vertattr;
890 933
891 // Bank section tba 934 // Bank section tba
935
892 // Deflection section tba 936 // Deflection section tba
893 937
894 // Sum velocities 938 // Sum velocities
@@ -898,11 +942,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
898 { 942 {
899 m_lastAngularVelocity.X = 0; 943 m_lastAngularVelocity.X = 0;
900 m_lastAngularVelocity.Y = 0; 944 m_lastAngularVelocity.Y = 0;
945 DetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", m_prim.LocalID, m_lastAngularVelocity);
901 } 946 }
902 947
903 if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) 948 if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f))
904 { 949 {
905 m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero. 950 m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero.
951 DetailLog("{0},MoveAngular,zeroSmallValues,lastAngular={1}", m_prim.LocalID, m_lastAngularVelocity);
906 } 952 }
907 953
908 // apply friction 954 // apply friction
@@ -912,10 +958,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin
912 // Apply to the body 958 // Apply to the body
913 m_prim.RotationalVelocity = m_lastAngularVelocity; 959 m_prim.RotationalVelocity = m_lastAngularVelocity;
914 960
961 DetailLog("{0},MoveAngular,done,decay={1},lastAngular={2}", m_prim.LocalID, decayamount, m_lastAngularVelocity);
915 } //end MoveAngular 962 } //end MoveAngular
963
916 internal void LimitRotation(float timestep) 964 internal void LimitRotation(float timestep)
917 { 965 {
918 Quaternion rotq = m_prim.Orientation; // rotq = rotation of object 966 Quaternion rotq = m_prim.Orientation;
919 Quaternion m_rot = rotq; 967 Quaternion m_rot = rotq;
920 bool changed = false; 968 bool changed = false;
921 if (m_RollreferenceFrame != Quaternion.Identity) 969 if (m_RollreferenceFrame != Quaternion.Identity)
@@ -923,18 +971,22 @@ namespace OpenSim.Region.Physics.BulletSPlugin
923 if (rotq.X >= m_RollreferenceFrame.X) 971 if (rotq.X >= m_RollreferenceFrame.X)
924 { 972 {
925 m_rot.X = rotq.X - (m_RollreferenceFrame.X / 2); 973 m_rot.X = rotq.X - (m_RollreferenceFrame.X / 2);
974 changed = true;
926 } 975 }
927 if (rotq.Y >= m_RollreferenceFrame.Y) 976 if (rotq.Y >= m_RollreferenceFrame.Y)
928 { 977 {
929 m_rot.Y = rotq.Y - (m_RollreferenceFrame.Y / 2); 978 m_rot.Y = rotq.Y - (m_RollreferenceFrame.Y / 2);
979 changed = true;
930 } 980 }
931 if (rotq.X <= -m_RollreferenceFrame.X) 981 if (rotq.X <= -m_RollreferenceFrame.X)
932 { 982 {
933 m_rot.X = rotq.X + (m_RollreferenceFrame.X / 2); 983 m_rot.X = rotq.X + (m_RollreferenceFrame.X / 2);
984 changed = true;
934 } 985 }
935 if (rotq.Y <= -m_RollreferenceFrame.Y) 986 if (rotq.Y <= -m_RollreferenceFrame.Y)
936 { 987 {
937 m_rot.Y = rotq.Y + (m_RollreferenceFrame.Y / 2); 988 m_rot.Y = rotq.Y + (m_RollreferenceFrame.Y / 2);
989 changed = true;
938 } 990 }
939 changed = true; 991 changed = true;
940 } 992 }
@@ -944,8 +996,23 @@ namespace OpenSim.Region.Physics.BulletSPlugin
944 m_rot.Y = 0; 996 m_rot.Y = 0;
945 changed = true; 997 changed = true;
946 } 998 }
999 if ((m_flags & VehicleFlag.LOCK_ROTATION) != 0)
1000 {
1001 m_rot.X = 0;
1002 m_rot.Y = 0;
1003 changed = true;
1004 }
947 if (changed) 1005 if (changed)
948 m_prim.Orientation = m_rot; 1006 m_prim.Orientation = m_rot;
1007
1008 DetailLog("{0},LimitRotation,done,changed={1},orig={2},new={3}", m_prim.LocalID, changed, rotq, m_rot);
1009 }
1010
1011 // Invoke the detailed logger and output something if it's enabled.
1012 private void DetailLog(string msg, params Object[] args)
1013 {
1014 if (m_prim.Scene.VehicleLoggingEnabled)
1015 m_prim.Scene.PhysicsLogging.Write(msg, args);
949 } 1016 }
950 } 1017 }
951} 1018}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index 130f1ca..71a4303 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -42,6 +42,8 @@ public sealed class BSPrim : PhysicsActor
42 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 42 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
43 private static readonly string LogHeader = "[BULLETS PRIM]"; 43 private static readonly string LogHeader = "[BULLETS PRIM]";
44 44
45 private void DebugLog(string mm, params Object[] xx) { if (_scene.shouldDebugLog) m_log.DebugFormat(mm, xx); }
46
45 private IMesh _mesh; 47 private IMesh _mesh;
46 private PrimitiveBaseShape _pbs; 48 private PrimitiveBaseShape _pbs;
47 private ShapeData.PhysicsShapeType _shapeType; 49 private ShapeData.PhysicsShapeType _shapeType;
@@ -50,6 +52,7 @@ public sealed class BSPrim : PhysicsActor
50 private List<ConvexResult> _hulls; 52 private List<ConvexResult> _hulls;
51 53
52 private BSScene _scene; 54 private BSScene _scene;
55 public BSScene Scene { get { return _scene; } }
53 private String _avName; 56 private String _avName;
54 private uint _localID = 0; 57 private uint _localID = 0;
55 58
@@ -86,8 +89,8 @@ public sealed class BSPrim : PhysicsActor
86 private bool _kinematic; 89 private bool _kinematic;
87 private float _buoyancy; 90 private float _buoyancy;
88 91
89 private List<BSPrim> _childrenPrims;
90 private BSPrim _parentPrim; 92 private BSPrim _parentPrim;
93 private List<BSPrim> _childrenPrims;
91 94
92 private int _subscribedEventsMs = 0; 95 private int _subscribedEventsMs = 0;
93 private int _nextCollisionOkTime = 0; 96 private int _nextCollisionOkTime = 0;
@@ -145,9 +148,19 @@ public sealed class BSPrim : PhysicsActor
145 public void Destroy() 148 public void Destroy()
146 { 149 {
147 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); 150 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID);
151 // DetailLog("{0},Destroy", LocalID);
148 // Undo any vehicle properties 152 // Undo any vehicle properties
149 _vehicle.ProcessTypeChange(Vehicle.TYPE_NONE); 153 _vehicle.ProcessTypeChange(Vehicle.TYPE_NONE);
150 _scene.RemoveVehiclePrim(this); // just to make sure 154 _scene.RemoveVehiclePrim(this); // just to make sure
155
156 // undo any dependance with/on other objects
157 if (_parentPrim != null)
158 {
159 // If I'm someone's child, tell them to forget about me.
160 _parentPrim.RemoveChildFromLinkset(this);
161 _parentPrim = null;
162 }
163
151 _scene.TaintedObject(delegate() 164 _scene.TaintedObject(delegate()
152 { 165 {
153 // everything in the C# world will get garbage collected. Tell the C++ world to free stuff. 166 // everything in the C# world will get garbage collected. Tell the C++ world to free stuff.
@@ -202,7 +215,8 @@ public sealed class BSPrim : PhysicsActor
202 // link me to the specified parent 215 // link me to the specified parent
203 public override void link(PhysicsActor obj) { 216 public override void link(PhysicsActor obj) {
204 BSPrim parent = obj as BSPrim; 217 BSPrim parent = obj as BSPrim;
205 // m_log.DebugFormat("{0}: link {1}/{2} to {3}", LogHeader, _avName, _localID, obj.LocalID); 218 DebugLog("{0}: link {1}/{2} to {3}", LogHeader, _avName, _localID, obj.LocalID);
219 DetailLog("{0},link,parent={1}", LocalID, obj.LocalID);
206 // TODO: decide if this parent checking needs to happen at taint time 220 // TODO: decide if this parent checking needs to happen at taint time
207 if (_parentPrim == null) 221 if (_parentPrim == null)
208 { 222 {
@@ -225,7 +239,7 @@ public sealed class BSPrim : PhysicsActor
225 else 239 else
226 { 240 {
227 // asking to reparent a prim should not happen 241 // asking to reparent a prim should not happen
228 m_log.ErrorFormat("{0}: Reparenting a prim. ", LogHeader); 242 m_log.ErrorFormat("{0}: link(): Reparenting a prim. ", LogHeader);
229 } 243 }
230 } 244 }
231 } 245 }
@@ -236,7 +250,9 @@ public sealed class BSPrim : PhysicsActor
236 public override void delink() { 250 public override void delink() {
237 // TODO: decide if this parent checking needs to happen at taint time 251 // TODO: decide if this parent checking needs to happen at taint time
238 // Race condition here: if link() and delink() in same simulation tick, the delink will not happen 252 // Race condition here: if link() and delink() in same simulation tick, the delink will not happen
239 // m_log.DebugFormat("{0}: delink {1}/{2}", LogHeader, _avName, _localID); 253 DebugLog("{0}: delink {1}/{2}. Parent={3}", LogHeader, _avName, _localID,
254 (_parentPrim==null ? "NULL" : _parentPrim._avName+"/"+_parentPrim.LocalID.ToString()));
255 DetailLog("{0},delink,parent={1}", LocalID, (_parentPrim==null ? "NULL" : _parentPrim.LocalID.ToString()));
240 if (_parentPrim != null) 256 if (_parentPrim != null)
241 { 257 {
242 _parentPrim.RemoveChildFromLinkset(this); 258 _parentPrim.RemoveChildFromLinkset(this);
@@ -252,8 +268,10 @@ public sealed class BSPrim : PhysicsActor
252 { 268 {
253 if (!_childrenPrims.Contains(child)) 269 if (!_childrenPrims.Contains(child))
254 { 270 {
271 DebugLog("{0}: AddChildToLinkset: adding child {1} to {2}", LogHeader, child.LocalID, this.LocalID);
272 DetailLog("{0},AddChildToLinkset,child={1}", LocalID, pchild.LocalID);
255 _childrenPrims.Add(child); 273 _childrenPrims.Add(child);
256 child.ParentPrim = this; // the child has gained a parent 274 child._parentPrim = this; // the child has gained a parent
257 RecreateGeomAndObject(); // rebuild my shape with the new child added 275 RecreateGeomAndObject(); // rebuild my shape with the new child added
258 } 276 }
259 }); 277 });
@@ -269,9 +287,14 @@ public sealed class BSPrim : PhysicsActor
269 { 287 {
270 if (_childrenPrims.Contains(child)) 288 if (_childrenPrims.Contains(child))
271 { 289 {
272 BulletSimAPI.RemoveConstraint(_scene.WorldID, child.LocalID, this.LocalID); 290 DebugLog("{0}: RemoveChildFromLinkset: Removing constraint to {1}", LogHeader, child.LocalID);
291 DetailLog("{0},RemoveChildToLinkset,child={1}", LocalID, pchild.LocalID);
292 if (!BulletSimAPI.RemoveConstraintByID(_scene.WorldID, child.LocalID))
293 {
294 m_log.ErrorFormat("{0}: RemoveChildFromLinkset: Failed remove constraint for {1}", LogHeader, child.LocalID);
295 }
273 _childrenPrims.Remove(child); 296 _childrenPrims.Remove(child);
274 child.ParentPrim = null; // the child has lost its parent 297 child._parentPrim = null; // the child has lost its parent
275 RecreateGeomAndObject(); // rebuild my shape with the child removed 298 RecreateGeomAndObject(); // rebuild my shape with the child removed
276 } 299 }
277 else 300 else
@@ -282,11 +305,6 @@ public sealed class BSPrim : PhysicsActor
282 return; 305 return;
283 } 306 }
284 307
285 public BSPrim ParentPrim
286 {
287 set { _parentPrim = value; }
288 }
289
290 // return true if we are the root of a linkset (there are children to manage) 308 // return true if we are the root of a linkset (there are children to manage)
291 public bool IsRootOfLinkset 309 public bool IsRootOfLinkset
292 { 310 {
@@ -304,20 +322,28 @@ public sealed class BSPrim : PhysicsActor
304 base.RequestPhysicsterseUpdate(); 322 base.RequestPhysicsterseUpdate();
305 } 323 }
306 324
307 public override void LockAngularMotion(OMV.Vector3 axis) { return; } 325 public override void LockAngularMotion(OMV.Vector3 axis)
326 {
327 DetailLog("{0},LockAngularMotion,call,axis={1}", LocalID, axis);
328 return;
329 }
308 330
309 public override OMV.Vector3 Position { 331 public override OMV.Vector3 Position {
310 get { 332 get {
311 // don't do the following GetObjectPosition because this function is called a zillion times 333 // child prims move around based on their parent. Need to get the latest location
334 if (_parentPrim != null)
335 _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
336 // don't do the GetObjectPosition for root elements because this function is called a zillion times
312 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); 337 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
313 return _position; 338 return _position;
314 } 339 }
315 set { 340 set {
316 _position = value; 341 _position = value;
342 // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint?
317 _scene.TaintedObject(delegate() 343 _scene.TaintedObject(delegate()
318 { 344 {
345 DetailLog("{0},SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
319 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); 346 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
320 // m_log.DebugFormat("{0}: setPosition: id={1}, position={2}", LogHeader, _localID, _position);
321 }); 347 });
322 } 348 }
323 } 349 }
@@ -330,6 +356,7 @@ public sealed class BSPrim : PhysicsActor
330 _force = value; 356 _force = value;
331 _scene.TaintedObject(delegate() 357 _scene.TaintedObject(delegate()
332 { 358 {
359 DetailLog("{0},SetForce,taint,force={1}", LocalID, _force);
333 BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force); 360 BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force);
334 }); 361 });
335 } 362 }
@@ -341,15 +368,23 @@ public sealed class BSPrim : PhysicsActor
341 } 368 }
342 set { 369 set {
343 Vehicle type = (Vehicle)value; 370 Vehicle type = (Vehicle)value;
344 _vehicle.ProcessTypeChange(type);
345 _scene.TaintedObject(delegate() 371 _scene.TaintedObject(delegate()
346 { 372 {
373 DetailLog("{0},SetVehicleType,taint,type={1}", LocalID, type);
374 _vehicle.ProcessTypeChange(type);
347 if (type == Vehicle.TYPE_NONE) 375 if (type == Vehicle.TYPE_NONE)
348 { 376 {
349 _scene.RemoveVehiclePrim(this); 377 _scene.RemoveVehiclePrim(this);
350 } 378 }
351 else 379 else
352 { 380 {
381 _scene.TaintedObject(delegate()
382 {
383 // Tell the physics engine to clear state
384 IntPtr obj = BulletSimAPI.GetBodyHandleWorldID2(_scene.WorldID, LocalID);
385 BulletSimAPI.ClearForces2(obj);
386 });
387
353 // make it so the scene will call us each tick to do vehicle things 388 // make it so the scene will call us each tick to do vehicle things
354 _scene.AddVehiclePrim(this); 389 _scene.AddVehiclePrim(this);
355 } 390 }
@@ -359,37 +394,52 @@ public sealed class BSPrim : PhysicsActor
359 } 394 }
360 public override void VehicleFloatParam(int param, float value) 395 public override void VehicleFloatParam(int param, float value)
361 { 396 {
362 _vehicle.ProcessFloatVehicleParam((Vehicle)param, value); 397 m_log.DebugFormat("{0} VehicleFloatParam. {1} <= {2}", LogHeader, param, value);
398 _scene.TaintedObject(delegate()
399 {
400 _vehicle.ProcessFloatVehicleParam((Vehicle)param, value, _scene.LastSimulatedTimestep);
401 });
363 } 402 }
364 public override void VehicleVectorParam(int param, OMV.Vector3 value) 403 public override void VehicleVectorParam(int param, OMV.Vector3 value)
365 { 404 {
366 _vehicle.ProcessVectorVehicleParam((Vehicle)param, value); 405 m_log.DebugFormat("{0} VehicleVectorParam. {1} <= {2}", LogHeader, param, value);
406 _scene.TaintedObject(delegate()
407 {
408 _vehicle.ProcessVectorVehicleParam((Vehicle)param, value, _scene.LastSimulatedTimestep);
409 });
367 } 410 }
368 public override void VehicleRotationParam(int param, OMV.Quaternion rotation) 411 public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
369 { 412 {
370 _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation); 413 m_log.DebugFormat("{0} VehicleRotationParam. {1} <= {2}", LogHeader, param, rotation);
414 _scene.TaintedObject(delegate()
415 {
416 _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation);
417 });
371 } 418 }
372 public override void VehicleFlags(int param, bool remove) 419 public override void VehicleFlags(int param, bool remove)
373 { 420 {
374 _vehicle.ProcessVehicleFlags(param, remove); 421 m_log.DebugFormat("{0} VehicleFlags. {1}. Remove={2}", LogHeader, param, remove);
422 _scene.TaintedObject(delegate()
423 {
424 _vehicle.ProcessVehicleFlags(param, remove);
425 });
375 } 426 }
376 // Called each simulation step to advance vehicle characteristics 427
428 // Called each simulation step to advance vehicle characteristics.
429 // Called from Scene when doing simulation step so we're in taint processing time.
377 public void StepVehicle(float timeStep) 430 public void StepVehicle(float timeStep)
378 { 431 {
379 _vehicle.Step(timeStep, _scene); 432 _vehicle.Step(timeStep);
380 } 433 }
381 434
382 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more 435 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
383 public override void SetVolumeDetect(int param) { 436 public override void SetVolumeDetect(int param) {
384 bool newValue = (param != 0); 437 bool newValue = (param != 0);
385 if (_isVolumeDetect != newValue) 438 _isVolumeDetect = newValue;
439 _scene.TaintedObject(delegate()
386 { 440 {
387 _isVolumeDetect = newValue; 441 SetObjectDynamic();
388 _scene.TaintedObject(delegate() 442 });
389 {
390 SetObjectDynamic();
391 });
392 }
393 return; 443 return;
394 } 444 }
395 445
@@ -397,9 +447,11 @@ public sealed class BSPrim : PhysicsActor
397 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } } 447 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } }
398 public override OMV.Vector3 Velocity { 448 public override OMV.Vector3 Velocity {
399 get { return _velocity; } 449 get { return _velocity; }
400 set { _velocity = value; 450 set {
451 _velocity = value;
401 _scene.TaintedObject(delegate() 452 _scene.TaintedObject(delegate()
402 { 453 {
454 DetailLog("{0},SetVelocity,taint,vel={1}", LocalID, _velocity);
403 BulletSimAPI.SetObjectVelocity(_scene.WorldID, LocalID, _velocity); 455 BulletSimAPI.SetObjectVelocity(_scene.WorldID, LocalID, _velocity);
404 }); 456 });
405 } 457 }
@@ -407,6 +459,7 @@ public sealed class BSPrim : PhysicsActor
407 public override OMV.Vector3 Torque { 459 public override OMV.Vector3 Torque {
408 get { return _torque; } 460 get { return _torque; }
409 set { _torque = value; 461 set { _torque = value;
462 DetailLog("{0},SetTorque,call,torque={1}", LocalID, _torque);
410 } 463 }
411 } 464 }
412 public override float CollisionScore { 465 public override float CollisionScore {
@@ -419,13 +472,21 @@ public sealed class BSPrim : PhysicsActor
419 set { _acceleration = value; } 472 set { _acceleration = value; }
420 } 473 }
421 public override OMV.Quaternion Orientation { 474 public override OMV.Quaternion Orientation {
422 get { return _orientation; } 475 get {
476 if (_parentPrim != null)
477 {
478 // children move around because tied to parent. Get a fresh value.
479 _orientation = BulletSimAPI.GetObjectOrientation(_scene.WorldID, LocalID);
480 }
481 return _orientation;
482 }
423 set { 483 set {
424 _orientation = value; 484 _orientation = value;
425 // m_log.DebugFormat("{0}: set orientation: id={1}, ori={2}", LogHeader, LocalID, _orientation); 485 // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint?
426 _scene.TaintedObject(delegate() 486 _scene.TaintedObject(delegate()
427 { 487 {
428 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); 488 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
489 DetailLog("{0},SetOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation);
429 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); 490 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
430 }); 491 });
431 } 492 }
@@ -458,8 +519,9 @@ public sealed class BSPrim : PhysicsActor
458 get { return !IsPhantom && !_isVolumeDetect; } 519 get { return !IsPhantom && !_isVolumeDetect; }
459 } 520 }
460 521
461 // make gravity work if the object is physical and not selected 522 // Make gravity work if the object is physical and not selected
462 // no locking here because only called when it is safe 523 // No locking here because only called when it is safe
524 // Only called at taint time so it is save to call into Bullet.
463 private void SetObjectDynamic() 525 private void SetObjectDynamic()
464 { 526 {
465 // m_log.DebugFormat("{0}: ID={1}, SetObjectDynamic: IsStatic={2}, IsSolid={3}", LogHeader, _localID, IsStatic, IsSolid); 527 // m_log.DebugFormat("{0}: ID={1}, SetObjectDynamic: IsStatic={2}, IsSolid={3}", LogHeader, _localID, IsStatic, IsSolid);
@@ -476,6 +538,7 @@ public sealed class BSPrim : PhysicsActor
476 RecreateGeomAndObject(); 538 RecreateGeomAndObject();
477 539
478 } 540 }
541 DetailLog("{0},SetObjectDynamic,taint,static={1},solid={2},mass={3}", LocalID, IsStatic, IsSolid, _mass);
479 BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), _mass); 542 BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), _mass);
480 } 543 }
481 544
@@ -516,11 +579,24 @@ public sealed class BSPrim : PhysicsActor
516 set { _floatOnWater = value; } 579 set { _floatOnWater = value; }
517 } 580 }
518 public override OMV.Vector3 RotationalVelocity { 581 public override OMV.Vector3 RotationalVelocity {
519 get { return _rotationalVelocity; } 582 get {
520 set { _rotationalVelocity = value; 583 /*
584 OMV.Vector3 pv = OMV.Vector3.Zero;
585 // if close to zero, report zero
586 // This is copied from ODE but I'm not sure why it returns zero but doesn't
587 // zero the property in the physics engine.
588 if (_rotationalVelocity.ApproxEquals(pv, 0.2f))
589 return pv;
590 */
591
592 return _rotationalVelocity;
593 }
594 set {
595 _rotationalVelocity = value;
521 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); 596 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
522 _scene.TaintedObject(delegate() 597 _scene.TaintedObject(delegate()
523 { 598 {
599 DetailLog("{0},SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
524 BulletSimAPI.SetObjectAngularVelocity(_scene.WorldID, LocalID, _rotationalVelocity); 600 BulletSimAPI.SetObjectAngularVelocity(_scene.WorldID, LocalID, _rotationalVelocity);
525 }); 601 });
526 } 602 }
@@ -533,11 +609,13 @@ public sealed class BSPrim : PhysicsActor
533 } 609 }
534 public override float Buoyancy { 610 public override float Buoyancy {
535 get { return _buoyancy; } 611 get { return _buoyancy; }
536 set { _buoyancy = value; 612 set {
537 _scene.TaintedObject(delegate() 613 _buoyancy = value;
538 { 614 _scene.TaintedObject(delegate()
539 BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, _localID, _buoyancy); 615 {
540 }); 616 DetailLog("{0},SetBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
617 BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, _localID, _buoyancy);
618 });
541 } 619 }
542 } 620 }
543 621
@@ -573,27 +651,45 @@ public sealed class BSPrim : PhysicsActor
573 public override float APIDStrength { set { return; } } 651 public override float APIDStrength { set { return; } }
574 public override float APIDDamping { set { return; } } 652 public override float APIDDamping { set { return; } }
575 653
654 private List<OMV.Vector3> m_accumulatedForces = new List<OMV.Vector3>();
576 public override void AddForce(OMV.Vector3 force, bool pushforce) { 655 public override void AddForce(OMV.Vector3 force, bool pushforce) {
577 if (force.IsFinite()) 656 if (force.IsFinite())
578 { 657 {
579 _force.X += force.X; 658 // _force += force;
580 _force.Y += force.Y; 659 lock (m_accumulatedForces)
581 _force.Z += force.Z; 660 m_accumulatedForces.Add(new OMV.Vector3(force));
582 } 661 }
583 else 662 else
584 { 663 {
585 m_log.WarnFormat("{0}: Got a NaN force applied to a Character", LogHeader); 664 m_log.WarnFormat("{0}: Got a NaN force applied to a Character", LogHeader);
665 return;
586 } 666 }
587 _scene.TaintedObject(delegate() 667 _scene.TaintedObject(delegate()
588 { 668 {
589 BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force); 669 lock (m_accumulatedForces)
670 {
671 if (m_accumulatedForces.Count > 0)
672 {
673 OMV.Vector3 fSum = OMV.Vector3.Zero;
674 foreach (OMV.Vector3 v in m_accumulatedForces)
675 {
676 fSum += v;
677 }
678 m_accumulatedForces.Clear();
679
680 DetailLog("{0},SetObjectForce,taint,force={1}", LocalID, fSum);
681 BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, fSum);
682 }
683 }
590 }); 684 });
591 } 685 }
592 686
593 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { 687 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
688 DetailLog("{0},AddAngularForce,call,angForce={1},push={2}", LocalID, force, pushforce);
594 // m_log.DebugFormat("{0}: AddAngularForce. f={1}, push={2}", LogHeader, force, pushforce); 689 // m_log.DebugFormat("{0}: AddAngularForce. f={1}, push={2}", LogHeader, force, pushforce);
595 } 690 }
596 public override void SetMomentum(OMV.Vector3 momentum) { 691 public override void SetMomentum(OMV.Vector3 momentum) {
692 DetailLog("{0},SetMomentum,call,mom={1}", LocalID, momentum);
597 } 693 }
598 public override void SubscribeEvents(int ms) { 694 public override void SubscribeEvents(int ms) {
599 _subscribedEventsMs = ms; 695 _subscribedEventsMs = ms;
@@ -918,6 +1014,7 @@ public sealed class BSPrim : PhysicsActor
918 { 1014 {
919 // m_log.DebugFormat("{0}: CreateGeom: Defaulting to sphere of size {1}", LogHeader, _size); 1015 // m_log.DebugFormat("{0}: CreateGeom: Defaulting to sphere of size {1}", LogHeader, _size);
920 _shapeType = ShapeData.PhysicsShapeType.SHAPE_SPHERE; 1016 _shapeType = ShapeData.PhysicsShapeType.SHAPE_SPHERE;
1017 DetailLog("{0},CreateGeom,sphere", LocalID);
921 // Bullet native objects are scaled by the Bullet engine so pass the size in 1018 // Bullet native objects are scaled by the Bullet engine so pass the size in
922 _scale = _size; 1019 _scale = _size;
923 } 1020 }
@@ -925,6 +1022,7 @@ public sealed class BSPrim : PhysicsActor
925 else 1022 else
926 { 1023 {
927 // m_log.DebugFormat("{0}: CreateGeom: Defaulting to box. lid={1}, size={2}", LogHeader, LocalID, _size); 1024 // m_log.DebugFormat("{0}: CreateGeom: Defaulting to box. lid={1}, size={2}", LogHeader, LocalID, _size);
1025 DetailLog("{0},CreateGeom,box", LocalID);
928 _shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX; 1026 _shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX;
929 _scale = _size; 1027 _scale = _size;
930 } 1028 }
@@ -961,10 +1059,12 @@ public sealed class BSPrim : PhysicsActor
961 // if this new shape is the same as last time, don't recreate the mesh 1059 // if this new shape is the same as last time, don't recreate the mesh
962 if (_meshKey == newMeshKey) return; 1060 if (_meshKey == newMeshKey) return;
963 1061
1062 DetailLog("{0},CreateGeomMesh,create,key={1}", LocalID, _meshKey);
964 // Since we're recreating new, get rid of any previously generated shape 1063 // Since we're recreating new, get rid of any previously generated shape
965 if (_meshKey != 0) 1064 if (_meshKey != 0)
966 { 1065 {
967 // m_log.DebugFormat("{0}: CreateGeom: deleting old mesh. lID={1}, Key={2}", LogHeader, _localID, _meshKey); 1066 // m_log.DebugFormat("{0}: CreateGeom: deleting old mesh. lID={1}, Key={2}", LogHeader, _localID, _meshKey);
1067 DetailLog("{0},CreateGeomMesh,deleteOld,key={1}", LocalID, _meshKey);
968 BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey); 1068 BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey);
969 _mesh = null; 1069 _mesh = null;
970 _meshKey = 0; 1070 _meshKey = 0;
@@ -981,7 +1081,6 @@ public sealed class BSPrim : PhysicsActor
981 int vi = 0; 1081 int vi = 0;
982 foreach (OMV.Vector3 vv in vertices) 1082 foreach (OMV.Vector3 vv in vertices)
983 { 1083 {
984 // m_log.DebugFormat("{0}: {1}: <{2:0.00}, {3:0.00}, {4:0.00}>", LogHeader, vi / 3, vv.X, vv.Y, vv.Z);
985 verticesAsFloats[vi++] = vv.X; 1084 verticesAsFloats[vi++] = vv.X;
986 verticesAsFloats[vi++] = vv.Y; 1085 verticesAsFloats[vi++] = vv.Y;
987 verticesAsFloats[vi++] = vv.Z; 1086 verticesAsFloats[vi++] = vv.Z;
@@ -995,6 +1094,7 @@ public sealed class BSPrim : PhysicsActor
995 _shapeType = ShapeData.PhysicsShapeType.SHAPE_MESH; 1094 _shapeType = ShapeData.PhysicsShapeType.SHAPE_MESH;
996 // meshes are already scaled by the meshmerizer 1095 // meshes are already scaled by the meshmerizer
997 _scale = new OMV.Vector3(1f, 1f, 1f); 1096 _scale = new OMV.Vector3(1f, 1f, 1f);
1097 DetailLog("{0},CreateGeomMesh,done", LocalID);
998 return; 1098 return;
999 } 1099 }
1000 1100
@@ -1008,13 +1108,17 @@ public sealed class BSPrim : PhysicsActor
1008 // if the hull hasn't changed, don't rebuild it 1108 // if the hull hasn't changed, don't rebuild it
1009 if (newHullKey == _hullKey) return; 1109 if (newHullKey == _hullKey) return;
1010 1110
1111 DetailLog("{0},CreateGeomHull,create,key={1}", LocalID, _meshKey);
1112
1011 // Since we're recreating new, get rid of any previously generated shape 1113 // Since we're recreating new, get rid of any previously generated shape
1012 if (_hullKey != 0) 1114 if (_hullKey != 0)
1013 { 1115 {
1014 // m_log.DebugFormat("{0}: CreateGeom: deleting old hull. Key={1}", LogHeader, _hullKey); 1116 // m_log.DebugFormat("{0}: CreateGeom: deleting old hull. Key={1}", LogHeader, _hullKey);
1117 DetailLog("{0},CreateGeomHull,deleteOldHull,key={1}", LocalID, _meshKey);
1015 BulletSimAPI.DestroyHull(_scene.WorldID, _hullKey); 1118 BulletSimAPI.DestroyHull(_scene.WorldID, _hullKey);
1016 _hullKey = 0; 1119 _hullKey = 0;
1017 _hulls.Clear(); 1120 _hulls.Clear();
1121 DetailLog("{0},CreateGeomHull,deleteOldMesh,key={1}", LocalID, _meshKey);
1018 BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey); 1122 BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey);
1019 _mesh = null; // the mesh cannot match either 1123 _mesh = null; // the mesh cannot match either
1020 _meshKey = 0; 1124 _meshKey = 0;
@@ -1111,6 +1215,7 @@ public sealed class BSPrim : PhysicsActor
1111 _shapeType = ShapeData.PhysicsShapeType.SHAPE_HULL; 1215 _shapeType = ShapeData.PhysicsShapeType.SHAPE_HULL;
1112 // meshes are already scaled by the meshmerizer 1216 // meshes are already scaled by the meshmerizer
1113 _scale = new OMV.Vector3(1f, 1f, 1f); 1217 _scale = new OMV.Vector3(1f, 1f, 1f);
1218 DetailLog("{0},CreateGeomHull,done", LocalID);
1114 return; 1219 return;
1115 } 1220 }
1116 1221
@@ -1129,7 +1234,6 @@ public sealed class BSPrim : PhysicsActor
1129 if (IsRootOfLinkset) 1234 if (IsRootOfLinkset)
1130 { 1235 {
1131 // Create a linkset around this object 1236 // Create a linkset around this object
1132 // CreateLinksetWithCompoundHull();
1133 CreateLinksetWithConstraints(); 1237 CreateLinksetWithConstraints();
1134 } 1238 }
1135 else 1239 else
@@ -1191,33 +1295,33 @@ public sealed class BSPrim : PhysicsActor
1191 // TODO: make this more effeicient: a large linkset gets rebuilt over and over and prims are added 1295 // TODO: make this more effeicient: a large linkset gets rebuilt over and over and prims are added
1192 void CreateLinksetWithConstraints() 1296 void CreateLinksetWithConstraints()
1193 { 1297 {
1194 // m_log.DebugFormat("{0}: CreateLinkset. Root prim={1}, prims={2}", LogHeader, LocalID, _childrenPrims.Count+1); 1298 DebugLog("{0}: CreateLinkset. Root prim={1}, prims={2}", LogHeader, LocalID, _childrenPrims.Count+1);
1195 1299
1196 // remove any constraints that might be in place 1300 // remove any constraints that might be in place
1197 foreach (BSPrim prim in _childrenPrims) 1301 foreach (BSPrim prim in _childrenPrims)
1198 { 1302 {
1199 // m_log.DebugFormat("{0}: CreateLinkset: RemoveConstraint between root prim {1} and child prim {2}", LogHeader, LocalID, prim.LocalID); 1303 DebugLog("{0}: CreateLinkset: RemoveConstraint between root prim {1} and child prim {2}", LogHeader, LocalID, prim.LocalID);
1200 BulletSimAPI.RemoveConstraint(_scene.WorldID, LocalID, prim.LocalID); 1304 BulletSimAPI.RemoveConstraint(_scene.WorldID, LocalID, prim.LocalID);
1201 } 1305 }
1202 // create constraints between the root prim and each of the children 1306 // create constraints between the root prim and each of the children
1203 foreach (BSPrim prim in _childrenPrims) 1307 foreach (BSPrim prim in _childrenPrims)
1204 { 1308 {
1205 // m_log.DebugFormat("{0}: CreateLinkset: AddConstraint between root prim {1} and child prim {2}", LogHeader, LocalID, prim.LocalID);
1206
1207 // Zero motion for children so they don't interpolate 1309 // Zero motion for children so they don't interpolate
1208 prim.ZeroMotion(); 1310 prim.ZeroMotion();
1209 1311
1210 // relative position normalized to the root prim 1312 // relative position normalized to the root prim
1211 OMV.Vector3 childRelativePosition = (prim._position - this._position) * OMV.Quaternion.Inverse(this._orientation); 1313 OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(this._orientation);
1314 OMV.Vector3 childRelativePosition = (prim._position - this._position) * invThisOrientation;
1212 1315
1213 // relative rotation of the child to the parent 1316 // relative rotation of the child to the parent
1214 OMV.Quaternion relativeRotation = OMV.Quaternion.Inverse(prim._orientation) * this._orientation; 1317 OMV.Quaternion childRelativeRotation = invThisOrientation * prim._orientation;
1215 1318
1216 // this is a constraint that allows no freedom of movement between the two objects 1319 // this is a constraint that allows no freedom of movement between the two objects
1217 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 1320 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
1321 DebugLog("{0}: CreateLinkset: Adding a constraint between root prim {1} and child prim {2}", LogHeader, LocalID, prim.LocalID);
1218 BulletSimAPI.AddConstraint(_scene.WorldID, LocalID, prim.LocalID, 1322 BulletSimAPI.AddConstraint(_scene.WorldID, LocalID, prim.LocalID,
1219 childRelativePosition, 1323 childRelativePosition,
1220 relativeRotation, 1324 childRelativeRotation,
1221 OMV.Vector3.Zero, 1325 OMV.Vector3.Zero,
1222 OMV.Quaternion.Identity, 1326 OMV.Quaternion.Identity,
1223 OMV.Vector3.Zero, OMV.Vector3.Zero, 1327 OMV.Vector3.Zero, OMV.Vector3.Zero,
@@ -1252,78 +1356,71 @@ public sealed class BSPrim : PhysicsActor
1252 const float POSITION_TOLERANCE = 0.05f; 1356 const float POSITION_TOLERANCE = 0.05f;
1253 const float ACCELERATION_TOLERANCE = 0.01f; 1357 const float ACCELERATION_TOLERANCE = 0.01f;
1254 const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f; 1358 const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f;
1255 const bool SHOULD_DAMP_UPDATES = false;
1256 1359
1257 public void UpdateProperties(EntityProperties entprop) 1360 public void UpdateProperties(EntityProperties entprop)
1258 { 1361 {
1362 /*
1259 UpdatedProperties changed = 0; 1363 UpdatedProperties changed = 0;
1260 if (SHOULD_DAMP_UPDATES) 1364 // assign to the local variables so the normal set action does not happen
1365 // if (_position != entprop.Position)
1366 if (!_position.ApproxEquals(entprop.Position, POSITION_TOLERANCE))
1261 { 1367 {
1262 // assign to the local variables so the normal set action does not happen 1368 _position = entprop.Position;
1263 // if (_position != entprop.Position) 1369 changed |= UpdatedProperties.Position;
1264 if (!_position.ApproxEquals(entprop.Position, POSITION_TOLERANCE))
1265 {
1266 _position = entprop.Position;
1267 // m_log.DebugFormat("{0}: UpdateProperties: id={1}, pos = {2}", LogHeader, LocalID, _position);
1268 changed |= UpdatedProperties.Position;
1269 }
1270 // if (_orientation != entprop.Rotation)
1271 if (!_orientation.ApproxEquals(entprop.Rotation, ROTATION_TOLERANCE))
1272 {
1273 _orientation = entprop.Rotation;
1274 // m_log.DebugFormat("{0}: UpdateProperties: id={1}, rot = {2}", LogHeader, LocalID, _orientation);
1275 changed |= UpdatedProperties.Rotation;
1276 }
1277 // if (_velocity != entprop.Velocity)
1278 if (!_velocity.ApproxEquals(entprop.Velocity, VELOCITY_TOLERANCE))
1279 {
1280 _velocity = entprop.Velocity;
1281 // m_log.DebugFormat("{0}: UpdateProperties: velocity = {1}", LogHeader, _velocity);
1282 changed |= UpdatedProperties.Velocity;
1283 }
1284 // if (_acceleration != entprop.Acceleration)
1285 if (!_acceleration.ApproxEquals(entprop.Acceleration, ACCELERATION_TOLERANCE))
1286 {
1287 _acceleration = entprop.Acceleration;
1288 // m_log.DebugFormat("{0}: UpdateProperties: acceleration = {1}", LogHeader, _acceleration);
1289 changed |= UpdatedProperties.Acceleration;
1290 }
1291 // if (_rotationalVelocity != entprop.RotationalVelocity)
1292 if (!_rotationalVelocity.ApproxEquals(entprop.RotationalVelocity, ROTATIONAL_VELOCITY_TOLERANCE))
1293 {
1294 _rotationalVelocity = entprop.RotationalVelocity;
1295 // m_log.DebugFormat("{0}: UpdateProperties: rotationalVelocity = {1}", LogHeader, _rotationalVelocity);
1296 changed |= UpdatedProperties.RotationalVel;
1297 }
1298 if (changed != 0)
1299 {
1300 // m_log.DebugFormat("{0}: UpdateProperties: id={1}, c={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation);
1301 // Only update the position of single objects and linkset roots
1302 if (this._parentPrim == null)
1303 {
1304 // m_log.DebugFormat("{0}: RequestTerseUpdate. id={1}, ch={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation);
1305 base.RequestPhysicsterseUpdate();
1306 }
1307 }
1308 } 1370 }
1309 else 1371 // if (_orientation != entprop.Rotation)
1372 if (!_orientation.ApproxEquals(entprop.Rotation, ROTATION_TOLERANCE))
1310 { 1373 {
1311 // Don't check for damping here -- it's done in BulletSim and SceneObjectPart. 1374 _orientation = entprop.Rotation;
1312 1375 changed |= UpdatedProperties.Rotation;
1313 // Only updates only for individual prims and for the root object of a linkset. 1376 }
1377 // if (_velocity != entprop.Velocity)
1378 if (!_velocity.ApproxEquals(entprop.Velocity, VELOCITY_TOLERANCE))
1379 {
1380 _velocity = entprop.Velocity;
1381 changed |= UpdatedProperties.Velocity;
1382 }
1383 // if (_acceleration != entprop.Acceleration)
1384 if (!_acceleration.ApproxEquals(entprop.Acceleration, ACCELERATION_TOLERANCE))
1385 {
1386 _acceleration = entprop.Acceleration;
1387 changed |= UpdatedProperties.Acceleration;
1388 }
1389 // if (_rotationalVelocity != entprop.RotationalVelocity)
1390 if (!_rotationalVelocity.ApproxEquals(entprop.RotationalVelocity, ROTATIONAL_VELOCITY_TOLERANCE))
1391 {
1392 _rotationalVelocity = entprop.RotationalVelocity;
1393 changed |= UpdatedProperties.RotationalVel;
1394 }
1395 if (changed != 0)
1396 {
1397 // Only update the position of single objects and linkset roots
1314 if (this._parentPrim == null) 1398 if (this._parentPrim == null)
1315 { 1399 {
1316 // Assign to the local variables so the normal set action does not happen
1317 _position = entprop.Position;
1318 _orientation = entprop.Rotation;
1319 _velocity = entprop.Velocity;
1320 _acceleration = entprop.Acceleration;
1321 _rotationalVelocity = entprop.RotationalVelocity;
1322 // m_log.DebugFormat("{0}: RequestTerseUpdate. id={1}, ch={2}, pos={3}, rot={4}, vel={5}, acc={6}, rvel={7}",
1323 // LogHeader, LocalID, changed, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
1324 base.RequestPhysicsterseUpdate(); 1400 base.RequestPhysicsterseUpdate();
1325 } 1401 }
1326 } 1402 }
1403 */
1404
1405 // Don't check for damping here -- it's done in BulletSim and SceneObjectPart.
1406
1407 // Updates only for individual prims and for the root object of a linkset.
1408 if (this._parentPrim == null)
1409 {
1410 // Assign to the local variables so the normal set action does not happen
1411 _position = entprop.Position;
1412 _orientation = entprop.Rotation;
1413 _velocity = entprop.Velocity;
1414 _acceleration = entprop.Acceleration;
1415 _rotationalVelocity = entprop.RotationalVelocity;
1416
1417 // m_log.DebugFormat("{0}: RequestTerseUpdate. id={1}, ch={2}, pos={3}, rot={4}, vel={5}, acc={6}, rvel={7}",
1418 // LogHeader, LocalID, changed, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
1419 DetailLog("{0},UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
1420 LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
1421
1422 base.RequestPhysicsterseUpdate();
1423 }
1327 } 1424 }
1328 1425
1329 // I've collided with something 1426 // I've collided with something
@@ -1362,5 +1459,11 @@ public sealed class BSPrim : PhysicsActor
1362 collisionCollection.Clear(); 1459 collisionCollection.Clear();
1363 } 1460 }
1364 } 1461 }
1462
1463 // Invoke the detailed logger and output something if it's enabled.
1464 private void DetailLog(string msg, params Object[] args)
1465 {
1466 Scene.PhysicsLogging.Write(msg, args);
1467 }
1365} 1468}
1366} 1469}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index 417cb5f..8773485 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -29,12 +29,14 @@ using System.Collections.Generic;
29using System.Runtime.InteropServices; 29using System.Runtime.InteropServices;
30using System.Text; 30using System.Text;
31using System.Threading; 31using System.Threading;
32using Nini.Config;
33using log4net;
34using OpenSim.Framework; 32using OpenSim.Framework;
33using OpenSim.Region.Framework;
34using OpenSim.Region.CoreModules;
35using Logging = OpenSim.Region.CoreModules.Framework.Statistics.Logging;
35using OpenSim.Region.Physics.Manager; 36using OpenSim.Region.Physics.Manager;
37using Nini.Config;
38using log4net;
36using OpenMetaverse; 39using OpenMetaverse;
37using OpenSim.Region.Framework;
38 40
39// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) 41// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim)
40// Debug linkset 42// Debug linkset
@@ -44,15 +46,17 @@ using OpenSim.Region.Framework;
44// Compute physics FPS reasonably 46// Compute physics FPS reasonably
45// Based on material, set density and friction 47// Based on material, set density and friction
46// More efficient memory usage when passing hull information from BSPrim to BulletSim 48// More efficient memory usage when passing hull information from BSPrim to BulletSim
49// Move all logic out of the C++ code and into the C# code for easier future modifications.
47// Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly? 50// Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly?
48// In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground) 51// In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground)
49// At the moment, physical and phantom causes object to drop through the terrain 52// At the moment, physical and phantom causes object to drop through the terrain
50// Physical phantom objects and related typing (collision options ) 53// Physical phantom objects and related typing (collision options )
54// Use collision masks for collision with terrain and phantom objects
51// Check out llVolumeDetect. Must do something for that. 55// Check out llVolumeDetect. Must do something for that.
52// Should prim.link() and prim.delink() membership checking happen at taint time? 56// Should prim.link() and prim.delink() membership checking happen at taint time?
57// changing the position and orientation of a linked prim must rebuild the constraint with the root.
53// Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once 58// Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once
54// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect 59// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect
55// Use collision masks for collision with terrain and phantom objects
56// Implement the genCollisions feature in BulletSim::SetObjectProperties (don't pass up unneeded collisions) 60// Implement the genCollisions feature in BulletSim::SetObjectProperties (don't pass up unneeded collisions)
57// Implement LockAngularMotion 61// Implement LockAngularMotion
58// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation) 62// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation)
@@ -60,9 +64,6 @@ using OpenSim.Region.Framework;
60// Remove mesh and Hull stuff. Use mesh passed to bullet and use convexdecom from bullet. 64// Remove mesh and Hull stuff. Use mesh passed to bullet and use convexdecom from bullet.
61// Add PID movement operations. What does ScenePresence.MoveToTarget do? 65// Add PID movement operations. What does ScenePresence.MoveToTarget do?
62// Check terrain size. 128 or 127? 66// Check terrain size. 128 or 127?
63// Multiple contact points on collision?
64// See code in ode::near... calls to collision_accounting_events()
65// (This might not be a problem. ODE collects all the collisions with one object in one tick.)
66// Raycast 67// Raycast
67// 68//
68namespace OpenSim.Region.Physics.BulletSPlugin 69namespace OpenSim.Region.Physics.BulletSPlugin
@@ -72,6 +73,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
72 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 73 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
73 private static readonly string LogHeader = "[BULLETS SCENE]"; 74 private static readonly string LogHeader = "[BULLETS SCENE]";
74 75
76 private void DebugLog(string mm, params Object[] xx) { if (shouldDebugLog) m_log.DebugFormat(mm, xx); }
77
75 public string BulletSimVersion = "?"; 78 public string BulletSimVersion = "?";
76 79
77 private Dictionary<uint, BSCharacter> m_avatars = new Dictionary<uint, BSCharacter>(); 80 private Dictionary<uint, BSCharacter> m_avatars = new Dictionary<uint, BSCharacter>();
@@ -105,6 +108,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
105 private long m_simulationStep = 0; 108 private long m_simulationStep = 0;
106 public long SimulationStep { get { return m_simulationStep; } } 109 public long SimulationStep { get { return m_simulationStep; } }
107 110
111 public float LastSimulatedTimestep { get; private set; }
112
108 // A value of the time now so all the collision and update routines do not have to get their own 113 // A value of the time now so all the collision and update routines do not have to get their own
109 // Set to 'now' just before all the prims and actors are called for collisions and updates 114 // Set to 'now' just before all the prims and actors are called for collisions and updates
110 private int m_simulationNowTime; 115 private int m_simulationNowTime;
@@ -121,6 +126,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
121 private bool _meshSculptedPrim = true; // cause scuplted prims to get meshed 126 private bool _meshSculptedPrim = true; // cause scuplted prims to get meshed
122 private bool _forceSimplePrimMeshing = false; // if a cube or sphere, let Bullet do internal shapes 127 private bool _forceSimplePrimMeshing = false; // if a cube or sphere, let Bullet do internal shapes
123 128
129 public float PID_D { get; private set; } // derivative
130 public float PID_P { get; private set; } // proportional
131
124 public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero 132 public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero
125 public const uint GROUNDPLANE_ID = 1; 133 public const uint GROUNDPLANE_ID = 1;
126 134
@@ -147,8 +155,20 @@ public class BSScene : PhysicsScene, IPhysicsParameters
147 ConfigurationParameters[] m_params; 155 ConfigurationParameters[] m_params;
148 GCHandle m_paramsHandle; 156 GCHandle m_paramsHandle;
149 157
158 public bool shouldDebugLog { get; private set; }
159
150 private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle; 160 private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle;
151 161
162 // Sometimes you just have to log everything.
163 public Logging.LogWriter PhysicsLogging;
164 private bool m_physicsLoggingEnabled;
165 private string m_physicsLoggingDir;
166 private string m_physicsLoggingPrefix;
167 private int m_physicsLoggingFileMinutes;
168
169 private bool m_vehicleLoggingEnabled;
170 public bool VehicleLoggingEnabled { get { return m_vehicleLoggingEnabled; } }
171
152 public BSScene(string identifier) 172 public BSScene(string identifier)
153 { 173 {
154 m_initialized = false; 174 m_initialized = false;
@@ -169,17 +189,32 @@ public class BSScene : PhysicsScene, IPhysicsParameters
169 m_updateArray = new EntityProperties[m_maxUpdatesPerFrame]; 189 m_updateArray = new EntityProperties[m_maxUpdatesPerFrame];
170 m_updateArrayPinnedHandle = GCHandle.Alloc(m_updateArray, GCHandleType.Pinned); 190 m_updateArrayPinnedHandle = GCHandle.Alloc(m_updateArray, GCHandleType.Pinned);
171 191
192 // Enable very detailed logging.
193 // By creating an empty logger when not logging, the log message invocation code
194 // can be left in and every call doesn't have to check for null.
195 if (m_physicsLoggingEnabled)
196 {
197 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes);
198 }
199 else
200 {
201 PhysicsLogging = new Logging.LogWriter();
202 }
203
172 // Get the version of the DLL 204 // Get the version of the DLL
173 // TODO: this doesn't work yet. Something wrong with marshaling the returned string. 205 // TODO: this doesn't work yet. Something wrong with marshaling the returned string.
174 // BulletSimVersion = BulletSimAPI.GetVersion(); 206 // BulletSimVersion = BulletSimAPI.GetVersion();
175 // m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion); 207 // m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion);
176 208
177 // if Debug, enable logging from the unmanaged code 209 // if Debug, enable logging from the unmanaged code
178 if (m_log.IsDebugEnabled) 210 if (m_log.IsDebugEnabled || PhysicsLogging.Enabled)
179 { 211 {
180 m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader); 212 m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader);
181 // the handle is saved to it doesn't get freed after this call 213 if (PhysicsLogging.Enabled)
182 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger); 214 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLoggerPhysLog);
215 else
216 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger);
217 // the handle is saved in a variable to make sure it doesn't get freed after this call
183 BulletSimAPI.SetDebugLogCallback(m_DebugLogCallbackHandle); 218 BulletSimAPI.SetDebugLogCallback(m_DebugLogCallbackHandle);
184 } 219 }
185 220
@@ -209,6 +244,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
209 m_meshLOD = 8f; 244 m_meshLOD = 8f;
210 m_sculptLOD = 32f; 245 m_sculptLOD = 32f;
211 246
247 shouldDebugLog = false;
212 m_detailedStatsStep = 0; // disabled 248 m_detailedStatsStep = 0; // disabled
213 249
214 m_maxSubSteps = 10; 250 m_maxSubSteps = 10;
@@ -217,6 +253,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
217 m_maxUpdatesPerFrame = 2048; 253 m_maxUpdatesPerFrame = 2048;
218 m_maximumObjectMass = 10000.01f; 254 m_maximumObjectMass = 10000.01f;
219 255
256 PID_D = 2200f;
257 PID_P = 900f;
258
220 parms.defaultFriction = 0.5f; 259 parms.defaultFriction = 0.5f;
221 parms.defaultDensity = 10.000006836f; // Aluminum g/cm3 260 parms.defaultDensity = 10.000006836f; // Aluminum g/cm3
222 parms.defaultRestitution = 0f; 261 parms.defaultRestitution = 0f;
@@ -261,7 +300,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
261 _meshSculptedPrim = pConfig.GetBoolean("MeshSculptedPrim", _meshSculptedPrim); 300 _meshSculptedPrim = pConfig.GetBoolean("MeshSculptedPrim", _meshSculptedPrim);
262 _forceSimplePrimMeshing = pConfig.GetBoolean("ForceSimplePrimMeshing", _forceSimplePrimMeshing); 301 _forceSimplePrimMeshing = pConfig.GetBoolean("ForceSimplePrimMeshing", _forceSimplePrimMeshing);
263 302
303 shouldDebugLog = pConfig.GetBoolean("ShouldDebugLog", shouldDebugLog);
264 m_detailedStatsStep = pConfig.GetInt("DetailedStatsStep", m_detailedStatsStep); 304 m_detailedStatsStep = pConfig.GetInt("DetailedStatsStep", m_detailedStatsStep);
305
265 m_meshLOD = pConfig.GetFloat("MeshLevelOfDetail", m_meshLOD); 306 m_meshLOD = pConfig.GetFloat("MeshLevelOfDetail", m_meshLOD);
266 m_sculptLOD = pConfig.GetFloat("SculptLevelOfDetail", m_sculptLOD); 307 m_sculptLOD = pConfig.GetFloat("SculptLevelOfDetail", m_sculptLOD);
267 308
@@ -271,6 +312,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
271 m_maxUpdatesPerFrame = pConfig.GetInt("MaxUpdatesPerFrame", m_maxUpdatesPerFrame); 312 m_maxUpdatesPerFrame = pConfig.GetInt("MaxUpdatesPerFrame", m_maxUpdatesPerFrame);
272 m_maximumObjectMass = pConfig.GetFloat("MaxObjectMass", m_maximumObjectMass); 313 m_maximumObjectMass = pConfig.GetFloat("MaxObjectMass", m_maximumObjectMass);
273 314
315 PID_D = pConfig.GetFloat("PIDDerivative", PID_D);
316 PID_P = pConfig.GetFloat("PIDProportional", PID_P);
317
274 parms.defaultFriction = pConfig.GetFloat("DefaultFriction", parms.defaultFriction); 318 parms.defaultFriction = pConfig.GetFloat("DefaultFriction", parms.defaultFriction);
275 parms.defaultDensity = pConfig.GetFloat("DefaultDensity", parms.defaultDensity); 319 parms.defaultDensity = pConfig.GetFloat("DefaultDensity", parms.defaultDensity);
276 parms.defaultRestitution = pConfig.GetFloat("DefaultRestitution", parms.defaultRestitution); 320 parms.defaultRestitution = pConfig.GetFloat("DefaultRestitution", parms.defaultRestitution);
@@ -303,6 +347,14 @@ public class BSScene : PhysicsScene, IPhysicsParameters
303 parms.shouldSplitSimulationIslands = ParamBoolean(pConfig, "ShouldSplitSimulationIslands", parms.shouldSplitSimulationIslands); 347 parms.shouldSplitSimulationIslands = ParamBoolean(pConfig, "ShouldSplitSimulationIslands", parms.shouldSplitSimulationIslands);
304 parms.shouldEnableFrictionCaching = ParamBoolean(pConfig, "ShouldEnableFrictionCaching", parms.shouldEnableFrictionCaching); 348 parms.shouldEnableFrictionCaching = ParamBoolean(pConfig, "ShouldEnableFrictionCaching", parms.shouldEnableFrictionCaching);
305 parms.numberOfSolverIterations = pConfig.GetFloat("NumberOfSolverIterations", parms.numberOfSolverIterations); 349 parms.numberOfSolverIterations = pConfig.GetFloat("NumberOfSolverIterations", parms.numberOfSolverIterations);
350
351 // Very detailed logging for physics debugging
352 m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false);
353 m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", ".");
354 m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-");
355 m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5);
356 // Very detailed logging for vehicle debugging
357 m_vehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false);
306 } 358 }
307 } 359 }
308 m_params[0] = parms; 360 m_params[0] = parms;
@@ -323,12 +375,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters
323 return ret; 375 return ret;
324 } 376 }
325 377
326
327 // Called directly from unmanaged code so don't do much 378 // Called directly from unmanaged code so don't do much
328 private void BulletLogger(string msg) 379 private void BulletLogger(string msg)
329 { 380 {
330 m_log.Debug("[BULLETS UNMANAGED]:" + msg); 381 m_log.Debug("[BULLETS UNMANAGED]:" + msg);
331 } 382 }
383
384 // Called directly from unmanaged code so don't do much
385 private void BulletLoggerPhysLog(string msg)
386 {
387 PhysicsLogging.Write("[BULLETS UNMANAGED]:" + msg);
388 }
332 389
333 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying) 390 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying)
334 { 391 {
@@ -347,34 +404,42 @@ public class BSScene : PhysicsScene, IPhysicsParameters
347 public override void RemoveAvatar(PhysicsActor actor) 404 public override void RemoveAvatar(PhysicsActor actor)
348 { 405 {
349 // m_log.DebugFormat("{0}: RemoveAvatar", LogHeader); 406 // m_log.DebugFormat("{0}: RemoveAvatar", LogHeader);
350 if (actor is BSCharacter) 407 BSCharacter bsactor = actor as BSCharacter;
351 { 408 if (bsactor != null)
352 ((BSCharacter)actor).Destroy();
353 }
354 try
355 { 409 {
356 lock (m_avatars) m_avatars.Remove(actor.LocalID); 410 try
357 } 411 {
358 catch (Exception e) 412 lock (m_avatars) m_avatars.Remove(actor.LocalID);
359 { 413 }
360 m_log.WarnFormat("{0}: Attempt to remove avatar that is not in physics scene: {1}", LogHeader, e); 414 catch (Exception e)
415 {
416 m_log.WarnFormat("{0}: Attempt to remove avatar that is not in physics scene: {1}", LogHeader, e);
417 }
418 bsactor.Destroy();
419 // bsactor.dispose();
361 } 420 }
362 } 421 }
363 422
364 public override void RemovePrim(PhysicsActor prim) 423 public override void RemovePrim(PhysicsActor prim)
365 { 424 {
366 // m_log.DebugFormat("{0}: RemovePrim", LogHeader); 425 BSPrim bsprim = prim as BSPrim;
367 if (prim is BSPrim) 426 if (bsprim != null)
368 {
369 ((BSPrim)prim).Destroy();
370 }
371 try
372 { 427 {
373 lock (m_prims) m_prims.Remove(prim.LocalID); 428 m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID);
429 try
430 {
431 lock (m_prims) m_prims.Remove(bsprim.LocalID);
432 }
433 catch (Exception e)
434 {
435 m_log.ErrorFormat("{0}: Attempt to remove prim that is not in physics scene: {1}", LogHeader, e);
436 }
437 bsprim.Destroy();
438 // bsprim.dispose();
374 } 439 }
375 catch (Exception e) 440 else
376 { 441 {
377 m_log.WarnFormat("{0}: Attempt to remove prim that is not in physics scene: {1}", LogHeader, e); 442 m_log.ErrorFormat("{0}: Attempt to remove prim that is not a BSPrim type.", LogHeader);
378 } 443 }
379 } 444 }
380 445
@@ -400,6 +465,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
400 int collidersCount; 465 int collidersCount;
401 IntPtr collidersPtr; 466 IntPtr collidersPtr;
402 467
468 LastSimulatedTimestep = timeStep;
469
403 // prevent simulation until we've been initialized 470 // prevent simulation until we've been initialized
404 if (!m_initialized) return 10.0f; 471 if (!m_initialized) return 10.0f;
405 472
@@ -459,7 +526,6 @@ public class BSScene : PhysicsScene, IPhysicsParameters
459 for (int ii = 0; ii < updatedEntityCount; ii++) 526 for (int ii = 0; ii < updatedEntityCount; ii++)
460 { 527 {
461 EntityProperties entprop = m_updateArray[ii]; 528 EntityProperties entprop = m_updateArray[ii];
462 // m_log.DebugFormat("{0}: entprop[{1}]: id={2}, pos={3}", LogHeader, ii, entprop.ID, entprop.Position);
463 BSPrim prim; 529 BSPrim prim;
464 if (m_prims.TryGetValue(entprop.ID, out prim)) 530 if (m_prims.TryGetValue(entprop.ID, out prim))
465 { 531 {
@@ -532,8 +598,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters
532 }); 598 });
533 } 599 }
534 600
601 // Someday we will have complex terrain with caves and tunnels
602 // For the moment, it's flat and convex
603 public float GetTerrainHeightAtXYZ(Vector3 loc)
604 {
605 return GetTerrainHeightAtXY(loc.X, loc.Y);
606 }
607
535 public float GetTerrainHeightAtXY(float tX, float tY) 608 public float GetTerrainHeightAtXY(float tX, float tY)
536 { 609 {
610 if (tX < 0 || tX >= Constants.RegionSize || tY < 0 || tY >= Constants.RegionSize)
611 return 30;
537 return m_heightMap[((int)tX) * Constants.RegionSize + ((int)tY)]; 612 return m_heightMap[((int)tX) * Constants.RegionSize + ((int)tY)];
538 } 613 }
539 614
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
index 086f0dc..babb707 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
@@ -146,6 +146,22 @@ public struct ConfigurationParameters
146 public const float numericFalse = 0f; 146 public const float numericFalse = 0f;
147} 147}
148 148
149// Values used by Bullet and BulletSim to control collisions
150public enum CollisionFlags : uint
151{
152 STATIC_OBJECT = 1 << 0,
153 KINEMATIC_OBJECT = 1 << 1,
154 NO_CONTACT_RESPONSE = 1 << 2,
155 CUSTOM_MATERIAL_CALLBACK = 1 << 3,
156 CHARACTER_OBJECT = 1 << 4,
157 DISABLE_VISUALIZE_OBJECT = 1 << 5,
158 DISABLE_SPU_COLLISION_PROCESS = 1 << 6,
159 // Following used by BulletSim to control collisions
160 VOLUME_DETECT_OBJECT = 1 << 10,
161 PHANTOM_OBJECT = 1 << 11,
162 PHYSICAL_OBJECT = 1 << 12,
163};
164
149static class BulletSimAPI { 165static class BulletSimAPI {
150 166
151[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 167[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
@@ -214,6 +230,9 @@ public static extern bool RemoveConstraint(uint worldID, uint id1, uint id2);
214public static extern Vector3 GetObjectPosition(uint WorldID, uint id); 230public static extern Vector3 GetObjectPosition(uint WorldID, uint id);
215 231
216[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 232[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
233public static extern Quaternion GetObjectOrientation(uint WorldID, uint id);
234
235[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
217public static extern bool SetObjectTranslation(uint worldID, uint id, Vector3 position, Quaternion rotation); 236public static extern bool SetObjectTranslation(uint worldID, uint id, Vector3 position, Quaternion rotation);
218 237
219[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 238[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
@@ -268,5 +287,37 @@ public static extern void DumpBulletStatistics();
268public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg); 287public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);
269[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 288[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
270public static extern void SetDebugLogCallback(DebugLogCallback callback); 289public static extern void SetDebugLogCallback(DebugLogCallback callback);
290
291// ===============================================================================
292// ===============================================================================
293// ===============================================================================
294// A new version of the API that moves all the logic out of the C++ code and into
295// the C# code. This will make modifications easier for the next person.
296// This interface passes the actual pointers to the objects in the unmanaged
297// address space. All the management (calls for creation/destruction/lookup)
298// is done in the C# code.
299// The names have a 2 tacked on. This will be removed as the code gets rebuilt
300// and the old code is removed from the C# code.
301[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
302public static extern IntPtr GetSimHandle2(uint worldID);
303
304[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
305public static extern IntPtr GetBodyHandleWorldID2(uint worldID, uint id);
306
307[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
308public static extern IntPtr GetBodyHandle2(IntPtr sim, uint id);
309
310[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
311public static extern IntPtr ClearForces2(IntPtr obj);
312
313[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
314public static extern IntPtr SetCollisionFlags2(IntPtr obj, uint flags);
315
316[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
317public static extern IntPtr AddToCollisionFlags2(IntPtr obj, uint flags);
318
319[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
320public static extern IntPtr RemoveFromCollisionFlags2(IntPtr obj, uint flags);
321
271} 322}
272} 323}
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
index 977f39e..070ba57 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
@@ -6887,22 +6887,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6887 if (folderID == UUID.Zero) 6887 if (folderID == UUID.Zero)
6888 return; 6888 return;
6889 6889
6890 byte[] bucket = new byte[1];
6891 bucket[0] = (byte)AssetType.Folder;
6892 //byte[] objBytes = folderID.GetBytes();
6893 //Array.Copy(objBytes, 0, bucket, 1, 16);
6894
6895 GridInstantMessage msg = new GridInstantMessage(World,
6896 m_host.OwnerID, m_host.Name, destID,
6897 (byte)InstantMessageDialog.TaskInventoryOffered,
6898 false, category+". "+m_host.Name+" is located at "+
6899 World.RegionInfo.RegionName+" "+
6900 m_host.AbsolutePosition.ToString(),
6901 folderID, true, m_host.AbsolutePosition,
6902 bucket);
6903
6904 if (m_TransferModule != null) 6890 if (m_TransferModule != null)
6891 {
6892 byte[] bucket = new byte[] { (byte)AssetType.Folder };
6893
6894 GridInstantMessage msg = new GridInstantMessage(World,
6895 m_host.UUID, m_host.Name + ", an object owned by " +
6896 resolveName(m_host.OwnerID) + ",", destID,
6897 (byte)InstantMessageDialog.TaskInventoryOffered,
6898 false, category + "\n" + m_host.Name + " is located at " +
6899 World.RegionInfo.RegionName + " " +
6900 m_host.AbsolutePosition.ToString(),
6901 folderID, true, m_host.AbsolutePosition,
6902 bucket);
6903
6905 m_TransferModule.SendInstantMessage(msg, delegate(bool success) {}); 6904 m_TransferModule.SendInstantMessage(msg, delegate(bool success) {});
6905 }
6906 } 6906 }
6907 6907
6908 public void llSetVehicleType(int type) 6908 public void llSetVehicleType(int type)
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs
index 4bd3dff..7844c75 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs
@@ -200,24 +200,34 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
200 for (int i = 0; i < result.Length; i++) 200 for (int i = 0; i < result.Length; i++)
201 { 201 {
202 if (result[i] is string) 202 if (result[i] is string)
203 {
203 llist[i] = new LSL_String((string)result[i]); 204 llist[i] = new LSL_String((string)result[i]);
205 }
204 else if (result[i] is int) 206 else if (result[i] is int)
207 {
205 llist[i] = new LSL_Integer((int)result[i]); 208 llist[i] = new LSL_Integer((int)result[i]);
209 }
206 else if (result[i] is float) 210 else if (result[i] is float)
211 {
207 llist[i] = new LSL_Float((float)result[i]); 212 llist[i] = new LSL_Float((float)result[i]);
213 }
214 else if (result[i] is UUID)
215 {
216 llist[i] = new LSL_Key(result[i].ToString());
217 }
208 else if (result[i] is OpenMetaverse.Vector3) 218 else if (result[i] is OpenMetaverse.Vector3)
209 { 219 {
210 OpenMetaverse.Vector3 vresult = (OpenMetaverse.Vector3)result[i]; 220 OpenMetaverse.Vector3 vresult = (OpenMetaverse.Vector3)result[i];
211 llist[i] = new LSL_Vector(vresult.X,vresult.Y,vresult.Z); 221 llist[i] = new LSL_Vector(vresult.X, vresult.Y, vresult.Z);
212 } 222 }
213 else if (result[i] is OpenMetaverse.Quaternion) 223 else if (result[i] is OpenMetaverse.Quaternion)
214 { 224 {
215 OpenMetaverse.Quaternion qresult = (OpenMetaverse.Quaternion)result[i]; 225 OpenMetaverse.Quaternion qresult = (OpenMetaverse.Quaternion)result[i];
216 llist[i] = new LSL_Rotation(qresult.X,qresult.Y,qresult.Z,qresult.W); 226 llist[i] = new LSL_Rotation(qresult.X, qresult.Y, qresult.Z, qresult.W);
217 } 227 }
218 else 228 else
219 { 229 {
220 MODError(String.Format("unknown list element returned by {0}",fname)); 230 MODError(String.Format("unknown list element {1} returned by {0}", fname, result[i].GetType().Name));
221 } 231 }
222 } 232 }
223 233
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
index 29d0342..bf77dc5 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
@@ -3322,5 +3322,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3322 InitLSL(); 3322 InitLSL();
3323 ((LSL_Api)m_LSL_Api).DetachFromAvatar(); 3323 ((LSL_Api)m_LSL_Api).DetachFromAvatar();
3324 } 3324 }
3325
3326 /// <summary>
3327 /// Checks if thing is a UUID.
3328 /// </summary>
3329 /// <param name="thing"></param>
3330 /// <returns>1 if thing is a valid UUID, 0 otherwise</returns>
3331 public LSL_Integer osIsUUID(string thing)
3332 {
3333 CheckThreatLevel(ThreatLevel.None, "osIsUUID");
3334 m_host.AddScriptLPS(1);
3335
3336 UUID test;
3337 return UUID.TryParse(thing, out test) ? 1 : 0;
3338 }
3325 } 3339 }
3326} 3340}
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs
index 19f3ce1..f7314da 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs
@@ -68,6 +68,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
68 private const int AGENT = 1; 68 private const int AGENT = 1;
69 private const int AGENT_BY_USERNAME = 0x10; 69 private const int AGENT_BY_USERNAME = 0x10;
70 private const int NPC = 0x20; 70 private const int NPC = 0x20;
71 private const int OS_NPC = 0x01000000;
71 private const int ACTIVE = 2; 72 private const int ACTIVE = 2;
72 private const int PASSIVE = 4; 73 private const int PASSIVE = 4;
73 private const int SCRIPTED = 8; 74 private const int SCRIPTED = 8;
@@ -220,7 +221,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
220 List<SensedEntity> sensedEntities = new List<SensedEntity>(); 221 List<SensedEntity> sensedEntities = new List<SensedEntity>();
221 222
222 // Is the sensor type is AGENT and not SCRIPTED then include agents 223 // Is the sensor type is AGENT and not SCRIPTED then include agents
223 if ((ts.type & (AGENT | AGENT_BY_USERNAME | NPC)) != 0 && (ts.type & SCRIPTED) == 0) 224 if ((ts.type & (AGENT | AGENT_BY_USERNAME | NPC | OS_NPC)) != 0 && (ts.type & SCRIPTED) == 0)
224 { 225 {
225 sensedEntities.AddRange(doAgentSensor(ts)); 226 sensedEntities.AddRange(doAgentSensor(ts));
226 } 227 }
@@ -484,7 +485,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
484// "[SENSOR REPEAT]: Inspecting scene presence {0}, type {1} on sensor sweep for {2}, type {3}", 485// "[SENSOR REPEAT]: Inspecting scene presence {0}, type {1} on sensor sweep for {2}, type {3}",
485// presence.Name, presence.PresenceType, ts.name, ts.type); 486// presence.Name, presence.PresenceType, ts.name, ts.type);
486 487
487 if ((ts.type & NPC) == 0 && presence.PresenceType == PresenceType.Npc) 488 if ((ts.type & NPC) == 0 && (ts.type & OS_NPC) == 0 && presence.PresenceType == PresenceType.Npc)
488 { 489 {
489 INPC npcData = npcModule.GetNPC(presence.UUID, presence.Scene); 490 INPC npcData = npcModule.GetNPC(presence.UUID, presence.Scene);
490 if (npcData == null || !npcData.SenseAsAgent) 491 if (npcData == null || !npcData.SenseAsAgent)
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
index 1facc96..24bdf0c 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
@@ -276,5 +276,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces
276 276
277 void osSetTerrainTexture(int level, LSL_Key texture); 277 void osSetTerrainTexture(int level, LSL_Key texture);
278 void osSetTerrainTextureHeight(int corner, double low, double high); 278 void osSetTerrainTextureHeight(int corner, double low, double high);
279
280 /// <summary>
281 /// Checks if thing is a UUID.
282 /// </summary>
283 /// <param name="thing"></param>
284 /// <returns>1 if thing is a valid UUID, 0 otherwise</returns>
285 LSL_Integer osIsUUID(string thing);
279 } 286 }
280} 287}
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs
index a08cc42..5669917 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs
@@ -56,6 +56,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
56 public const int ACTIVE = 2; 56 public const int ACTIVE = 2;
57 public const int PASSIVE = 4; 57 public const int PASSIVE = 4;
58 public const int SCRIPTED = 8; 58 public const int SCRIPTED = 8;
59 public const int OS_NPC = 0x01000000;
59 60
60 public const int CONTROL_FWD = 1; 61 public const int CONTROL_FWD = 1;
61 public const int CONTROL_BACK = 2; 62 public const int CONTROL_BACK = 2;
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs
index b40bdf0..99995a7 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs
@@ -930,5 +930,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
930 { 930 {
931 m_OSSL_Functions.osSetTerrainTextureHeight(corner, low, high); 931 m_OSSL_Functions.osSetTerrainTextureHeight(corner, low, high);
932 } 932 }
933
934 public LSL_Integer osIsUUID(string thing)
935 {
936 return m_OSSL_Functions.osIsUUID(thing);
937 }
933 } 938 }
934} 939}
diff --git a/OpenSim/Region/ScriptEngine/Shared/Helpers.cs b/OpenSim/Region/ScriptEngine/Shared/Helpers.cs
index 5c9d30f..9e5fb24 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Helpers.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Helpers.cs
@@ -36,6 +36,7 @@ using OpenSim.Framework;
36using OpenSim.Region.CoreModules; 36using OpenSim.Region.CoreModules;
37using OpenSim.Region.Framework.Scenes; 37using OpenSim.Region.Framework.Scenes;
38using OpenSim.Services.Interfaces; 38using OpenSim.Services.Interfaces;
39using OpenSim.Region.Framework.Interfaces;
39 40
40namespace OpenSim.Region.ScriptEngine.Shared 41namespace OpenSim.Region.ScriptEngine.Shared
41{ 42{
@@ -83,6 +84,12 @@ namespace OpenSim.Region.ScriptEngine.Shared
83 84
84 public class DetectParams 85 public class DetectParams
85 { 86 {
87 public const int AGENT = 1;
88 public const int ACTIVE = 2;
89 public const int PASSIVE = 4;
90 public const int SCRIPTED = 8;
91 public const int OS_NPC = 0x01000000;
92
86 public DetectParams() 93 public DetectParams()
87 { 94 {
88 Key = UUID.Zero; 95 Key = UUID.Zero;
@@ -199,8 +206,27 @@ namespace OpenSim.Region.ScriptEngine.Shared
199 Type = 0x01; // Avatar 206 Type = 0x01; // Avatar
200 if (presence.PresenceType == PresenceType.Npc) 207 if (presence.PresenceType == PresenceType.Npc)
201 Type = 0x20; 208 Type = 0x20;
209
210 // Cope Impl. We don't use OS_NPC.
211 //if (presence.PresenceType != PresenceType.Npc)
212 //{
213 // Type = AGENT;
214 //}
215 //else
216 //{
217 // Type = OS_NPC;
218
219 // INPCModule npcModule = scene.RequestModuleInterface<INPCModule>();
220 // INPC npcData = npcModule.GetNPC(presence.UUID, presence.Scene);
221
222 // if (npcData.SenseAsAgent)
223 // {
224 // Type |= AGENT;
225 // }
226 //}
227
202 if (presence.Velocity != Vector3.Zero) 228 if (presence.Velocity != Vector3.Zero)
203 Type |= 0x02; // Active 229 Type |= ACTIVE;
204 230
205 Group = presence.ControllingClient.ActiveGroupId; 231 Group = presence.ControllingClient.ActiveGroupId;
206 232
@@ -215,15 +241,15 @@ namespace OpenSim.Region.ScriptEngine.Shared
215 Name = part.Name; 241 Name = part.Name;
216 Owner = part.OwnerID; 242 Owner = part.OwnerID;
217 if (part.Velocity == Vector3.Zero) 243 if (part.Velocity == Vector3.Zero)
218 Type = 0x04; // Passive 244 Type = PASSIVE;
219 else 245 else
220 Type = 0x02; // Passive 246 Type = ACTIVE;
221 247
222 foreach (SceneObjectPart p in part.ParentGroup.Parts) 248 foreach (SceneObjectPart p in part.ParentGroup.Parts)
223 { 249 {
224 if (p.Inventory.ContainsScripts()) 250 if (p.Inventory.ContainsScripts())
225 { 251 {
226 Type |= 0x08; // Scripted 252 Type |= SCRIPTED; // Scripted
227 break; 253 break;
228 } 254 }
229 } 255 }
diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
index 983eed2..771db0c 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
@@ -312,11 +312,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
312 part.SetScriptEvents(ItemID, 312 part.SetScriptEvents(ItemID,
313 (int)m_Script.GetStateEventFlags(State)); 313 (int)m_Script.GetStateEventFlags(State));
314 314
315 Running = false; 315 if (!Running)
316
317 if (ShuttingDown)
318 m_startOnInit = false; 316 m_startOnInit = false;
319 317
318 Running = false;
319
320 // we get new rez events on sim restart, too 320 // we get new rez events on sim restart, too
321 // but if there is state, then we fire the change 321 // but if there is state, then we fire the change
322 // event 322 // event
@@ -352,12 +352,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
352 352
353 public void Init() 353 public void Init()
354 { 354 {
355 if (!m_startOnInit) 355 if (ShuttingDown)
356 return; 356 return;
357 357
358 if (m_startedFromSavedState) 358 if (m_startedFromSavedState)
359 { 359 {
360 Start(); 360 if (m_startOnInit)
361 Start();
361 if (m_postOnRez) 362 if (m_postOnRez)
362 { 363 {
363 PostEvent(new EventParams("on_rez", 364 PostEvent(new EventParams("on_rez",
@@ -389,7 +390,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
389 } 390 }
390 else 391 else
391 { 392 {
392 Start(); 393 if (m_startOnInit)
394 Start();
393 PostEvent(new EventParams("state_entry", 395 PostEvent(new EventParams("state_entry",
394 new Object[0], new DetectParams[0])); 396 new Object[0], new DetectParams[0]));
395 if (m_postOnRez) 397 if (m_postOnRez)
diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
index 35a0200..79a6e09 100644
--- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
+++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
@@ -109,6 +109,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine
109 private bool m_KillTimedOutScripts; 109 private bool m_KillTimedOutScripts;
110 private string m_ScriptEnginesPath = null; 110 private string m_ScriptEnginesPath = null;
111 111
112 private ExpiringCache<UUID, bool> m_runFlags = new ExpiringCache<UUID, bool>();
113
112 /// <summary> 114 /// <summary>
113 /// Is the entire simulator in the process of shutting down? 115 /// Is the entire simulator in the process of shutting down?
114 /// </summary> 116 /// </summary>
@@ -715,6 +717,10 @@ namespace OpenSim.Region.ScriptEngine.XEngine
715 m_Scene.EventManager.OnGetScriptRunning += OnGetScriptRunning; 717 m_Scene.EventManager.OnGetScriptRunning += OnGetScriptRunning;
716 m_Scene.EventManager.OnShutdown += OnShutdown; 718 m_Scene.EventManager.OnShutdown += OnShutdown;
717 719
720 // If region ready has been triggered, then the region had no scripts to compile and completed its other
721 // work.
722 m_Scene.EventManager.OnRegionReady += s => m_InitialStartup = false;
723
718 if (m_SleepTime > 0) 724 if (m_SleepTime > 0)
719 { 725 {
720 m_ThreadPool.QueueWorkItem(new WorkItemCallback(this.DoMaintenance), 726 m_ThreadPool.QueueWorkItem(new WorkItemCallback(this.DoMaintenance),
@@ -1269,7 +1275,15 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1269 1275
1270 if (instance!=null) 1276 if (instance!=null)
1271 instance.Init(); 1277 instance.Init();
1272 1278
1279 bool runIt;
1280 if (m_runFlags.TryGetValue(itemID, out runIt))
1281 {
1282 if (!runIt)
1283 StopScript(itemID);
1284 m_runFlags.Remove(itemID);
1285 }
1286
1273 return true; 1287 return true;
1274 } 1288 }
1275 1289
@@ -1660,6 +1674,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1660 IScriptInstance instance = GetInstance(itemID); 1674 IScriptInstance instance = GetInstance(itemID);
1661 if (instance != null) 1675 if (instance != null)
1662 instance.Start(); 1676 instance.Start();
1677 else
1678 m_runFlags.AddOrUpdate(itemID, true, 240);
1663 } 1679 }
1664 1680
1665 public void StopScript(UUID itemID) 1681 public void StopScript(UUID itemID)
@@ -1671,6 +1687,10 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1671 // cause issues on mono 2.6, 2.10 and possibly later where locks are not released properly on abort. 1687 // cause issues on mono 2.6, 2.10 and possibly later where locks are not released properly on abort.
1672 instance.Stop(1000); 1688 instance.Stop(1000);
1673 } 1689 }
1690 else
1691 {
1692 m_runFlags.AddOrUpdate(itemID, false, 240);
1693 }
1674 } 1694 }
1675 1695
1676 public DetectParams GetDetectParams(UUID itemID, int idx) 1696 public DetectParams GetDetectParams(UUID itemID, int idx)
diff --git a/OpenSim/Tests/Common/Helpers/SceneHelpers.cs b/OpenSim/Tests/Common/Helpers/SceneHelpers.cs
index 769de83..7598cc3 100644
--- a/OpenSim/Tests/Common/Helpers/SceneHelpers.cs
+++ b/OpenSim/Tests/Common/Helpers/SceneHelpers.cs
@@ -190,7 +190,7 @@ namespace OpenSim.Tests.Common
190 = physicsPluginManager.GetPhysicsScene("basicphysics", "ZeroMesher", new IniConfigSource(), "test"); 190 = physicsPluginManager.GetPhysicsScene("basicphysics", "ZeroMesher", new IniConfigSource(), "test");
191 191
192 testScene.RegionInfo.EstateSettings = new EstateSettings(); 192 testScene.RegionInfo.EstateSettings = new EstateSettings();
193 testScene.LoginsDisabled = false; 193 testScene.LoginsEnabled = true;
194 testScene.RegisterRegionWithGrid(); 194 testScene.RegisterRegionWithGrid();
195 195
196 SceneManager.Add(testScene); 196 SceneManager.Add(testScene);