aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--OpenSim/Addons/Groups/GroupsModule.cs21
-rw-r--r--OpenSim/Framework/IClientAPI.cs4
-rw-r--r--OpenSim/Framework/Monitoring/Stats/Stat.cs24
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs242
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs7
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs69
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs116
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs72
-rw-r--r--OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs21
-rw-r--r--OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs4
-rw-r--r--OpenSim/Region/Framework/Scenes/EventManager.cs6
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.Inventory.cs4
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs30
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresence.cs120
-rw-r--r--OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs3
-rw-r--r--OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs12
-rw-r--r--OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs3
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSActors.cs6
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs37
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs95
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs37
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs82
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSParam.cs8
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs11
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs52
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs32
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs2
-rw-r--r--OpenSim/Region/Physics/Manager/PhysicsActor.cs5
-rw-r--r--OpenSim/Region/Physics/Manager/PhysicsScene.cs9
-rw-r--r--OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs20
-rw-r--r--OpenSim/Tests/Common/Mock/TestClient.cs3
31 files changed, 910 insertions, 247 deletions
diff --git a/OpenSim/Addons/Groups/GroupsModule.cs b/OpenSim/Addons/Groups/GroupsModule.cs
index 82e2d6f..69d03a9 100644
--- a/OpenSim/Addons/Groups/GroupsModule.cs
+++ b/OpenSim/Addons/Groups/GroupsModule.cs
@@ -1402,19 +1402,18 @@ namespace OpenSim.Groups
1402 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); 1402 if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
1403 1403
1404 // TODO: All the client update functions need to be reexamined because most do too much and send too much stuff 1404 // TODO: All the client update functions need to be reexamined because most do too much and send too much stuff
1405 UserAccount account = m_sceneList[0].UserAccountService.GetUserAccount(remoteClient.Scene.RegionInfo.ScopeID, dataForAgentID); 1405 string firstname = "Unknown", lastname = "Unknown";
1406 string firstname, lastname; 1406 string name = m_UserManagement.GetUserName(dataForAgentID);
1407 if (account != null) 1407 if (!string.IsNullOrEmpty(name))
1408 {
1409 firstname = account.FirstName;
1410 lastname = account.LastName;
1411 }
1412 else
1413 { 1408 {
1414 firstname = "Unknown"; 1409 string[] parts = name.Split(new char[] { ' ' });
1415 lastname = "Unknown"; 1410 if (parts.Length >= 2)
1411 {
1412 firstname = parts[0];
1413 lastname = parts[1];
1414 }
1416 } 1415 }
1417 1416
1418 remoteClient.SendAgentDataUpdate(dataForAgentID, activeGroupID, firstname, 1417 remoteClient.SendAgentDataUpdate(dataForAgentID, activeGroupID, firstname,
1419 lastname, activeGroupPowers, activeGroupName, 1418 lastname, activeGroupPowers, activeGroupName,
1420 activeGroupTitle); 1419 activeGroupTitle);
diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs
index 6c9e7c9..22cc79d 100644
--- a/OpenSim/Framework/IClientAPI.cs
+++ b/OpenSim/Framework/IClientAPI.cs
@@ -834,6 +834,8 @@ namespace OpenSim.Framework
834 /// </remarks> 834 /// </remarks>
835 event UpdateAgent OnAgentUpdate; 835 event UpdateAgent OnAgentUpdate;
836 836
837 event UpdateAgent OnAgentCameraUpdate;
838
837 event AgentRequestSit OnAgentRequestSit; 839 event AgentRequestSit OnAgentRequestSit;
838 event AgentSit OnAgentSit; 840 event AgentSit OnAgentSit;
839 event AvatarPickerRequest OnAvatarPickerRequest; 841 event AvatarPickerRequest OnAvatarPickerRequest;
@@ -1489,7 +1491,7 @@ namespace OpenSim.Framework
1489 void SendChangeUserRights(UUID agentID, UUID friendID, int rights); 1491 void SendChangeUserRights(UUID agentID, UUID friendID, int rights);
1490 void SendTextBoxRequest(string message, int chatChannel, string objectname, UUID ownerID, string ownerFirstName, string ownerLastName, UUID objectId); 1492 void SendTextBoxRequest(string message, int chatChannel, string objectname, UUID ownerID, string ownerFirstName, string ownerLastName, UUID objectId);
1491 1493
1492 void StopFlying(ISceneEntity presence); 1494 void SendAgentTerseUpdate(ISceneEntity presence);
1493 1495
1494 void SendPlacesReply(UUID queryID, UUID transactionID, PlacesReplyData[] data); 1496 void SendPlacesReply(UUID queryID, UUID transactionID, PlacesReplyData[] data);
1495 } 1497 }
diff --git a/OpenSim/Framework/Monitoring/Stats/Stat.cs b/OpenSim/Framework/Monitoring/Stats/Stat.cs
index 9629b6e..ffd5132 100644
--- a/OpenSim/Framework/Monitoring/Stats/Stat.cs
+++ b/OpenSim/Framework/Monitoring/Stats/Stat.cs
@@ -225,7 +225,13 @@ namespace OpenSim.Framework.Monitoring
225 public virtual string ToConsoleString() 225 public virtual string ToConsoleString()
226 { 226 {
227 StringBuilder sb = new StringBuilder(); 227 StringBuilder sb = new StringBuilder();
228 sb.AppendFormat("{0}.{1}.{2} : {3} {4}", Category, Container, ShortName, Value, UnitName); 228 sb.AppendFormat(
229 "{0}.{1}.{2} : {3}{4}",
230 Category,
231 Container,
232 ShortName,
233 Value,
234 UnitName == null || UnitName == "" ? "" : string.Format(" {0}", UnitName));
229 235
230 AppendMeasuresOfInterest(sb); 236 AppendMeasuresOfInterest(sb);
231 237
@@ -253,6 +259,8 @@ namespace OpenSim.Framework.Monitoring
253 == MeasuresOfInterest.AverageChangeOverTime) 259 == MeasuresOfInterest.AverageChangeOverTime)
254 { 260 {
255 double totalChange = 0; 261 double totalChange = 0;
262 double lastChangeOverTime = 0;
263 double? penultimateSample = null;
256 double? lastSample = null; 264 double? lastSample = null;
257 265
258 lock (m_samples) 266 lock (m_samples)
@@ -266,13 +274,25 @@ namespace OpenSim.Framework.Monitoring
266 if (lastSample != null) 274 if (lastSample != null)
267 totalChange += s - (double)lastSample; 275 totalChange += s - (double)lastSample;
268 276
277 penultimateSample = lastSample;
269 lastSample = s; 278 lastSample = s;
270 } 279 }
271 } 280 }
272 281
282 if (lastSample != null && penultimateSample != null)
283 lastChangeOverTime
284 = ((double)lastSample - (double)penultimateSample) / (Watchdog.WATCHDOG_INTERVAL_MS / 1000);
285
273 int divisor = m_samples.Count <= 1 ? 1 : m_samples.Count - 1; 286 int divisor = m_samples.Count <= 1 ? 1 : m_samples.Count - 1;
274 287
275 sb.AppendFormat(", {0:0.##} {1}/s", totalChange / divisor / (Watchdog.WATCHDOG_INTERVAL_MS / 1000), UnitName); 288 double averageChangeOverTime = totalChange / divisor / (Watchdog.WATCHDOG_INTERVAL_MS / 1000);
289
290 sb.AppendFormat(
291 ", {0:0.##}{1}/s, {2:0.##}{3}/s",
292 lastChangeOverTime,
293 UnitName == null || UnitName == "" ? "" : string.Format(" {0}", UnitName),
294 averageChangeOverTime,
295 UnitName == null || UnitName == "" ? "" : string.Format(" {0}", UnitName));
276 } 296 }
277 } 297 }
278 } 298 }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
index ac5e77e..0e20e38 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -96,6 +96,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
96 public event Action<IClientAPI, bool> OnCompleteMovementToRegion; 96 public event Action<IClientAPI, bool> OnCompleteMovementToRegion;
97 public event UpdateAgent OnPreAgentUpdate; 97 public event UpdateAgent OnPreAgentUpdate;
98 public event UpdateAgent OnAgentUpdate; 98 public event UpdateAgent OnAgentUpdate;
99 public event UpdateAgent OnAgentCameraUpdate;
99 public event AgentRequestSit OnAgentRequestSit; 100 public event AgentRequestSit OnAgentRequestSit;
100 public event AgentSit OnAgentSit; 101 public event AgentSit OnAgentSit;
101 public event AvatarPickerRequest OnAvatarPickerRequest; 102 public event AvatarPickerRequest OnAvatarPickerRequest;
@@ -368,7 +369,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
368 /// This does mean that agent updates must be processed synchronously, at least for each client, and called methods 369 /// This does mean that agent updates must be processed synchronously, at least for each client, and called methods
369 /// cannot retain a reference to it outside of that method. 370 /// cannot retain a reference to it outside of that method.
370 /// </remarks> 371 /// </remarks>
371 private AgentUpdateArgs m_lastAgentUpdateArgs; 372 private AgentUpdateArgs m_thisAgentUpdateArgs = new AgentUpdateArgs();
372 373
373 protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>(); 374 protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>();
374 protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers 375 protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers
@@ -505,6 +506,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
505 m_udpServer = udpServer; 506 m_udpServer = udpServer;
506 m_udpClient = udpClient; 507 m_udpClient = udpClient;
507 m_udpClient.OnQueueEmpty += HandleQueueEmpty; 508 m_udpClient.OnQueueEmpty += HandleQueueEmpty;
509 m_udpClient.HasUpdates += HandleHasUpdates;
508 m_udpClient.OnPacketStats += PopulateStats; 510 m_udpClient.OnPacketStats += PopulateStats;
509 511
510 m_prioritizer = new Prioritizer(m_scene); 512 m_prioritizer = new Prioritizer(m_scene);
@@ -4164,8 +4166,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4164 4166
4165 void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories) 4167 void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories)
4166 { 4168 {
4169// if (!m_udpServer.IsRunningOutbound)
4170// return;
4171
4167 if ((categories & ThrottleOutPacketTypeFlags.Task) != 0) 4172 if ((categories & ThrottleOutPacketTypeFlags.Task) != 0)
4168 { 4173 {
4174// if (!m_udpServer.IsRunningOutbound)
4175// return;
4176
4169 if (m_maxUpdates == 0 || m_LastQueueFill == 0) 4177 if (m_maxUpdates == 0 || m_LastQueueFill == 0)
4170 { 4178 {
4171 m_maxUpdates = m_udpServer.PrimUpdatesPerCallback; 4179 m_maxUpdates = m_udpServer.PrimUpdatesPerCallback;
@@ -4191,6 +4199,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4191 ImageManager.ProcessImageQueue(m_udpServer.TextureSendLimit); 4199 ImageManager.ProcessImageQueue(m_udpServer.TextureSendLimit);
4192 } 4200 }
4193 4201
4202 internal bool HandleHasUpdates(ThrottleOutPacketTypeFlags categories)
4203 {
4204 bool hasUpdates = false;
4205
4206 if ((categories & ThrottleOutPacketTypeFlags.Task) != 0)
4207 {
4208 if (m_entityUpdates.Count > 0)
4209 hasUpdates = true;
4210 else if (m_entityProps.Count > 0)
4211 hasUpdates = true;
4212 }
4213
4214 if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0)
4215 {
4216 if (ImageManager.HasUpdates())
4217 hasUpdates = true;
4218 }
4219
4220 return hasUpdates;
4221 }
4222
4194 public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID) 4223 public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID)
4195 { 4224 {
4196 AssetUploadCompletePacket newPack = new AssetUploadCompletePacket(); 4225 AssetUploadCompletePacket newPack = new AssetUploadCompletePacket();
@@ -5058,7 +5087,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5058 SceneObjectPart part = (SceneObjectPart)entity; 5087 SceneObjectPart part = (SceneObjectPart)entity;
5059 5088
5060 attachPoint = part.ParentGroup.AttachmentPoint; 5089 attachPoint = part.ParentGroup.AttachmentPoint;
5061 5090 attachPoint = ((attachPoint % 16) * 16 + (attachPoint / 16));
5062// m_log.DebugFormat( 5091// m_log.DebugFormat(
5063// "[LLCLIENTVIEW]: Sending attachPoint {0} for {1} {2} to {3}", 5092// "[LLCLIENTVIEW]: Sending attachPoint {0} for {1} {2} to {3}",
5064// attachPoint, part.Name, part.LocalId, Name); 5093// attachPoint, part.Name, part.LocalId, Name);
@@ -5086,7 +5115,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5086 pos += 4; 5115 pos += 4;
5087 5116
5088 // Avatar/CollisionPlane 5117 // Avatar/CollisionPlane
5089 data[pos++] = (byte)((attachPoint % 16) * 16 + (attachPoint / 16)); ; 5118 data[pos++] = (byte) attachPoint;
5090 if (avatar) 5119 if (avatar)
5091 { 5120 {
5092 data[pos++] = 1; 5121 data[pos++] = 1;
@@ -5618,83 +5647,137 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5618 5647
5619 #region Packet Handlers 5648 #region Packet Handlers
5620 5649
5650 public int TotalAgentUpdates { get; set; }
5651
5621 #region Scene/Avatar 5652 #region Scene/Avatar
5622 5653
5623 private bool HandleAgentUpdate(IClientAPI sener, Packet packet) 5654 // Threshold for body rotation to be a significant agent update
5655 private const float QDELTA = 0.000001f;
5656 // Threshold for camera rotation to be a significant agent update
5657 private const float VDELTA = 0.01f;
5658
5659 /// <summary>
5660 /// This checks the update significance against the last update made.
5661 /// </summary>
5662 /// <remarks>Can only be called by one thread at a time</remarks>
5663 /// <returns></returns>
5664 /// <param name='x'></param>
5665 public bool CheckAgentUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
5624 { 5666 {
5625 if (OnAgentUpdate != null) 5667 return CheckAgentMovementUpdateSignificance(x) || CheckAgentCameraUpdateSignificance(x);
5626 { 5668 }
5627 AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
5628 5669
5629 #region Packet Session and User Check 5670 /// <summary>
5630 if (agentUpdate.AgentData.SessionID != SessionId || agentUpdate.AgentData.AgentID != AgentId) 5671 /// This checks the movement/state update significance against the last update made.
5631 { 5672 /// </summary>
5632 PacketPool.Instance.ReturnPacket(packet); 5673 /// <remarks>Can only be called by one thread at a time</remarks>
5633 return false; 5674 /// <returns></returns>
5634 } 5675 /// <param name='x'></param>
5635 #endregion 5676 private bool CheckAgentMovementUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
5677 {
5678 float qdelta1 = 1 - (float)Math.Pow(Quaternion.Dot(x.BodyRotation, m_thisAgentUpdateArgs.BodyRotation), 2);
5679 //qdelta2 = 1 - (float)Math.Pow(Quaternion.Dot(x.HeadRotation, m_thisAgentUpdateArgs.HeadRotation), 2);
5680
5681 bool movementSignificant =
5682 (qdelta1 > QDELTA) // significant if body rotation above threshold
5683 // Ignoring head rotation altogether, because it's not being used for anything interesting up the stack
5684 // || (qdelta2 > QDELTA * 10) // significant if head rotation above threshold
5685 || (x.ControlFlags != m_thisAgentUpdateArgs.ControlFlags) // significant if control flags changed
5686 || (x.ControlFlags != (byte)AgentManager.ControlFlags.NONE) // significant if user supplying any movement update commands
5687 || (x.Far != m_thisAgentUpdateArgs.Far) // significant if far distance changed
5688 || (x.Flags != m_thisAgentUpdateArgs.Flags) // significant if Flags changed
5689 || (x.State != m_thisAgentUpdateArgs.State) // significant if Stats changed
5690 ;
5691 //if (movementSignificant)
5692 //{
5693 //m_log.DebugFormat("[LLCLIENTVIEW]: Bod {0} {1}",
5694 // qdelta1, qdelta2);
5695 //m_log.DebugFormat("[LLCLIENTVIEW]: St {0} {1} {2} {3}",
5696 // x.ControlFlags, x.Flags, x.Far, x.State);
5697 //}
5698 return movementSignificant;
5699 }
5636 5700
5637 bool update = false; 5701 /// <summary>
5638 AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData; 5702 /// This checks the camera update significance against the last update made.
5639 5703 /// </summary>
5640 if (m_lastAgentUpdateArgs != null) 5704 /// <remarks>Can only be called by one thread at a time</remarks>
5641 { 5705 /// <returns></returns>
5642 // These should be ordered from most-likely to 5706 /// <param name='x'></param>
5643 // least likely to change. I've made an initial 5707 private bool CheckAgentCameraUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
5644 // guess at that. 5708 {
5645 update = 5709 float vdelta1 = Vector3.Distance(x.CameraAtAxis, m_thisAgentUpdateArgs.CameraAtAxis);
5646 ( 5710 float vdelta2 = Vector3.Distance(x.CameraCenter, m_thisAgentUpdateArgs.CameraCenter);
5647 (x.BodyRotation != m_lastAgentUpdateArgs.BodyRotation) || 5711 float vdelta3 = Vector3.Distance(x.CameraLeftAxis, m_thisAgentUpdateArgs.CameraLeftAxis);
5648 (x.CameraAtAxis != m_lastAgentUpdateArgs.CameraAtAxis) || 5712 float vdelta4 = Vector3.Distance(x.CameraUpAxis, m_thisAgentUpdateArgs.CameraUpAxis);
5649 (x.CameraCenter != m_lastAgentUpdateArgs.CameraCenter) ||
5650 (x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) ||
5651 (x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) ||
5652 (x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) ||
5653 (x.ControlFlags != 0) ||
5654 (x.Far != m_lastAgentUpdateArgs.Far) ||
5655 (x.Flags != m_lastAgentUpdateArgs.Flags) ||
5656 (x.State != m_lastAgentUpdateArgs.State) ||
5657 (x.HeadRotation != m_lastAgentUpdateArgs.HeadRotation) ||
5658 (x.SessionID != m_lastAgentUpdateArgs.SessionID) ||
5659 (x.AgentID != m_lastAgentUpdateArgs.AgentID)
5660 );
5661 }
5662 else
5663 {
5664 m_lastAgentUpdateArgs = new AgentUpdateArgs();
5665 update = true;
5666 }
5667 5713
5668 if (update) 5714 bool cameraSignificant =
5669 { 5715 (vdelta1 > VDELTA) ||
5670// m_log.DebugFormat("[LLCLIENTVIEW]: Triggered AgentUpdate for {0}", sener.Name); 5716 (vdelta2 > VDELTA) ||
5717 (vdelta3 > VDELTA) ||
5718 (vdelta4 > VDELTA)
5719 ;
5671 5720
5672 m_lastAgentUpdateArgs.AgentID = x.AgentID; 5721 //if (cameraSignificant)
5673 m_lastAgentUpdateArgs.BodyRotation = x.BodyRotation; 5722 //{
5674 m_lastAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis; 5723 //m_log.DebugFormat("[LLCLIENTVIEW]: Cam1 {0} {1}",
5675 m_lastAgentUpdateArgs.CameraCenter = x.CameraCenter; 5724 // x.CameraAtAxis, x.CameraCenter);
5676 m_lastAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis; 5725 //m_log.DebugFormat("[LLCLIENTVIEW]: Cam2 {0} {1}",
5677 m_lastAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis; 5726 // x.CameraLeftAxis, x.CameraUpAxis);
5678 m_lastAgentUpdateArgs.ControlFlags = x.ControlFlags; 5727 //}
5679 m_lastAgentUpdateArgs.Far = x.Far;
5680 m_lastAgentUpdateArgs.Flags = x.Flags;
5681 m_lastAgentUpdateArgs.HeadRotation = x.HeadRotation;
5682 m_lastAgentUpdateArgs.SessionID = x.SessionID;
5683 m_lastAgentUpdateArgs.State = x.State;
5684 5728
5685 UpdateAgent handlerAgentUpdate = OnAgentUpdate; 5729 return cameraSignificant;
5686 UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate; 5730 }
5687 5731
5688 if (handlerPreAgentUpdate != null) 5732 private bool HandleAgentUpdate(IClientAPI sener, Packet packet)
5689 OnPreAgentUpdate(this, m_lastAgentUpdateArgs); 5733 {
5734 // We got here, which means that something in agent update was significant
5690 5735
5691 if (handlerAgentUpdate != null) 5736 AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
5692 OnAgentUpdate(this, m_lastAgentUpdateArgs); 5737 AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData;
5693 5738
5694 handlerAgentUpdate = null; 5739 if (x.AgentID != AgentId || x.SessionID != SessionId)
5695 handlerPreAgentUpdate = null; 5740 return false;
5696 } 5741
5697 } 5742 // Before we update the current m_thisAgentUpdateArgs, let's check this again
5743 // to see what exactly changed
5744 bool movement = CheckAgentMovementUpdateSignificance(x);
5745 bool camera = CheckAgentCameraUpdateSignificance(x);
5746
5747 m_thisAgentUpdateArgs.AgentID = x.AgentID;
5748 m_thisAgentUpdateArgs.BodyRotation = x.BodyRotation;
5749 m_thisAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis;
5750 m_thisAgentUpdateArgs.CameraCenter = x.CameraCenter;
5751 m_thisAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis;
5752 m_thisAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis;
5753 m_thisAgentUpdateArgs.ControlFlags = x.ControlFlags;
5754 m_thisAgentUpdateArgs.Far = x.Far;
5755 m_thisAgentUpdateArgs.Flags = x.Flags;
5756 m_thisAgentUpdateArgs.HeadRotation = x.HeadRotation;
5757 m_thisAgentUpdateArgs.SessionID = x.SessionID;
5758 m_thisAgentUpdateArgs.State = x.State;
5759
5760 UpdateAgent handlerAgentUpdate = OnAgentUpdate;
5761 UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate;
5762 UpdateAgent handlerAgentCameraUpdate = OnAgentCameraUpdate;
5763
5764 // Was there a significant movement/state change?
5765 if (movement)
5766 {
5767 if (handlerPreAgentUpdate != null)
5768 OnPreAgentUpdate(this, m_thisAgentUpdateArgs);
5769
5770 if (handlerAgentUpdate != null)
5771 OnAgentUpdate(this, m_thisAgentUpdateArgs);
5772 }
5773 // Was there a significant camera(s) change?
5774 if (camera)
5775 if (handlerAgentCameraUpdate != null)
5776 handlerAgentCameraUpdate(this, m_thisAgentUpdateArgs);
5777
5778 handlerAgentUpdate = null;
5779 handlerPreAgentUpdate = null;
5780 handlerAgentCameraUpdate = null;
5698 5781
5699 PacketPool.Instance.ReturnPacket(packet); 5782 PacketPool.Instance.ReturnPacket(packet);
5700 5783
@@ -12813,7 +12896,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12813 OutPacket(dialog, ThrottleOutPacketType.Task); 12896 OutPacket(dialog, ThrottleOutPacketType.Task);
12814 } 12897 }
12815 12898
12816 public void StopFlying(ISceneEntity p) 12899 public void SendAgentTerseUpdate(ISceneEntity p)
12817 { 12900 {
12818 if (p is ScenePresence) 12901 if (p is ScenePresence)
12819 { 12902 {
@@ -12827,25 +12910,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12827 12910
12828 Vector3 pos = presence.AbsolutePosition; 12911 Vector3 pos = presence.AbsolutePosition;
12829 12912
12830 if (presence.Appearance.AvatarHeight != 127.0f)
12831 pos += new Vector3(0f, 0f, (presence.Appearance.AvatarHeight/6f));
12832 else
12833 pos += new Vector3(0f, 0f, (1.56f/6f));
12834
12835 presence.AbsolutePosition = pos;
12836
12837 // attach a suitable collision plane regardless of the actual situation to force the LLClient to land.
12838 // Collision plane below the avatar's position a 6th of the avatar's height is suitable.
12839 // Mind you, that this method doesn't get called if the avatar's velocity magnitude is greater then a
12840 // certain amount.. because the LLClient wouldn't land in that situation anyway.
12841
12842 // why are we still testing for this really old height value default???
12843 if (presence.Appearance.AvatarHeight != 127.0f)
12844 presence.CollisionPlane = new Vector4(0, 0, 0, pos.Z - presence.Appearance.AvatarHeight/6f);
12845 else
12846 presence.CollisionPlane = new Vector4(0, 0, 0, pos.Z - (1.56f/6f));
12847
12848
12849 ImprovedTerseObjectUpdatePacket.ObjectDataBlock block = 12913 ImprovedTerseObjectUpdatePacket.ObjectDataBlock block =
12850 CreateImprovedTerseBlock(p, false); 12914 CreateImprovedTerseBlock(p, false);
12851 12915
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs
index 073c357..41dd4d1 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs
@@ -206,6 +206,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
206 } 206 }
207 } 207 }
208 208
209 public bool HasUpdates()
210 {
211 J2KImage image = GetHighestPriorityImage();
212
213 return image != null && image.IsDecoded;
214 }
215
209 public bool ProcessImageQueue(int packetsToSend) 216 public bool ProcessImageQueue(int packetsToSend)
210 { 217 {
211 int packetsSent = 0; 218 int packetsSent = 0;
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
index f7ed14d..d52ad7e 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
@@ -31,6 +31,7 @@ using System.Net;
31using System.Threading; 31using System.Threading;
32using log4net; 32using log4net;
33using OpenSim.Framework; 33using OpenSim.Framework;
34using OpenSim.Framework.Monitoring;
34using OpenMetaverse; 35using OpenMetaverse;
35using OpenMetaverse.Packets; 36using OpenMetaverse.Packets;
36 37
@@ -81,6 +82,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
81 /// hooked to put more data on the empty queue</summary> 82 /// hooked to put more data on the empty queue</summary>
82 public event QueueEmpty OnQueueEmpty; 83 public event QueueEmpty OnQueueEmpty;
83 84
85 public event Func<ThrottleOutPacketTypeFlags, bool> HasUpdates;
86
84 /// <summary>AgentID for this client</summary> 87 /// <summary>AgentID for this client</summary>
85 public readonly UUID AgentID; 88 public readonly UUID AgentID;
86 /// <summary>The remote address of the connected client</summary> 89 /// <summary>The remote address of the connected client</summary>
@@ -645,15 +648,38 @@ namespace OpenSim.Region.ClientStack.LindenUDP
645 /// <param name="categories">Throttle categories to fire the callback for</param> 648 /// <param name="categories">Throttle categories to fire the callback for</param>
646 private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories) 649 private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories)
647 { 650 {
648 if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty) 651// if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty)
652 if (!m_isQueueEmptyRunning && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty)
649 { 653 {
654 m_isQueueEmptyRunning = true;
655
656 int start = Environment.TickCount & Int32.MaxValue;
657 const int MIN_CALLBACK_MS = 30;
658
659 m_nextOnQueueEmpty = start + MIN_CALLBACK_MS;
660 if (m_nextOnQueueEmpty == 0)
661 m_nextOnQueueEmpty = 1;
662
650 // Use a value of 0 to signal that FireQueueEmpty is running 663 // Use a value of 0 to signal that FireQueueEmpty is running
651 m_nextOnQueueEmpty = 0; 664// m_nextOnQueueEmpty = 0;
652 // Asynchronously run the callback 665
653 Util.FireAndForget(FireQueueEmpty, categories); 666 m_categories = categories;
667
668 if (HasUpdates(m_categories))
669 {
670 // Asynchronously run the callback
671 Util.FireAndForget(FireQueueEmpty, categories);
672 }
673 else
674 {
675 m_isQueueEmptyRunning = false;
676 }
654 } 677 }
655 } 678 }
656 679
680 private bool m_isQueueEmptyRunning;
681 private ThrottleOutPacketTypeFlags m_categories = 0;
682
657 /// <summary> 683 /// <summary>
658 /// Fires the OnQueueEmpty callback and sets the minimum time that it 684 /// Fires the OnQueueEmpty callback and sets the minimum time that it
659 /// can be called again 685 /// can be called again
@@ -663,22 +689,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP
663 /// signature</param> 689 /// signature</param>
664 private void FireQueueEmpty(object o) 690 private void FireQueueEmpty(object o)
665 { 691 {
666 const int MIN_CALLBACK_MS = 30; 692// int start = Environment.TickCount & Int32.MaxValue;
693// const int MIN_CALLBACK_MS = 30;
667 694
668 ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o; 695// if (m_udpServer.IsRunningOutbound)
669 QueueEmpty callback = OnQueueEmpty; 696// {
670 697 ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o;
671 int start = Environment.TickCount & Int32.MaxValue; 698 QueueEmpty callback = OnQueueEmpty;
672 699
673 if (callback != null) 700 if (callback != null)
674 { 701 {
675 try { callback(categories); } 702// if (m_udpServer.IsRunningOutbound)
676 catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); } 703// {
677 } 704 try { callback(categories); }
705 catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); }
706// }
707 }
708// }
709
710// m_nextOnQueueEmpty = start + MIN_CALLBACK_MS;
711// if (m_nextOnQueueEmpty == 0)
712// m_nextOnQueueEmpty = 1;
713
714// }
678 715
679 m_nextOnQueueEmpty = start + MIN_CALLBACK_MS; 716 m_isQueueEmptyRunning = false;
680 if (m_nextOnQueueEmpty == 0)
681 m_nextOnQueueEmpty = 1;
682 } 717 }
683 internal void ForceThrottleSetting(int throttle, int setting) 718 internal void ForceThrottleSetting(int throttle, int setting)
684 { 719 {
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
index b4ac021..7a4c6f4 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
@@ -69,9 +69,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
69 69
70 StatsManager.RegisterStat( 70 StatsManager.RegisterStat(
71 new Stat( 71 new Stat(
72 "IncomingUDPReceivesCount",
73 "Number of UDP receives performed",
74 "Number of UDP receives performed",
75 "",
76 "clientstack",
77 scene.Name,
78 StatType.Pull,
79 MeasuresOfInterest.AverageChangeOverTime,
80 stat => stat.Value = m_udpServer.UdpReceives,
81 StatVerbosity.Debug));
82
83 StatsManager.RegisterStat(
84 new Stat(
72 "IncomingPacketsProcessedCount", 85 "IncomingPacketsProcessedCount",
73 "Number of inbound UDP packets processed", 86 "Number of inbound LL protocol packets processed",
74 "Number of inbound UDP packets processed", 87 "Number of inbound LL protocol packets processed",
75 "", 88 "",
76 "clientstack", 89 "clientstack",
77 scene.Name, 90 scene.Name,
@@ -79,6 +92,34 @@ namespace OpenSim.Region.ClientStack.LindenUDP
79 MeasuresOfInterest.AverageChangeOverTime, 92 MeasuresOfInterest.AverageChangeOverTime,
80 stat => stat.Value = m_udpServer.IncomingPacketsProcessed, 93 stat => stat.Value = m_udpServer.IncomingPacketsProcessed,
81 StatVerbosity.Debug)); 94 StatVerbosity.Debug));
95
96 StatsManager.RegisterStat(
97 new Stat(
98 "OutgoingUDPSendsCount",
99 "Number of UDP sends performed",
100 "Number of UDP sends performed",
101 "",
102 "clientstack",
103 scene.Name,
104 StatType.Pull,
105 MeasuresOfInterest.AverageChangeOverTime,
106 stat => stat.Value = m_udpServer.UdpSends,
107 StatVerbosity.Debug));
108
109 StatsManager.RegisterStat(
110 new Stat(
111 "AverageUDPProcessTime",
112 "Average number of milliseconds taken to process each incoming UDP packet in a sample.",
113 "This is for initial receive processing which is separate from the later client LL packet processing stage.",
114 "ms",
115 "clientstack",
116 scene.Name,
117 StatType.Pull,
118 MeasuresOfInterest.None,
119 stat => stat.Value = m_udpServer.AverageReceiveTicksForLastSamplePeriod / TimeSpan.TicksPerMillisecond,
120// stat =>
121// stat.Value = Math.Round(m_udpServer.AverageReceiveTicksForLastSamplePeriod / TimeSpan.TicksPerMillisecond, 7),
122 StatVerbosity.Debug));
82 } 123 }
83 124
84 public bool HandlesRegion(Location x) 125 public bool HandlesRegion(Location x)
@@ -185,6 +226,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
185 protected bool m_sendPing; 226 protected bool m_sendPing;
186 227
187 private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>(); 228 private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>();
229
230 /// <summary>
231 /// Event used to signal when queued packets are available for sending.
232 /// </summary>
233 /// <remarks>
234 /// This allows the outbound loop to only operate when there is data to send rather than continuously polling.
235 /// Some data is sent immediately and not queued. That data would not trigger this event.
236 /// </remarks>
237 private AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false);
238
188 private Pool<IncomingPacket> m_incomingPacketPool; 239 private Pool<IncomingPacket> m_incomingPacketPool;
189 240
190 /// <summary> 241 /// <summary>
@@ -462,6 +513,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
462 m_scene = (Scene)scene; 513 m_scene = (Scene)scene;
463 m_location = new Location(m_scene.RegionInfo.RegionHandle); 514 m_location = new Location(m_scene.RegionInfo.RegionHandle);
464 515
516 StatsManager.RegisterStat(
517 new Stat(
518 "InboxPacketsCount",
519 "Number of LL protocol packets waiting for the second stage of processing after initial receive.",
520 "Number of LL protocol packets waiting for the second stage of processing after initial receive.",
521 "",
522 "clientstack",
523 scene.Name,
524 StatType.Pull,
525 MeasuresOfInterest.AverageChangeOverTime,
526 stat => stat.Value = packetInbox.Count,
527 StatVerbosity.Debug));
528
465 // XXX: These stats are also pool stats but we register them separately since they are currently not 529 // XXX: These stats are also pool stats but we register them separately since they are currently not
466 // turned on and off by EnablePools()/DisablePools() 530 // turned on and off by EnablePools()/DisablePools()
467 StatsManager.RegisterStat( 531 StatsManager.RegisterStat(
@@ -575,6 +639,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
575 "debug lludp status", 639 "debug lludp status",
576 "Return status of LLUDP packet processing.", 640 "Return status of LLUDP packet processing.",
577 HandleStatusCommand); 641 HandleStatusCommand);
642
643 MainConsole.Instance.Commands.AddCommand(
644 "Debug",
645 false,
646 "debug lludp toggle agentupdate",
647 "debug lludp toggle agentupdate",
648 "Toggle whether agentupdate packets are processed or simply discarded.",
649 HandleAgentUpdateCommand);
578 } 650 }
579 651
580 private void HandlePacketCommand(string module, string[] args) 652 private void HandlePacketCommand(string module, string[] args)
@@ -709,6 +781,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
709 } 781 }
710 } 782 }
711 783
784 bool m_discardAgentUpdates;
785
786 private void HandleAgentUpdateCommand(string module, string[] args)
787 {
788 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
789 return;
790
791 m_discardAgentUpdates = !m_discardAgentUpdates;
792
793 MainConsole.Instance.OutputFormat(
794 "Discard AgentUpdates now {0} for {1}", m_discardAgentUpdates, m_scene.Name);
795 }
796
712 private void HandleStatusCommand(string module, string[] args) 797 private void HandleStatusCommand(string module, string[] args)
713 { 798 {
714 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) 799 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
@@ -809,12 +894,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
809 } 894 }
810 895
811 PacketPool.Instance.ReturnPacket(packet); 896 PacketPool.Instance.ReturnPacket(packet);
812 m_dataPresentEvent.Set();
813 897
898 m_dataPresentEvent.Set();
814 } 899 }
815 900
816 private AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false);
817
818 /// <summary> 901 /// <summary>
819 /// Start the process of sending a packet to the client. 902 /// Start the process of sending a packet to the client.
820 /// </summary> 903 /// </summary>
@@ -1325,6 +1408,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1325 LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length); 1408 LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length);
1326 #endregion BinaryStats 1409 #endregion BinaryStats
1327 1410
1411 if (packet.Type == PacketType.AgentUpdate)
1412 {
1413 if (m_discardAgentUpdates)
1414 return;
1415
1416 ((LLClientView)client).TotalAgentUpdates++;
1417
1418 AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
1419
1420 LLClientView llClient = client as LLClientView;
1421 if (agentUpdate.AgentData.SessionID != client.SessionId
1422 || agentUpdate.AgentData.AgentID != client.AgentId
1423 || !(llClient == null || llClient.CheckAgentUpdateSignificance(agentUpdate.AgentData)) )
1424 {
1425 PacketPool.Instance.ReturnPacket(packet);
1426 return;
1427 }
1428 }
1429
1328 #region Ping Check Handling 1430 #region Ping Check Handling
1329 1431
1330 if (packet.Type == PacketType.StartPingCheck) 1432 if (packet.Type == PacketType.StartPingCheck)
@@ -1734,7 +1836,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1734 // Action generic every round 1836 // Action generic every round
1735 Action<IClientAPI> clientPacketHandler = ClientOutgoingPacketHandler; 1837 Action<IClientAPI> clientPacketHandler = ClientOutgoingPacketHandler;
1736 1838
1737// while (true)
1738 while (base.IsRunningOutbound) 1839 while (base.IsRunningOutbound)
1739 { 1840 {
1740 m_scene.ThreadAlive(2); 1841 m_scene.ThreadAlive(2);
@@ -1798,6 +1899,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1798 // token bucket could get more tokens 1899 // token bucket could get more tokens
1799 //if (!m_packetSent) 1900 //if (!m_packetSent)
1800 // Thread.Sleep((int)TickCountResolution); 1901 // Thread.Sleep((int)TickCountResolution);
1902 //
1903 // Instead, now wait for data present to be explicitly signalled. Evidence so far is that with
1904 // modern mono it reduces CPU base load since there is no more continuous polling.
1801 m_dataPresentEvent.WaitOne(100); 1905 m_dataPresentEvent.WaitOne(100);
1802 1906
1803 Watchdog.UpdateThread(); 1907 Watchdog.UpdateThread();
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
index 7035e38..48c5b37 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
@@ -78,6 +78,36 @@ namespace OpenMetaverse
78 public bool IsRunningOutbound { get; private set; } 78 public bool IsRunningOutbound { get; private set; }
79 79
80 /// <summary> 80 /// <summary>
81 /// Number of UDP receives.
82 /// </summary>
83 public int UdpReceives { get; private set; }
84
85 /// <summary>
86 /// Number of UDP sends
87 /// </summary>
88 public int UdpSends { get; private set; }
89
90 /// <summary>
91 /// Number of receives over which to establish a receive time average.
92 /// </summary>
93 private readonly static int s_receiveTimeSamples = 500;
94
95 /// <summary>
96 /// Current number of samples taken to establish a receive time average.
97 /// </summary>
98 private int m_currentReceiveTimeSamples;
99
100 /// <summary>
101 /// Cumulative receive time for the sample so far.
102 /// </summary>
103 private int m_receiveTicksInCurrentSamplePeriod;
104
105 /// <summary>
106 /// The average time taken for each require receive in the last sample.
107 /// </summary>
108 public float AverageReceiveTicksForLastSamplePeriod { get; private set; }
109
110 /// <summary>
81 /// Default constructor 111 /// Default constructor
82 /// </summary> 112 /// </summary>
83 /// <param name="bindAddress">Local IP address to bind the server to</param> 113 /// <param name="bindAddress">Local IP address to bind the server to</param>
@@ -111,6 +141,8 @@ namespace OpenMetaverse
111 141
112 if (!IsRunningInbound) 142 if (!IsRunningInbound)
113 { 143 {
144 m_log.DebugFormat("[UDPBASE]: Starting inbound UDP loop");
145
114 const int SIO_UDP_CONNRESET = -1744830452; 146 const int SIO_UDP_CONNRESET = -1744830452;
115 147
116 IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort); 148 IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort);
@@ -151,6 +183,8 @@ namespace OpenMetaverse
151 /// </summary> 183 /// </summary>
152 public void StartOutbound() 184 public void StartOutbound()
153 { 185 {
186 m_log.DebugFormat("[UDPBASE]: Starting outbound UDP loop");
187
154 IsRunningOutbound = true; 188 IsRunningOutbound = true;
155 } 189 }
156 190
@@ -158,10 +192,8 @@ namespace OpenMetaverse
158 { 192 {
159 if (IsRunningInbound) 193 if (IsRunningInbound)
160 { 194 {
161 // wait indefinitely for a writer lock. Once this is called, the .NET runtime 195 m_log.DebugFormat("[UDPBASE]: Stopping inbound UDP loop");
162 // will deny any more reader locks, in effect blocking all other send/receive 196
163 // threads. Once we have the lock, we set IsRunningInbound = false to inform the other
164 // threads that the socket is closed.
165 IsRunningInbound = false; 197 IsRunningInbound = false;
166 m_udpSocket.Close(); 198 m_udpSocket.Close();
167 } 199 }
@@ -169,6 +201,8 @@ namespace OpenMetaverse
169 201
170 public void StopOutbound() 202 public void StopOutbound()
171 { 203 {
204 m_log.DebugFormat("[UDPBASE]: Stopping outbound UDP loop");
205
172 IsRunningOutbound = false; 206 IsRunningOutbound = false;
173 } 207 }
174 208
@@ -267,6 +301,8 @@ namespace OpenMetaverse
267 // to AsyncBeginReceive 301 // to AsyncBeginReceive
268 if (IsRunningInbound) 302 if (IsRunningInbound)
269 { 303 {
304 UdpReceives++;
305
270 // Asynchronous mode will start another receive before the 306 // Asynchronous mode will start another receive before the
271 // callback for this packet is even fired. Very parallel :-) 307 // callback for this packet is even fired. Very parallel :-)
272 if (m_asyncPacketHandling) 308 if (m_asyncPacketHandling)
@@ -278,6 +314,8 @@ namespace OpenMetaverse
278 314
279 try 315 try
280 { 316 {
317 int startTick = Util.EnvironmentTickCount();
318
281 // get the length of data actually read from the socket, store it with the 319 // get the length of data actually read from the socket, store it with the
282 // buffer 320 // buffer
283 buffer.DataLength = m_udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint); 321 buffer.DataLength = m_udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint);
@@ -285,6 +323,23 @@ namespace OpenMetaverse
285 // call the abstract method PacketReceived(), passing the buffer that 323 // call the abstract method PacketReceived(), passing the buffer that
286 // has just been filled from the socket read. 324 // has just been filled from the socket read.
287 PacketReceived(buffer); 325 PacketReceived(buffer);
326
327 // If more than one thread can be calling AsyncEndReceive() at once (e.g. if m_asyncPacketHandler)
328 // then a particular stat may be inaccurate due to a race condition. We won't worry about this
329 // since this should be rare and won't cause a runtime problem.
330 if (m_currentReceiveTimeSamples >= s_receiveTimeSamples)
331 {
332 AverageReceiveTicksForLastSamplePeriod
333 = (float)m_receiveTicksInCurrentSamplePeriod / s_receiveTimeSamples;
334
335 m_receiveTicksInCurrentSamplePeriod = 0;
336 m_currentReceiveTimeSamples = 0;
337 }
338 else
339 {
340 m_receiveTicksInCurrentSamplePeriod += Util.EnvironmentTickCountSubtract(startTick);
341 m_currentReceiveTimeSamples++;
342 }
288 } 343 }
289 catch (SocketException) { } 344 catch (SocketException) { }
290 catch (ObjectDisposedException) { } 345 catch (ObjectDisposedException) { }
@@ -298,14 +353,13 @@ namespace OpenMetaverse
298 if (!m_asyncPacketHandling) 353 if (!m_asyncPacketHandling)
299 AsyncBeginReceive(); 354 AsyncBeginReceive();
300 } 355 }
301
302 } 356 }
303 } 357 }
304 358
305 public void AsyncBeginSend(UDPPacketBuffer buf) 359 public void AsyncBeginSend(UDPPacketBuffer buf)
306 { 360 {
307 if (IsRunningOutbound) 361// if (IsRunningOutbound)
308 { 362// {
309 try 363 try
310 { 364 {
311 m_udpSocket.BeginSendTo( 365 m_udpSocket.BeginSendTo(
@@ -319,7 +373,7 @@ namespace OpenMetaverse
319 } 373 }
320 catch (SocketException) { } 374 catch (SocketException) { }
321 catch (ObjectDisposedException) { } 375 catch (ObjectDisposedException) { }
322 } 376// }
323 } 377 }
324 378
325 void AsyncEndSend(IAsyncResult result) 379 void AsyncEndSend(IAsyncResult result)
@@ -328,6 +382,8 @@ namespace OpenMetaverse
328 { 382 {
329// UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState; 383// UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState;
330 m_udpSocket.EndSendTo(result); 384 m_udpSocket.EndSendTo(result);
385
386 UdpSends++;
331 } 387 }
332 catch (SocketException) { } 388 catch (SocketException) { }
333 catch (ObjectDisposedException) { } 389 catch (ObjectDisposedException) { }
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs
index e0c8ea6..8f9800f 100644
--- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs
@@ -185,8 +185,11 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
185 } 185 }
186 } 186 }
187 187
188 public void UploadInventoryItem(UUID avatarID, UUID assetID, string name, int userlevel) 188 public void UploadInventoryItem(UUID avatarID, AssetType type, UUID assetID, string name, int userlevel)
189 { 189 {
190 if (type == AssetType.Link)
191 return;
192
190 string userAssetServer = string.Empty; 193 string userAssetServer = string.Empty;
191 if (IsForeignUser(avatarID, out userAssetServer) && userAssetServer != string.Empty && m_OutboundPermission) 194 if (IsForeignUser(avatarID, out userAssetServer) && userAssetServer != string.Empty && m_OutboundPermission)
192 { 195 {
@@ -221,7 +224,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
221 { 224 {
222 UUID newAssetID = base.CapsUpdateInventoryItemAsset(remoteClient, itemID, data); 225 UUID newAssetID = base.CapsUpdateInventoryItemAsset(remoteClient, itemID, data);
223 226
224 UploadInventoryItem(remoteClient.AgentId, newAssetID, "", 0); 227 UploadInventoryItem(remoteClient.AgentId, AssetType.Unknown, newAssetID, "", 0);
225 228
226 return newAssetID; 229 return newAssetID;
227 } 230 }
@@ -232,7 +235,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
232 protected override void ExportAsset(UUID agentID, UUID assetID) 235 protected override void ExportAsset(UUID agentID, UUID assetID)
233 { 236 {
234 if (!assetID.Equals(UUID.Zero)) 237 if (!assetID.Equals(UUID.Zero))
235 UploadInventoryItem(agentID, assetID, "", 0); 238 UploadInventoryItem(agentID, AssetType.Unknown, assetID, "", 0);
236 else 239 else
237 m_log.Debug("[HGScene]: Scene.Inventory did not create asset"); 240 m_log.Debug("[HGScene]: Scene.Inventory did not create asset");
238 } 241 }
@@ -348,7 +351,15 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
348 InventoryFolderBase root = m_Scene.InventoryService.GetRootFolder(client.AgentId); 351 InventoryFolderBase root = m_Scene.InventoryService.GetRootFolder(client.AgentId);
349 InventoryCollection content = m_Scene.InventoryService.GetFolderContent(client.AgentId, root.ID); 352 InventoryCollection content = m_Scene.InventoryService.GetFolderContent(client.AgentId, root.ID);
350 353
351 inv.SendBulkUpdateInventory(content.Folders.ToArray(), content.Items.ToArray()); 354 List<InventoryFolderBase> keep = new List<InventoryFolderBase>();
355
356 foreach (InventoryFolderBase f in content.Folders)
357 {
358 if (f.Name != "My Suitcase" && f.Name != "Current Outfit")
359 keep.Add(f);
360 }
361
362 inv.SendBulkUpdateInventory(keep.ToArray(), content.Items.ToArray());
352 } 363 }
353 } 364 }
354 } 365 }
@@ -381,7 +392,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
381 392
382 foreach (InventoryFolderBase f in content.Folders) 393 foreach (InventoryFolderBase f in content.Folders)
383 { 394 {
384 if (f.Name != "My Suitcase") 395 if (f.Name != "My Suitcase" && f.Name != "Current Outfit")
385 { 396 {
386 f.Name = f.Name + " (Unavailable)"; 397 f.Name = f.Name + " (Unavailable)";
387 keep.Add(f); 398 keep.Add(f);
diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs
index a91adfa..53bd2e2 100644
--- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs
@@ -389,7 +389,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
389 } 389 }
390 390
391 names[0] = "Unknown"; 391 names[0] = "Unknown";
392 names[1] = "UserUMMTGUN7"; 392 names[1] = "UserUMMTGUN8";
393 393
394 return false; 394 return false;
395 } 395 }
@@ -601,7 +601,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
601 // TODO: Can be removed when GUN* unknown users have definitely dropped significantly or 601 // TODO: Can be removed when GUN* unknown users have definitely dropped significantly or
602 // disappeared. 602 // disappeared.
603 user.FirstName = "Unknown"; 603 user.FirstName = "Unknown";
604 user.LastName = "UserUMMAU3"; 604 user.LastName = "UserUMMAU4";
605 } 605 }
606 606
607 AddUserInternal(user); 607 AddUserInternal(user);
diff --git a/OpenSim/Region/Framework/Scenes/EventManager.cs b/OpenSim/Region/Framework/Scenes/EventManager.cs
index 1018b54..6e8eb91 100644
--- a/OpenSim/Region/Framework/Scenes/EventManager.cs
+++ b/OpenSim/Region/Framework/Scenes/EventManager.cs
@@ -743,7 +743,7 @@ namespace OpenSim.Region.Framework.Scenes
743 public event OnIncomingSceneObjectDelegate OnIncomingSceneObject; 743 public event OnIncomingSceneObjectDelegate OnIncomingSceneObject;
744 public delegate void OnIncomingSceneObjectDelegate(SceneObjectGroup so); 744 public delegate void OnIncomingSceneObjectDelegate(SceneObjectGroup so);
745 745
746 public delegate void NewInventoryItemUploadComplete(UUID avatarID, UUID assetID, string name, int userlevel); 746 public delegate void NewInventoryItemUploadComplete(UUID avatarID, AssetType type, UUID assetID, string name, int userlevel);
747 747
748 public event NewInventoryItemUploadComplete OnNewInventoryItemUploadComplete; 748 public event NewInventoryItemUploadComplete OnNewInventoryItemUploadComplete;
749 749
@@ -2172,7 +2172,7 @@ namespace OpenSim.Region.Framework.Scenes
2172 } 2172 }
2173 } 2173 }
2174 2174
2175 public void TriggerOnNewInventoryItemUploadComplete(UUID agentID, UUID AssetID, String AssetName, int userlevel) 2175 public void TriggerOnNewInventoryItemUploadComplete(UUID agentID, AssetType type, UUID AssetID, String AssetName, int userlevel)
2176 { 2176 {
2177 NewInventoryItemUploadComplete handlerNewInventoryItemUpdateComplete = OnNewInventoryItemUploadComplete; 2177 NewInventoryItemUploadComplete handlerNewInventoryItemUpdateComplete = OnNewInventoryItemUploadComplete;
2178 if (handlerNewInventoryItemUpdateComplete != null) 2178 if (handlerNewInventoryItemUpdateComplete != null)
@@ -2181,7 +2181,7 @@ namespace OpenSim.Region.Framework.Scenes
2181 { 2181 {
2182 try 2182 try
2183 { 2183 {
2184 d(agentID, AssetID, AssetName, userlevel); 2184 d(agentID, type, AssetID, AssetName, userlevel);
2185 } 2185 }
2186 catch (Exception e) 2186 catch (Exception e)
2187 { 2187 {
diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
index 70018c8..8f6073a 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
@@ -139,7 +139,7 @@ namespace OpenSim.Region.Framework.Scenes
139 { 139 {
140 userlevel = 1; 140 userlevel = 1;
141 } 141 }
142 EventManager.TriggerOnNewInventoryItemUploadComplete(item.Owner, item.AssetID, item.Name, userlevel); 142 EventManager.TriggerOnNewInventoryItemUploadComplete(item.Owner, (AssetType)item.AssetType, item.AssetID, item.Name, userlevel);
143 143
144 return true; 144 return true;
145 } 145 }
@@ -178,7 +178,7 @@ namespace OpenSim.Region.Framework.Scenes
178 { 178 {
179 userlevel = 1; 179 userlevel = 1;
180 } 180 }
181 EventManager.TriggerOnNewInventoryItemUploadComplete(item.Owner, item.AssetID, item.Name, userlevel); 181 EventManager.TriggerOnNewInventoryItemUploadComplete(item.Owner, (AssetType)item.AssetType, item.AssetID, item.Name, userlevel);
182 182
183 if (originalFolder != UUID.Zero) 183 if (originalFolder != UUID.Zero)
184 { 184 {
diff --git a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs
index ce6415a..421cb08 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs
@@ -416,6 +416,7 @@ namespace OpenSim.Region.Framework.Scenes
416 void ProcessViewerEffect(IClientAPI remoteClient, List<ViewerEffectEventHandlerArg> args) 416 void ProcessViewerEffect(IClientAPI remoteClient, List<ViewerEffectEventHandlerArg> args)
417 { 417 {
418 // TODO: don't create new blocks if recycling an old packet 418 // TODO: don't create new blocks if recycling an old packet
419 bool discardableEffects = true;
419 ViewerEffectPacket.EffectBlock[] effectBlockArray = new ViewerEffectPacket.EffectBlock[args.Count]; 420 ViewerEffectPacket.EffectBlock[] effectBlockArray = new ViewerEffectPacket.EffectBlock[args.Count];
420 for (int i = 0; i < args.Count; i++) 421 for (int i = 0; i < args.Count; i++)
421 { 422 {
@@ -427,17 +428,34 @@ namespace OpenSim.Region.Framework.Scenes
427 effect.Type = args[i].Type; 428 effect.Type = args[i].Type;
428 effect.TypeData = args[i].TypeData; 429 effect.TypeData = args[i].TypeData;
429 effectBlockArray[i] = effect; 430 effectBlockArray[i] = effect;
431
432 if ((EffectType)effect.Type != EffectType.LookAt && (EffectType)effect.Type != EffectType.Beam)
433 discardableEffects = false;
434
435 //m_log.DebugFormat("[YYY]: VE {0} {1} {2}", effect.AgentID, effect.Duration, (EffectType)effect.Type);
430 } 436 }
431 437
432 ForEachClient( 438 ForEachScenePresence(sp =>
433 delegate(IClientAPI client)
434 { 439 {
435 if (client.AgentId != remoteClient.AgentId) 440 if (sp.ControllingClient.AgentId != remoteClient.AgentId)
436 client.SendViewerEffect(effectBlockArray); 441 {
437 } 442 if (!discardableEffects ||
438 ); 443 (discardableEffects && ShouldSendDiscardableEffect(remoteClient, sp)))
444 {
445 //m_log.DebugFormat("[YYY]: Sending to {0}", sp.UUID);
446 sp.ControllingClient.SendViewerEffect(effectBlockArray);
447 }
448 //else
449 // m_log.DebugFormat("[YYY]: Not sending to {0}", sp.UUID);
450 }
451 });
439 } 452 }
440 453
454 private bool ShouldSendDiscardableEffect(IClientAPI thisClient, ScenePresence other)
455 {
456 return Vector3.Distance(other.CameraPosition, thisClient.SceneAgent.AbsolutePosition) < 10;
457 }
458
441 private class DescendentsRequestData 459 private class DescendentsRequestData
442 { 460 {
443 public IClientAPI RemoteClient; 461 public IClientAPI RemoteClient;
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index 6e4ac98..1225c2e 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -142,6 +142,8 @@ namespace OpenSim.Region.Framework.Scenes
142 private Vector3 m_lastVelocity; 142 private Vector3 m_lastVelocity;
143 private Vector3 m_lastSize = new Vector3(0.45f,0.6f,1.9f); 143 private Vector3 m_lastSize = new Vector3(0.45f,0.6f,1.9f);
144 144
145 private bool m_followCamAuto = false;
146
145 147
146 private Vector3? m_forceToApply; 148 private Vector3? m_forceToApply;
147 private int m_userFlags; 149 private int m_userFlags;
@@ -874,6 +876,7 @@ namespace OpenSim.Region.Framework.Scenes
874 { 876 {
875 ControllingClient.OnCompleteMovementToRegion += CompleteMovement; 877 ControllingClient.OnCompleteMovementToRegion += CompleteMovement;
876 ControllingClient.OnAgentUpdate += HandleAgentUpdate; 878 ControllingClient.OnAgentUpdate += HandleAgentUpdate;
879 ControllingClient.OnAgentCameraUpdate += HandleAgentCamerasUpdate;
877 ControllingClient.OnAgentRequestSit += HandleAgentRequestSit; 880 ControllingClient.OnAgentRequestSit += HandleAgentRequestSit;
878 ControllingClient.OnAgentSit += HandleAgentSit; 881 ControllingClient.OnAgentSit += HandleAgentSit;
879 ControllingClient.OnSetAlwaysRun += HandleSetAlwaysRun; 882 ControllingClient.OnSetAlwaysRun += HandleSetAlwaysRun;
@@ -1306,7 +1309,26 @@ namespace OpenSim.Region.Framework.Scenes
1306 1309
1307 public void StopFlying() 1310 public void StopFlying()
1308 { 1311 {
1309 ControllingClient.StopFlying(this); 1312 Vector3 pos = AbsolutePosition;
1313 if (Appearance.AvatarHeight != 127.0f)
1314 pos += new Vector3(0f, 0f, (Appearance.AvatarHeight / 6f));
1315 else
1316 pos += new Vector3(0f, 0f, (1.56f / 6f));
1317
1318 AbsolutePosition = pos;
1319
1320 // attach a suitable collision plane regardless of the actual situation to force the LLClient to land.
1321 // Collision plane below the avatar's position a 6th of the avatar's height is suitable.
1322 // Mind you, that this method doesn't get called if the avatar's velocity magnitude is greater then a
1323 // certain amount.. because the LLClient wouldn't land in that situation anyway.
1324
1325 // why are we still testing for this really old height value default???
1326 if (Appearance.AvatarHeight != 127.0f)
1327 CollisionPlane = new Vector4(0, 0, 0, pos.Z - Appearance.AvatarHeight / 6f);
1328 else
1329 CollisionPlane = new Vector4(0, 0, 0, pos.Z - (1.56f / 6f));
1330
1331 ControllingClient.SendAgentTerseUpdate(this);
1310 } 1332 }
1311 1333
1312 /// <summary> 1334 /// <summary>
@@ -1662,9 +1684,9 @@ namespace OpenSim.Region.Framework.Scenes
1662 /// </summary> 1684 /// </summary>
1663 public void HandleAgentUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData) 1685 public void HandleAgentUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData)
1664 { 1686 {
1665// m_log.DebugFormat( 1687 //m_log.DebugFormat(
1666// "[SCENE PRESENCE]: In {0} received agent update from {1}, flags {2}", 1688 // "[SCENE PRESENCE]: In {0} received agent update from {1}, flags {2}",
1667// Scene.RegionInfo.RegionName, remoteClient.Name, (AgentManager.ControlFlags)agentData.ControlFlags); 1689 // Scene.RegionInfo.RegionName, remoteClient.Name, (AgentManager.ControlFlags)agentData.ControlFlags);
1668 1690
1669 if (IsChildAgent) 1691 if (IsChildAgent)
1670 { 1692 {
@@ -1672,10 +1694,6 @@ namespace OpenSim.Region.Framework.Scenes
1672 return; 1694 return;
1673 } 1695 }
1674 1696
1675 ++m_movementUpdateCount;
1676 if (m_movementUpdateCount < 1)
1677 m_movementUpdateCount = 1;
1678
1679 #region Sanity Checking 1697 #region Sanity Checking
1680 1698
1681 // This is irritating. Really. 1699 // This is irritating. Really.
@@ -1706,21 +1724,6 @@ namespace OpenSim.Region.Framework.Scenes
1706 1724
1707 AgentManager.ControlFlags flags = (AgentManager.ControlFlags)agentData.ControlFlags; 1725 AgentManager.ControlFlags flags = (AgentManager.ControlFlags)agentData.ControlFlags;
1708 1726
1709 // Camera location in world. We'll need to raytrace
1710 // from this location from time to time.
1711 CameraPosition = agentData.CameraCenter;
1712 if (Vector3.Distance(m_lastCameraPosition, CameraPosition) >= Scene.RootReprioritizationDistance)
1713 {
1714 ReprioritizeUpdates();
1715 m_lastCameraPosition = CameraPosition;
1716 }
1717
1718 // Use these three vectors to figure out what the agent is looking at
1719 // Convert it to a Matrix and/or Quaternion
1720 CameraAtAxis = agentData.CameraAtAxis;
1721 CameraLeftAxis = agentData.CameraLeftAxis;
1722 CameraUpAxis = agentData.CameraUpAxis;
1723
1724 // The Agent's Draw distance setting 1727 // The Agent's Draw distance setting
1725 // When we get to the point of re-computing neighbors everytime this 1728 // When we get to the point of re-computing neighbors everytime this
1726 // changes, then start using the agent's drawdistance rather than the 1729 // changes, then start using the agent's drawdistance rather than the
@@ -2005,10 +2008,79 @@ namespace OpenSim.Region.Framework.Scenes
2005 SendControlsToScripts(flagsForScripts); 2008 SendControlsToScripts(flagsForScripts);
2006 } 2009 }
2007 2010
2011 // We need to send this back to the client in order to see the edit beams
2012 if ((State & (uint)AgentState.Editing) != 0)
2013 ControllingClient.SendAgentTerseUpdate(this);
2014
2008 m_scene.EventManager.TriggerOnClientMovement(this); 2015 m_scene.EventManager.TriggerOnClientMovement(this);
2009 TriggerScenePresenceUpdated();
2010 } 2016 }
2011 2017
2018
2019 /// <summary>
2020 /// This is the event handler for client cameras. If a client is moving, or moving the camera, this event is triggering.
2021 /// </summary>
2022 private void HandleAgentCamerasUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData)
2023 {
2024 //m_log.DebugFormat(
2025 // "[SCENE PRESENCE]: In {0} received agent camera update from {1}, flags {2}",
2026 // Scene.RegionInfo.RegionName, remoteClient.Name, (AgentManager.ControlFlags)agentData.ControlFlags);
2027
2028 if (IsChildAgent)
2029 {
2030 // // m_log.Debug("DEBUG: HandleAgentUpdate: child agent");
2031 return;
2032 }
2033
2034 ++m_movementUpdateCount;
2035 if (m_movementUpdateCount < 1)
2036 m_movementUpdateCount = 1;
2037
2038
2039 AgentManager.ControlFlags flags = (AgentManager.ControlFlags)agentData.ControlFlags;
2040
2041 // Camera location in world. We'll need to raytrace
2042 // from this location from time to time.
2043 CameraPosition = agentData.CameraCenter;
2044 if (Vector3.Distance(m_lastCameraPosition, CameraPosition) >= Scene.RootReprioritizationDistance)
2045 {
2046 ReprioritizeUpdates();
2047 m_lastCameraPosition = CameraPosition;
2048 }
2049
2050 // Use these three vectors to figure out what the agent is looking at
2051 // Convert it to a Matrix and/or Quaternion
2052 CameraAtAxis = agentData.CameraAtAxis;
2053 CameraLeftAxis = agentData.CameraLeftAxis;
2054 CameraUpAxis = agentData.CameraUpAxis;
2055
2056 // The Agent's Draw distance setting
2057 // When we get to the point of re-computing neighbors everytime this
2058 // changes, then start using the agent's drawdistance rather than the
2059 // region's draw distance.
2060 // DrawDistance = agentData.Far;
2061 DrawDistance = Scene.DefaultDrawDistance;
2062
2063 // Check if Client has camera in 'follow cam' or 'build' mode.
2064 Vector3 camdif = (Vector3.One * Rotation - Vector3.One * CameraRotation);
2065
2066 m_followCamAuto = ((CameraUpAxis.Z > 0.959f && CameraUpAxis.Z < 0.98f)
2067 && (Math.Abs(camdif.X) < 0.4f && Math.Abs(camdif.Y) < 0.4f)) ? true : false;
2068
2069
2070 //m_log.DebugFormat("[FollowCam]: {0}", m_followCamAuto);
2071 // Raycast from the avatar's head to the camera to see if there's anything blocking the view
2072 if ((m_movementUpdateCount % NumMovementsBetweenRayCast) == 0 && m_scene.PhysicsScene.SupportsRayCast())
2073 {
2074 if (m_followCamAuto)
2075 {
2076 Vector3 posAdjusted = m_pos + HEAD_ADJUSTMENT;
2077 m_scene.PhysicsScene.RaycastWorld(m_pos, Vector3.Normalize(CameraPosition - posAdjusted), Vector3.Distance(CameraPosition, posAdjusted) + 0.3f, RayCastCameraCallback);
2078 }
2079 }
2080
2081 TriggerScenePresenceUpdated();
2082 }
2083
2012 /// <summary> 2084 /// <summary>
2013 /// Calculate an update to move the presence to the set target. 2085 /// Calculate an update to move the presence to the set target.
2014 /// </summary> 2086 /// </summary>
diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
index b28d96b..a96c8b4 100644
--- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
+++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
@@ -688,6 +688,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
688 public event Action<IClientAPI, bool> OnCompleteMovementToRegion; 688 public event Action<IClientAPI, bool> OnCompleteMovementToRegion;
689 public event UpdateAgent OnPreAgentUpdate; 689 public event UpdateAgent OnPreAgentUpdate;
690 public event UpdateAgent OnAgentUpdate; 690 public event UpdateAgent OnAgentUpdate;
691 public event UpdateAgent OnAgentCameraUpdate;
691 public event AgentRequestSit OnAgentRequestSit; 692 public event AgentRequestSit OnAgentRequestSit;
692 public event AgentSit OnAgentSit; 693 public event AgentSit OnAgentSit;
693 public event AvatarPickerRequest OnAvatarPickerRequest; 694 public event AvatarPickerRequest OnAvatarPickerRequest;
@@ -1687,7 +1688,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
1687 { 1688 {
1688 } 1689 }
1689 1690
1690 public void StopFlying(ISceneEntity presence) 1691 public void SendAgentTerseUpdate(ISceneEntity presence)
1691 { 1692 {
1692 } 1693 }
1693 1694
diff --git a/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs b/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs
index 79509ab..15dea17 100644
--- a/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs
+++ b/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs
@@ -611,7 +611,7 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden
611 // 611 //
612 if (showParams.Length <= 4) 612 if (showParams.Length <= 4)
613 { 613 {
614 m_log.InfoFormat("[INFO]: {0,-12} {1,20} {2,6} {3,11} {4, 10}", "Region", "Name", "Root", "Time", "Reqs/min"); 614 m_log.InfoFormat("[INFO]: {0,-12} {1,-20} {2,-6} {3,-11} {4,-11} {5,-16}", "Region", "Name", "Root", "Time", "Reqs/min", "AgentUpdates");
615 foreach (Scene scene in m_scenes.Values) 615 foreach (Scene scene in m_scenes.Values)
616 { 616 {
617 scene.ForEachClient( 617 scene.ForEachClient(
@@ -624,9 +624,15 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden
624 int avg_reqs = cinfo.AsyncRequests.Values.Sum() + cinfo.GenericRequests.Values.Sum() + cinfo.SyncRequests.Values.Sum(); 624 int avg_reqs = cinfo.AsyncRequests.Values.Sum() + cinfo.GenericRequests.Values.Sum() + cinfo.SyncRequests.Values.Sum();
625 avg_reqs = avg_reqs / ((DateTime.Now - cinfo.StartedTime).Minutes + 1); 625 avg_reqs = avg_reqs / ((DateTime.Now - cinfo.StartedTime).Minutes + 1);
626 626
627 m_log.InfoFormat("[INFO]: {0,-12} {1,20} {2,4} {3,9}min {4,10}", 627 m_log.InfoFormat("[INFO]: {0,-12} {1,-20} {2,-6} {3,-11} {4,-11} {5,-16}",
628 scene.RegionInfo.RegionName, llClient.Name, 628 scene.RegionInfo.RegionName, llClient.Name,
629 (llClient.SceneAgent.IsChildAgent ? "N" : "Y"), (DateTime.Now - cinfo.StartedTime).Minutes, avg_reqs); 629 llClient.SceneAgent.IsChildAgent ? "N" : "Y",
630 (DateTime.Now - cinfo.StartedTime).Minutes,
631 avg_reqs,
632 string.Format(
633 "{0} ({1:0.00}%)",
634 llClient.TotalAgentUpdates,
635 (float)cinfo.SyncRequests["AgentUpdate"] / llClient.TotalAgentUpdates * 100));
630 } 636 }
631 }); 637 });
632 } 638 }
diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
index c8aab54..f2355e2 100644
--- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
+++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
@@ -259,6 +259,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
259 public event Action<IClientAPI, bool> OnCompleteMovementToRegion; 259 public event Action<IClientAPI, bool> OnCompleteMovementToRegion;
260 public event UpdateAgent OnPreAgentUpdate; 260 public event UpdateAgent OnPreAgentUpdate;
261 public event UpdateAgent OnAgentUpdate; 261 public event UpdateAgent OnAgentUpdate;
262 public event UpdateAgent OnAgentCameraUpdate;
262 public event AgentRequestSit OnAgentRequestSit; 263 public event AgentRequestSit OnAgentRequestSit;
263 public event AgentSit OnAgentSit; 264 public event AgentSit OnAgentSit;
264 public event AvatarPickerRequest OnAvatarPickerRequest; 265 public event AvatarPickerRequest OnAvatarPickerRequest;
@@ -1242,7 +1243,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
1242 { 1243 {
1243 } 1244 }
1244 1245
1245 public void StopFlying(ISceneEntity presence) 1246 public void SendAgentTerseUpdate(ISceneEntity presence)
1246 { 1247 {
1247 } 1248 }
1248 1249
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs
index fff63e4..e0ccc50 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs
@@ -69,7 +69,7 @@ public class BSActorCollection
69 { 69 {
70 lock (m_actors) 70 lock (m_actors)
71 { 71 {
72 Release(); 72 ForEachActor(a => a.Dispose());
73 m_actors.Clear(); 73 m_actors.Clear();
74 } 74 }
75 } 75 }
@@ -98,10 +98,6 @@ public class BSActorCollection
98 { 98 {
99 ForEachActor(a => a.SetEnabled(enabl)); 99 ForEachActor(a => a.SetEnabled(enabl));
100 } 100 }
101 public void Release()
102 {
103 ForEachActor(a => a.Dispose());
104 }
105 public void Refresh() 101 public void Refresh()
106 { 102 {
107 ForEachActor(a => a.Refresh()); 103 ForEachActor(a => a.Refresh());
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index 0204967..82d7c44 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -45,7 +45,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
45 private static string LogHeader = "[BULLETSIM VEHICLE]"; 45 private static string LogHeader = "[BULLETSIM VEHICLE]";
46 46
47 // the prim this dynamic controller belongs to 47 // the prim this dynamic controller belongs to
48 private BSPrim ControllingPrim { get; set; } 48 private BSPrimLinkable ControllingPrim { get; set; }
49 49
50 private bool m_haveRegisteredForSceneEvents; 50 private bool m_haveRegisteredForSceneEvents;
51 51
@@ -128,9 +128,15 @@ namespace OpenSim.Region.Physics.BulletSPlugin
128 public BSDynamics(BSScene myScene, BSPrim myPrim, string actorName) 128 public BSDynamics(BSScene myScene, BSPrim myPrim, string actorName)
129 : base(myScene, myPrim, actorName) 129 : base(myScene, myPrim, actorName)
130 { 130 {
131 ControllingPrim = myPrim;
132 Type = Vehicle.TYPE_NONE; 131 Type = Vehicle.TYPE_NONE;
133 m_haveRegisteredForSceneEvents = false; 132 m_haveRegisteredForSceneEvents = false;
133
134 ControllingPrim = myPrim as BSPrimLinkable;
135 if (ControllingPrim == null)
136 {
137 // THIS CANNOT HAPPEN!!
138 }
139 VDetailLog("{0},Creation", ControllingPrim.LocalID);
134 } 140 }
135 141
136 // Return 'true' if this vehicle is doing vehicle things 142 // Return 'true' if this vehicle is doing vehicle things
@@ -585,6 +591,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
585 // Friction affects are handled by this vehicle code 591 // Friction affects are handled by this vehicle code
586 m_physicsScene.PE.SetFriction(ControllingPrim.PhysBody, BSParam.VehicleFriction); 592 m_physicsScene.PE.SetFriction(ControllingPrim.PhysBody, BSParam.VehicleFriction);
587 m_physicsScene.PE.SetRestitution(ControllingPrim.PhysBody, BSParam.VehicleRestitution); 593 m_physicsScene.PE.SetRestitution(ControllingPrim.PhysBody, BSParam.VehicleRestitution);
594 // ControllingPrim.Linkset.SetPhysicalFriction(BSParam.VehicleFriction);
595 // ControllingPrim.Linkset.SetPhysicalRestitution(BSParam.VehicleRestitution);
588 596
589 // Moderate angular movement introduced by Bullet. 597 // Moderate angular movement introduced by Bullet.
590 // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle. 598 // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle.
@@ -595,17 +603,20 @@ namespace OpenSim.Region.Physics.BulletSPlugin
595 603
596 // Vehicles report collision events so we know when it's on the ground 604 // Vehicles report collision events so we know when it's on the ground
597 m_physicsScene.PE.AddToCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); 605 m_physicsScene.PE.AddToCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS);
606 // ControllingPrim.Linkset.SetPhysicalCollisionFlags(CollisionFlags.BS_VEHICLE_COLLISIONS);
598 607
599 Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(ControllingPrim.PhysShape.physShapeInfo, m_vehicleMass); 608 Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(ControllingPrim.PhysShape.physShapeInfo, m_vehicleMass);
600 ControllingPrim.Inertia = inertia * BSParam.VehicleInertiaFactor; 609 ControllingPrim.Inertia = inertia * BSParam.VehicleInertiaFactor;
601 m_physicsScene.PE.SetMassProps(ControllingPrim.PhysBody, m_vehicleMass, ControllingPrim.Inertia); 610 m_physicsScene.PE.SetMassProps(ControllingPrim.PhysBody, m_vehicleMass, ControllingPrim.Inertia);
602 m_physicsScene.PE.UpdateInertiaTensor(ControllingPrim.PhysBody); 611 m_physicsScene.PE.UpdateInertiaTensor(ControllingPrim.PhysBody);
612 // ControllingPrim.Linkset.ComputeLocalInertia(BSParam.VehicleInertiaFactor);
603 613
604 // Set the gravity for the vehicle depending on the buoyancy 614 // Set the gravity for the vehicle depending on the buoyancy
605 // TODO: what should be done if prim and vehicle buoyancy differ? 615 // TODO: what should be done if prim and vehicle buoyancy differ?
606 m_VehicleGravity = ControllingPrim.ComputeGravity(m_VehicleBuoyancy); 616 m_VehicleGravity = ControllingPrim.ComputeGravity(m_VehicleBuoyancy);
607 // The actual vehicle gravity is set to zero in Bullet so we can do all the application of same. 617 // The actual vehicle gravity is set to zero in Bullet so we can do all the application of same.
608 m_physicsScene.PE.SetGravity(ControllingPrim.PhysBody, Vector3.Zero); 618 m_physicsScene.PE.SetGravity(ControllingPrim.PhysBody, Vector3.Zero);
619 // ControllingPrim.Linkset.SetPhysicalGravity(Vector3.Zero);
609 620
610 VDetailLog("{0},BSDynamics.SetPhysicalParameters,mass={1},inert={2},vehGrav={3},aDamp={4},frict={5},rest={6},lFact={7},aFact={8}", 621 VDetailLog("{0},BSDynamics.SetPhysicalParameters,mass={1},inert={2},vehGrav={3},aDamp={4},frict={5},rest={6},lFact={7},aFact={8}",
611 ControllingPrim.LocalID, m_vehicleMass, ControllingPrim.Inertia, m_VehicleGravity, 622 ControllingPrim.LocalID, m_vehicleMass, ControllingPrim.Inertia, m_VehicleGravity,
@@ -617,6 +628,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
617 { 628 {
618 if (ControllingPrim.PhysBody.HasPhysicalBody) 629 if (ControllingPrim.PhysBody.HasPhysicalBody)
619 m_physicsScene.PE.RemoveFromCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); 630 m_physicsScene.PE.RemoveFromCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS);
631 // ControllingPrim.Linkset.RemoveFromPhysicalCollisionFlags(CollisionFlags.BS_VEHICLE_COLLISIONS);
620 } 632 }
621 } 633 }
622 634
@@ -629,6 +641,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
629 // BSActor.Release() 641 // BSActor.Release()
630 public override void Dispose() 642 public override void Dispose()
631 { 643 {
644 VDetailLog("{0},Dispose", ControllingPrim.LocalID);
632 UnregisterForSceneEvents(); 645 UnregisterForSceneEvents();
633 Type = Vehicle.TYPE_NONE; 646 Type = Vehicle.TYPE_NONE;
634 Enabled = false; 647 Enabled = false;
@@ -1001,7 +1014,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1001 else if (newVelocityLengthSq < 0.001f) 1014 else if (newVelocityLengthSq < 0.001f)
1002 VehicleVelocity = Vector3.Zero; 1015 VehicleVelocity = Vector3.Zero;
1003 1016
1004 VDetailLog("{0}, MoveLinear,done,isColl={1},newVel={2}", ControllingPrim.LocalID, ControllingPrim.IsColliding, VehicleVelocity ); 1017 VDetailLog("{0}, MoveLinear,done,isColl={1},newVel={2}", ControllingPrim.LocalID, ControllingPrim.HasSomeCollision, VehicleVelocity );
1005 1018
1006 } // end MoveLinear() 1019 } // end MoveLinear()
1007 1020
@@ -1029,8 +1042,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1029 // Add this correction to the velocity to make it faster/slower. 1042 // Add this correction to the velocity to make it faster/slower.
1030 VehicleVelocity += linearMotorVelocityW; 1043 VehicleVelocity += linearMotorVelocityW;
1031 1044
1032 VDetailLog("{0}, MoveLinear,velocity,origVelW={1},velV={2},correctV={3},correctW={4},newVelW={5},fricFact={6}", 1045 VDetailLog("{0}, MoveLinear,velocity,origVelW={1},velV={2},tgt={3},correctV={4},correctW={5},newVelW={6},fricFact={7}",
1033 ControllingPrim.LocalID, origVelW, currentVelV, linearMotorCorrectionV, 1046 ControllingPrim.LocalID, origVelW, currentVelV, m_linearMotor.TargetValue, linearMotorCorrectionV,
1034 linearMotorVelocityW, VehicleVelocity, frictionFactorV); 1047 linearMotorVelocityW, VehicleVelocity, frictionFactorV);
1035 } 1048 }
1036 1049
@@ -1062,7 +1075,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1062 Vector3 linearDeflectionW = linearDeflectionV * VehicleOrientation; 1075 Vector3 linearDeflectionW = linearDeflectionV * VehicleOrientation;
1063 1076
1064 // Optionally, if not colliding, don't effect world downward velocity. Let falling things fall. 1077 // Optionally, if not colliding, don't effect world downward velocity. Let falling things fall.
1065 if (BSParam.VehicleLinearDeflectionNotCollidingNoZ && !m_controllingPrim.IsColliding) 1078 if (BSParam.VehicleLinearDeflectionNotCollidingNoZ && !m_controllingPrim.HasSomeCollision)
1066 { 1079 {
1067 linearDeflectionW.Z = 0f; 1080 linearDeflectionW.Z = 0f;
1068 } 1081 }
@@ -1222,7 +1235,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1222 float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition); 1235 float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition);
1223 distanceAboveGround = VehiclePosition.Z - targetHeight; 1236 distanceAboveGround = VehiclePosition.Z - targetHeight;
1224 // Not colliding if the vehicle is off the ground 1237 // Not colliding if the vehicle is off the ground
1225 if (!Prim.IsColliding) 1238 if (!Prim.HasSomeCollision)
1226 { 1239 {
1227 // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale); 1240 // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale);
1228 VehicleVelocity += new Vector3(0, 0, -distanceAboveGround); 1241 VehicleVelocity += new Vector3(0, 0, -distanceAboveGround);
@@ -1233,12 +1246,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1233 // be computed with a motor. 1246 // be computed with a motor.
1234 // TODO: add interaction with banking. 1247 // TODO: add interaction with banking.
1235 VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}", 1248 VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}",
1236 Prim.LocalID, distanceAboveGround, Prim.IsColliding, ret); 1249 Prim.LocalID, distanceAboveGround, Prim.HasSomeCollision, ret);
1237 */ 1250 */
1238 1251
1239 // Another approach is to measure if we're going up. If going up and not colliding, 1252 // Another approach is to measure if we're going up. If going up and not colliding,
1240 // the vehicle is in the air. Fix that by pushing down. 1253 // the vehicle is in the air. Fix that by pushing down.
1241 if (!ControllingPrim.IsColliding && VehicleVelocity.Z > 0.1) 1254 if (!ControllingPrim.HasSomeCollision && VehicleVelocity.Z > 0.1)
1242 { 1255 {
1243 // Get rid of any of the velocity vector that is pushing us up. 1256 // Get rid of any of the velocity vector that is pushing us up.
1244 float upVelocity = VehicleVelocity.Z; 1257 float upVelocity = VehicleVelocity.Z;
@@ -1260,7 +1273,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1260 } 1273 }
1261 */ 1274 */
1262 VDetailLog("{0}, MoveLinear,limitMotorUp,collide={1},upVel={2},newVel={3}", 1275 VDetailLog("{0}, MoveLinear,limitMotorUp,collide={1},upVel={2},newVel={3}",
1263 ControllingPrim.LocalID, ControllingPrim.IsColliding, upVelocity, VehicleVelocity); 1276 ControllingPrim.LocalID, ControllingPrim.HasSomeCollision, upVelocity, VehicleVelocity);
1264 } 1277 }
1265 } 1278 }
1266 } 1279 }
@@ -1270,14 +1283,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1270 Vector3 appliedGravity = m_VehicleGravity * m_vehicleMass; 1283 Vector3 appliedGravity = m_VehicleGravity * m_vehicleMass;
1271 1284
1272 // Hack to reduce downward force if the vehicle is probably sitting on the ground 1285 // Hack to reduce downward force if the vehicle is probably sitting on the ground
1273 if (ControllingPrim.IsColliding && IsGroundVehicle) 1286 if (ControllingPrim.HasSomeCollision && IsGroundVehicle)
1274 appliedGravity *= BSParam.VehicleGroundGravityFudge; 1287 appliedGravity *= BSParam.VehicleGroundGravityFudge;
1275 1288
1276 VehicleAddForce(appliedGravity); 1289 VehicleAddForce(appliedGravity);
1277 1290
1278 VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},collid={2},fudge={3},mass={4},appliedForce={5}", 1291 VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},collid={2},fudge={3},mass={4},appliedForce={5}",
1279 ControllingPrim.LocalID, m_VehicleGravity, 1292 ControllingPrim.LocalID, m_VehicleGravity,
1280 ControllingPrim.IsColliding, BSParam.VehicleGroundGravityFudge, m_vehicleMass, appliedGravity); 1293 ControllingPrim.HasSomeCollision, BSParam.VehicleGroundGravityFudge, m_vehicleMass, appliedGravity);
1281 } 1294 }
1282 1295
1283 // ======================================================================= 1296 // =======================================================================
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
index ad8e10f..960c0b4 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
@@ -203,6 +203,33 @@ public abstract class BSLinkset
203 return ret; 203 return ret;
204 } 204 }
205 205
206 // Called after a simulation step to post a collision with this object.
207 // Return 'true' if linkset processed the collision. 'false' says the linkset didn't have
208 // anything to add for the collision and it should be passed through normal processing.
209 // Default processing for a linkset.
210 public virtual bool HandleCollide(uint collidingWith, BSPhysObject collidee,
211 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
212 {
213 bool ret = false;
214
215 // prims in the same linkset cannot collide with each other
216 BSPrimLinkable convCollidee = collidee as BSPrimLinkable;
217 if (convCollidee != null && (LinksetID == convCollidee.Linkset.LinksetID))
218 {
219 // By returning 'true', we tell the caller the collision has been 'handled' so it won't
220 // do anything about this collision and thus, effectivily, ignoring the collision.
221 ret = true;
222 }
223 else
224 {
225 // Not a collision between members of the linkset. Must be a real collision.
226 // So the linkset root can know if there is a collision anywhere in the linkset.
227 LinksetRoot.SomeCollisionSimulationStep = m_physicsScene.SimulationStep;
228 }
229
230 return ret;
231 }
232
206 // I am the root of a linkset and a new child is being added 233 // I am the root of a linkset and a new child is being added
207 // Called while LinkActivity is locked. 234 // Called while LinkActivity is locked.
208 protected abstract void AddChildToLinkset(BSPrimLinkable child); 235 protected abstract void AddChildToLinkset(BSPrimLinkable child);
@@ -251,6 +278,73 @@ public abstract class BSLinkset
251 public abstract bool RemoveDependencies(BSPrimLinkable child); 278 public abstract bool RemoveDependencies(BSPrimLinkable child);
252 279
253 // ================================================================ 280 // ================================================================
281 // Some physical setting happen to all members of the linkset
282 public virtual void SetPhysicalFriction(float friction)
283 {
284 ForEachMember((member) =>
285 {
286 if (member.PhysBody.HasPhysicalBody)
287 m_physicsScene.PE.SetFriction(member.PhysBody, friction);
288 return false; // 'false' says to continue looping
289 }
290 );
291 }
292 public virtual void SetPhysicalRestitution(float restitution)
293 {
294 ForEachMember((member) =>
295 {
296 if (member.PhysBody.HasPhysicalBody)
297 m_physicsScene.PE.SetRestitution(member.PhysBody, restitution);
298 return false; // 'false' says to continue looping
299 }
300 );
301 }
302 public virtual void SetPhysicalGravity(OMV.Vector3 gravity)
303 {
304 ForEachMember((member) =>
305 {
306 if (member.PhysBody.HasPhysicalBody)
307 m_physicsScene.PE.SetGravity(member.PhysBody, gravity);
308 return false; // 'false' says to continue looping
309 }
310 );
311 }
312 public virtual void ComputeLocalInertia(OMV.Vector3 inertiaFactor)
313 {
314 ForEachMember((member) =>
315 {
316 if (member.PhysBody.HasPhysicalBody)
317 {
318 OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(member.PhysShape.physShapeInfo, member.Mass);
319 member.Inertia = inertia * inertiaFactor;
320 m_physicsScene.PE.SetMassProps(member.PhysBody, member.Mass, member.Inertia);
321 m_physicsScene.PE.UpdateInertiaTensor(member.PhysBody);
322 }
323 return false; // 'false' says to continue looping
324 }
325 );
326 }
327 public virtual void SetPhysicalCollisionFlags(CollisionFlags collFlags)
328 {
329 ForEachMember((member) =>
330 {
331 if (member.PhysBody.HasPhysicalBody)
332 m_physicsScene.PE.SetCollisionFlags(member.PhysBody, collFlags);
333 return false; // 'false' says to continue looping
334 }
335 );
336 }
337 public virtual void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags)
338 {
339 ForEachMember((member) =>
340 {
341 if (member.PhysBody.HasPhysicalBody)
342 m_physicsScene.PE.RemoveFromCollisionFlags(member.PhysBody, collFlags);
343 return false; // 'false' says to continue looping
344 }
345 );
346 }
347 // ================================================================
254 protected virtual float ComputeLinksetMass() 348 protected virtual float ComputeLinksetMass()
255 { 349 {
256 float mass = LinksetRoot.RawMass; 350 float mass = LinksetRoot.RawMass;
@@ -311,6 +405,5 @@ public abstract class BSLinkset
311 if (m_physicsScene.PhysicsLogging.Enabled) 405 if (m_physicsScene.PhysicsLogging.Enabled)
312 m_physicsScene.DetailLog(msg, args); 406 m_physicsScene.DetailLog(msg, args);
313 } 407 }
314
315} 408}
316} 409}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
index 1d94142..33ae5a5 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
@@ -44,6 +44,42 @@ public sealed class BSLinksetCompound : BSLinkset
44 { 44 {
45 } 45 }
46 46
47 // ================================================================
48 // Changing the physical property of the linkset only needs to change the root
49 public override void SetPhysicalFriction(float friction)
50 {
51 if (LinksetRoot.PhysBody.HasPhysicalBody)
52 m_physicsScene.PE.SetFriction(LinksetRoot.PhysBody, friction);
53 }
54 public override void SetPhysicalRestitution(float restitution)
55 {
56 if (LinksetRoot.PhysBody.HasPhysicalBody)
57 m_physicsScene.PE.SetRestitution(LinksetRoot.PhysBody, restitution);
58 }
59 public override void SetPhysicalGravity(OMV.Vector3 gravity)
60 {
61 if (LinksetRoot.PhysBody.HasPhysicalBody)
62 m_physicsScene.PE.SetGravity(LinksetRoot.PhysBody, gravity);
63 }
64 public override void ComputeLocalInertia(OMV.Vector3 inertiaFactor)
65 {
66 OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(LinksetRoot.PhysShape.physShapeInfo, LinksetRoot.Mass);
67 LinksetRoot.Inertia = inertia * inertiaFactor;
68 m_physicsScene.PE.SetMassProps(LinksetRoot.PhysBody, LinksetRoot.Mass, LinksetRoot.Inertia);
69 m_physicsScene.PE.UpdateInertiaTensor(LinksetRoot.PhysBody);
70 }
71 public override void SetPhysicalCollisionFlags(CollisionFlags collFlags)
72 {
73 if (LinksetRoot.PhysBody.HasPhysicalBody)
74 m_physicsScene.PE.SetCollisionFlags(LinksetRoot.PhysBody, collFlags);
75 }
76 public override void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags)
77 {
78 if (LinksetRoot.PhysBody.HasPhysicalBody)
79 m_physicsScene.PE.RemoveFromCollisionFlags(LinksetRoot.PhysBody, collFlags);
80 }
81 // ================================================================
82
47 // When physical properties are changed the linkset needs to recalculate 83 // When physical properties are changed the linkset needs to recalculate
48 // its internal properties. 84 // its internal properties.
49 public override void Refresh(BSPrimLinkable requestor) 85 public override void Refresh(BSPrimLinkable requestor)
@@ -59,6 +95,7 @@ public sealed class BSLinksetCompound : BSLinkset
59 { 95 {
60 DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}", 96 DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}",
61 requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren)); 97 requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren));
98
62 // When rebuilding, it is possible to set properties that would normally require a rebuild. 99 // When rebuilding, it is possible to set properties that would normally require a rebuild.
63 // If already rebuilding, don't request another rebuild. 100 // If already rebuilding, don't request another rebuild.
64 // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding. 101 // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding.
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
index a06a44d..f17d698 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
@@ -48,12 +48,22 @@ public sealed class BSLinksetConstraints : BSLinkset
48 { 48 {
49 base.Refresh(requestor); 49 base.Refresh(requestor);
50 50
51 if (HasAnyChildren && IsRoot(requestor)) 51 }
52
53 private void ScheduleRebuild(BSPrimLinkable requestor)
54 {
55 DetailLog("{0},BSLinksetConstraint.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}",
56 requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren));
57
58 // When rebuilding, it is possible to set properties that would normally require a rebuild.
59 // If already rebuilding, don't request another rebuild.
60 // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding.
61 if (!Rebuilding && HasAnyChildren)
52 { 62 {
53 // Queue to happen after all the other taint processing 63 // Queue to happen after all the other taint processing
54 m_physicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate() 64 m_physicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate()
55 { 65 {
56 if (HasAnyChildren && IsRoot(requestor)) 66 if (HasAnyChildren)
57 RecomputeLinksetConstraints(); 67 RecomputeLinksetConstraints();
58 }); 68 });
59 } 69 }
@@ -67,8 +77,14 @@ public sealed class BSLinksetConstraints : BSLinkset
67 // Called at taint-time! 77 // Called at taint-time!
68 public override bool MakeDynamic(BSPrimLinkable child) 78 public override bool MakeDynamic(BSPrimLinkable child)
69 { 79 {
70 // What is done for each object in BSPrim is what we want. 80 bool ret = false;
71 return false; 81 DetailLog("{0},BSLinksetConstraints.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child));
82 if (IsRoot(child))
83 {
84 // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly.
85 ScheduleRebuild(LinksetRoot);
86 }
87 return ret;
72 } 88 }
73 89
74 // The object is going static (non-physical). Do any setup necessary for a static linkset. 90 // The object is going static (non-physical). Do any setup necessary for a static linkset.
@@ -78,8 +94,16 @@ public sealed class BSLinksetConstraints : BSLinkset
78 // Called at taint-time! 94 // Called at taint-time!
79 public override bool MakeStatic(BSPrimLinkable child) 95 public override bool MakeStatic(BSPrimLinkable child)
80 { 96 {
81 // What is done for each object in BSPrim is what we want. 97 bool ret = false;
82 return false; 98
99 DetailLog("{0},BSLinksetConstraint.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
100 child.ClearDisplacement();
101 if (IsRoot(child))
102 {
103 // Schedule a rebuild to verify that the root shape is set to the real shape.
104 ScheduleRebuild(LinksetRoot);
105 }
106 return ret;
83 } 107 }
84 108
85 // Called at taint-time!! 109 // Called at taint-time!!
@@ -105,7 +129,7 @@ public sealed class BSLinksetConstraints : BSLinkset
105 // Just undo all the constraints for this linkset. Rebuild at the end of the step. 129 // Just undo all the constraints for this linkset. Rebuild at the end of the step.
106 ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot); 130 ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
107 // Cause the constraints, et al to be rebuilt before the next simulation step. 131 // Cause the constraints, et al to be rebuilt before the next simulation step.
108 Refresh(LinksetRoot); 132 ScheduleRebuild(LinksetRoot);
109 } 133 }
110 return ret; 134 return ret;
111 } 135 }
@@ -123,7 +147,7 @@ public sealed class BSLinksetConstraints : BSLinkset
123 DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); 147 DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
124 148
125 // Cause constraints and assorted properties to be recomputed before the next simulation step. 149 // Cause constraints and assorted properties to be recomputed before the next simulation step.
126 Refresh(LinksetRoot); 150 ScheduleRebuild(LinksetRoot);
127 } 151 }
128 return; 152 return;
129 } 153 }
@@ -147,7 +171,7 @@ public sealed class BSLinksetConstraints : BSLinkset
147 PhysicallyUnlinkAChildFromRoot(rootx, childx); 171 PhysicallyUnlinkAChildFromRoot(rootx, childx);
148 }); 172 });
149 // See that the linkset parameters are recomputed at the end of the taint time. 173 // See that the linkset parameters are recomputed at the end of the taint time.
150 Refresh(LinksetRoot); 174 ScheduleRebuild(LinksetRoot);
151 } 175 }
152 else 176 else
153 { 177 {
@@ -165,6 +189,7 @@ public sealed class BSLinksetConstraints : BSLinkset
165 Refresh(rootPrim); 189 Refresh(rootPrim);
166 } 190 }
167 191
192 // Create a static constraint between the two passed objects
168 private BSConstraint BuildConstraint(BSPrimLinkable rootPrim, BSPrimLinkable childPrim) 193 private BSConstraint BuildConstraint(BSPrimLinkable rootPrim, BSPrimLinkable childPrim)
169 { 194 {
170 // Zero motion for children so they don't interpolate 195 // Zero motion for children so they don't interpolate
@@ -281,24 +306,39 @@ public sealed class BSLinksetConstraints : BSLinkset
281 DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}", 306 DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}",
282 LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, linksetMass); 307 LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, linksetMass);
283 308
284 foreach (BSPrimLinkable child in m_children) 309 try
285 { 310 {
286 // A child in the linkset physically shows the mass of the whole linkset. 311 Rebuilding = true;
287 // This allows Bullet to apply enough force on the child to move the whole linkset.
288 // (Also do the mass stuff before recomputing the constraint so mass is not zero.)
289 child.UpdatePhysicalMassProperties(linksetMass, true);
290 312
291 BSConstraint constrain; 313 // There is no reason to build all this physical stuff for a non-physical linkset.
292 if (!m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain)) 314 if (!LinksetRoot.IsPhysicallyActive)
293 { 315 {
294 // If constraint doesn't exist yet, create it. 316 DetailLog("{0},BSLinksetConstraint.RecomputeLinksetCompound,notPhysical", LinksetRoot.LocalID);
295 constrain = BuildConstraint(LinksetRoot, child); 317 return; // Note the 'finally' clause at the botton which will get executed.
296 } 318 }
297 constrain.RecomputeConstraintVariables(linksetMass);
298 319
299 // PhysicsScene.PE.DumpConstraint(PhysicsScene.World, constrain.Constraint); // DEBUG DEBUG 320 foreach (BSPrimLinkable child in m_children)
300 } 321 {
322 // A child in the linkset physically shows the mass of the whole linkset.
323 // This allows Bullet to apply enough force on the child to move the whole linkset.
324 // (Also do the mass stuff before recomputing the constraint so mass is not zero.)
325 child.UpdatePhysicalMassProperties(linksetMass, true);
326
327 BSConstraint constrain;
328 if (!m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain))
329 {
330 // If constraint doesn't exist yet, create it.
331 constrain = BuildConstraint(LinksetRoot, child);
332 }
333 constrain.RecomputeConstraintVariables(linksetMass);
301 334
335 // PhysicsScene.PE.DumpConstraint(PhysicsScene.World, constrain.Constraint); // DEBUG DEBUG
336 }
337 }
338 finally
339 {
340 Rebuilding = false;
341 }
302 } 342 }
303} 343}
304} 344}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
index dcf1e83..0bdb5f1 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
@@ -461,8 +461,9 @@ public static class BSParam
461 (s) => { return MaxAddForceMagnitude; }, 461 (s) => { return MaxAddForceMagnitude; },
462 (s,v) => { MaxAddForceMagnitude = v; MaxAddForceMagnitudeSquared = v * v; } ), 462 (s,v) => { MaxAddForceMagnitude = v; MaxAddForceMagnitudeSquared = v * v; } ),
463 // Density is passed around as 100kg/m3. This scales that to 1kg/m3. 463 // Density is passed around as 100kg/m3. This scales that to 1kg/m3.
464 // Reduce by power of 100 because Bullet doesn't seem to handle objects with large mass very well
464 new ParameterDefn<float>("DensityScaleFactor", "Conversion for simulator/viewer density (100kg/m3) to physical density (1kg/m3)", 465 new ParameterDefn<float>("DensityScaleFactor", "Conversion for simulator/viewer density (100kg/m3) to physical density (1kg/m3)",
465 0.01f ), 466 0.0001f ),
466 467
467 new ParameterDefn<float>("PID_D", "Derivitive factor for motion smoothing", 468 new ParameterDefn<float>("PID_D", "Derivitive factor for motion smoothing",
468 2200f ), 469 2200f ),
@@ -607,8 +608,9 @@ public static class BSParam
607 0.0f ), 608 0.0f ),
608 new ParameterDefn<float>("VehicleRestitution", "Bouncyness factor for vehicles (0.0 - 1.0)", 609 new ParameterDefn<float>("VehicleRestitution", "Bouncyness factor for vehicles (0.0 - 1.0)",
609 0.0f ), 610 0.0f ),
611 // Turn off fudge with DensityScaleFactor = 0.0001. Value used to be 0.2f;
610 new ParameterDefn<float>("VehicleGroundGravityFudge", "Factor to multiply gravity if a ground vehicle is probably on the ground (0.0 - 1.0)", 612 new ParameterDefn<float>("VehicleGroundGravityFudge", "Factor to multiply gravity if a ground vehicle is probably on the ground (0.0 - 1.0)",
611 0.2f ), 613 1.0f ),
612 new ParameterDefn<float>("VehicleAngularBankingTimescaleFudge", "Factor to multiple angular banking timescale. Tune to increase realism.", 614 new ParameterDefn<float>("VehicleAngularBankingTimescaleFudge", "Factor to multiple angular banking timescale. Tune to increase realism.",
613 60.0f ), 615 60.0f ),
614 new ParameterDefn<bool>("VehicleEnableLinearDeflection", "Turn on/off vehicle linear deflection effect", 616 new ParameterDefn<bool>("VehicleEnableLinearDeflection", "Turn on/off vehicle linear deflection effect",
@@ -701,7 +703,7 @@ public static class BSParam
701 new ParameterDefn<float>("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)", 703 new ParameterDefn<float>("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)",
702 (float)BSLinkset.LinksetImplementation.Compound ), 704 (float)BSLinkset.LinksetImplementation.Compound ),
703 new ParameterDefn<bool>("LinksetOffsetCenterOfMass", "If 'true', compute linkset center-of-mass and offset linkset position to account for same", 705 new ParameterDefn<bool>("LinksetOffsetCenterOfMass", "If 'true', compute linkset center-of-mass and offset linkset position to account for same",
704 false ), 706 true ),
705 new ParameterDefn<bool>("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.", 707 new ParameterDefn<bool>("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.",
706 false ), 708 false ),
707 new ParameterDefn<bool>("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints", 709 new ParameterDefn<bool>("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints",
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
index fc4545f..d34b797 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
@@ -353,6 +353,16 @@ public abstract class BSPhysObject : PhysicsActor
353 CollidingStep = BSScene.NotASimulationStep; 353 CollidingStep = BSScene.NotASimulationStep;
354 } 354 }
355 } 355 }
356 // Complex objects (like linksets) need to know if there is a collision on any part of
357 // their shape. 'IsColliding' has an existing definition of reporting a collision on
358 // only this specific prim or component of linksets.
359 // 'HasSomeCollision' is defined as reporting if there is a collision on any part of
360 // the complex body that this prim is the root of.
361 public virtual bool HasSomeCollision
362 {
363 get { return IsColliding; }
364 set { IsColliding = value; }
365 }
356 public override bool CollidingGround { 366 public override bool CollidingGround {
357 get { return (CollidingGroundStep == PhysScene.SimulationStep); } 367 get { return (CollidingGroundStep == PhysScene.SimulationStep); }
358 set 368 set
@@ -386,6 +396,7 @@ public abstract class BSPhysObject : PhysicsActor
386 // Return 'true' if a collision was processed and should be sent up. 396 // Return 'true' if a collision was processed and should be sent up.
387 // Return 'false' if this object is not enabled/subscribed/appropriate for or has already seen this collision. 397 // Return 'false' if this object is not enabled/subscribed/appropriate for or has already seen this collision.
388 // Called at taint time from within the Step() function 398 // Called at taint time from within the Step() function
399 public delegate bool CollideCall(uint collidingWith, BSPhysObject collidee, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth);
389 public virtual bool Collide(uint collidingWith, BSPhysObject collidee, 400 public virtual bool Collide(uint collidingWith, BSPhysObject collidee,
390 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) 401 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
391 { 402 {
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index d43448e..e92a1d2 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -96,7 +96,7 @@ public class BSPrim : BSPhysObject
96 _isVolumeDetect = false; 96 _isVolumeDetect = false;
97 97
98 // Add a dynamic vehicle to our set of actors that can move this prim. 98 // Add a dynamic vehicle to our set of actors that can move this prim.
99 PhysicalActors.Add(VehicleActorName, new BSDynamics(PhysScene, this, VehicleActorName)); 99 // PhysicalActors.Add(VehicleActorName, new BSDynamics(PhysScene, this, VehicleActorName));
100 100
101 _mass = CalculateMass(); 101 _mass = CalculateMass();
102 102
@@ -440,8 +440,8 @@ public class BSPrim : BSPhysObject
440 Gravity = ComputeGravity(Buoyancy); 440 Gravity = ComputeGravity(Buoyancy);
441 PhysScene.PE.SetGravity(PhysBody, Gravity); 441 PhysScene.PE.SetGravity(PhysBody, Gravity);
442 442
443 OMV.Vector3 currentScale = PhysScene.PE.GetLocalScaling(PhysShape.physShapeInfo); // DEBUG DEBUG 443 // OMV.Vector3 currentScale = PhysScene.PE.GetLocalScaling(PhysShape.physShapeInfo); // DEBUG DEBUG
444 DetailLog("{0},BSPrim.UpdateMassProperties,currentScale{1},shape={2}", LocalID, currentScale, PhysShape.physShapeInfo); // DEBUG DEBUG 444 // DetailLog("{0},BSPrim.UpdateMassProperties,currentScale{1},shape={2}", LocalID, currentScale, PhysShape.physShapeInfo); // DEBUG DEBUG
445 445
446 Inertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass); 446 Inertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass);
447 PhysScene.PE.SetMassProps(PhysBody, physMass, Inertia); 447 PhysScene.PE.SetMassProps(PhysBody, physMass, Inertia);
@@ -495,9 +495,9 @@ public class BSPrim : BSPhysObject
495 } 495 }
496 } 496 }
497 497
498 // Find and return a handle to the current vehicle actor. 498 // Find and return a handle to the current vehicle actor.
499 // Return 'null' if there is no vehicle actor. 499 // Return 'null' if there is no vehicle actor.
500 public BSDynamics GetVehicleActor() 500 public BSDynamics GetVehicleActor(bool createIfNone)
501 { 501 {
502 BSDynamics ret = null; 502 BSDynamics ret = null;
503 BSActor actor; 503 BSActor actor;
@@ -505,12 +505,21 @@ public class BSPrim : BSPhysObject
505 { 505 {
506 ret = actor as BSDynamics; 506 ret = actor as BSDynamics;
507 } 507 }
508 else
509 {
510 if (createIfNone)
511 {
512 ret = new BSDynamics(PhysScene, this, VehicleActorName);
513 PhysicalActors.Add(ret.ActorName, ret);
514 }
515 }
508 return ret; 516 return ret;
509 } 517 }
518
510 public override int VehicleType { 519 public override int VehicleType {
511 get { 520 get {
512 int ret = (int)Vehicle.TYPE_NONE; 521 int ret = (int)Vehicle.TYPE_NONE;
513 BSDynamics vehicleActor = GetVehicleActor(); 522 BSDynamics vehicleActor = GetVehicleActor(false /* createIfNone */);
514 if (vehicleActor != null) 523 if (vehicleActor != null)
515 ret = (int)vehicleActor.Type; 524 ret = (int)vehicleActor.Type;
516 return ret; 525 return ret;
@@ -524,11 +533,24 @@ public class BSPrim : BSPhysObject
524 // change all the parameters. Like a plane changing to CAR when on the 533 // change all the parameters. Like a plane changing to CAR when on the
525 // ground. In this case, don't want to zero motion. 534 // ground. In this case, don't want to zero motion.
526 // ZeroMotion(true /* inTaintTime */); 535 // ZeroMotion(true /* inTaintTime */);
527 BSDynamics vehicleActor = GetVehicleActor(); 536 if (type == Vehicle.TYPE_NONE)
528 if (vehicleActor != null)
529 { 537 {
530 vehicleActor.ProcessTypeChange(type); 538 // Vehicle type is 'none' so get rid of any actor that may have been allocated.
531 ActivateIfPhysical(false); 539 BSDynamics vehicleActor = GetVehicleActor(false /* createIfNone */);
540 if (vehicleActor != null)
541 {
542 PhysicalActors.RemoveAndRelease(vehicleActor.ActorName);
543 }
544 }
545 else
546 {
547 // Vehicle type is not 'none' so create an actor and set it running.
548 BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
549 if (vehicleActor != null)
550 {
551 vehicleActor.ProcessTypeChange(type);
552 ActivateIfPhysical(false);
553 }
532 } 554 }
533 }); 555 });
534 } 556 }
@@ -537,7 +559,7 @@ public class BSPrim : BSPhysObject
537 { 559 {
538 PhysScene.TaintedObject("BSPrim.VehicleFloatParam", delegate() 560 PhysScene.TaintedObject("BSPrim.VehicleFloatParam", delegate()
539 { 561 {
540 BSDynamics vehicleActor = GetVehicleActor(); 562 BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
541 if (vehicleActor != null) 563 if (vehicleActor != null)
542 { 564 {
543 vehicleActor.ProcessFloatVehicleParam((Vehicle)param, value); 565 vehicleActor.ProcessFloatVehicleParam((Vehicle)param, value);
@@ -549,7 +571,7 @@ public class BSPrim : BSPhysObject
549 { 571 {
550 PhysScene.TaintedObject("BSPrim.VehicleVectorParam", delegate() 572 PhysScene.TaintedObject("BSPrim.VehicleVectorParam", delegate()
551 { 573 {
552 BSDynamics vehicleActor = GetVehicleActor(); 574 BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
553 if (vehicleActor != null) 575 if (vehicleActor != null)
554 { 576 {
555 vehicleActor.ProcessVectorVehicleParam((Vehicle)param, value); 577 vehicleActor.ProcessVectorVehicleParam((Vehicle)param, value);
@@ -561,7 +583,7 @@ public class BSPrim : BSPhysObject
561 { 583 {
562 PhysScene.TaintedObject("BSPrim.VehicleRotationParam", delegate() 584 PhysScene.TaintedObject("BSPrim.VehicleRotationParam", delegate()
563 { 585 {
564 BSDynamics vehicleActor = GetVehicleActor(); 586 BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
565 if (vehicleActor != null) 587 if (vehicleActor != null)
566 { 588 {
567 vehicleActor.ProcessRotationVehicleParam((Vehicle)param, rotation); 589 vehicleActor.ProcessRotationVehicleParam((Vehicle)param, rotation);
@@ -573,7 +595,7 @@ public class BSPrim : BSPhysObject
573 { 595 {
574 PhysScene.TaintedObject("BSPrim.VehicleFlags", delegate() 596 PhysScene.TaintedObject("BSPrim.VehicleFlags", delegate()
575 { 597 {
576 BSDynamics vehicleActor = GetVehicleActor(); 598 BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
577 if (vehicleActor != null) 599 if (vehicleActor != null)
578 { 600 {
579 vehicleActor.ProcessVehicleFlags(param, remove); 601 vehicleActor.ProcessVehicleFlags(param, remove);
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs
index 1fbcfcc..2f392da 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs
@@ -200,20 +200,38 @@ public class BSPrimLinkable : BSPrimDisplaced
200 } 200 }
201 201
202 // Called after a simulation step to post a collision with this object. 202 // Called after a simulation step to post a collision with this object.
203 // This returns 'true' if the collision has been queued and the SendCollisions call must
204 // be made at the end of the simulation step.
203 public override bool Collide(uint collidingWith, BSPhysObject collidee, 205 public override bool Collide(uint collidingWith, BSPhysObject collidee,
204 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) 206 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
205 { 207 {
206 // prims in the same linkset cannot collide with each other 208 bool ret = false;
207 BSPrimLinkable convCollidee = collidee as BSPrimLinkable; 209 // Ask the linkset if it wants to handle the collision
208 if (convCollidee != null && (this.Linkset.LinksetID == convCollidee.Linkset.LinksetID)) 210 if (!Linkset.HandleCollide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth))
209 { 211 {
210 return false; 212 // The linkset didn't handle it so pass the collision through normal processing
213 ret = base.Collide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth);
211 } 214 }
215 return ret;
216 }
212 217
213 // TODO: handle collisions of other objects with with children of linkset. 218 // A linkset reports any collision on any part of the linkset.
214 // This is a problem for LinksetCompound since the children are packed into the root. 219 public long SomeCollisionSimulationStep = 0;
220 public override bool HasSomeCollision
221 {
222 get
223 {
224 return (SomeCollisionSimulationStep == PhysScene.SimulationStep) || base.IsColliding;
225 }
226 set
227 {
228 if (value)
229 SomeCollisionSimulationStep = PhysScene.SimulationStep;
230 else
231 SomeCollisionSimulationStep = 0;
215 232
216 return base.Collide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth); 233 base.HasSomeCollision = value;
234 }
217 } 235 }
218} 236}
219} 237}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs b/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs
index 48d3742..48e74eb 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs
@@ -116,7 +116,7 @@ public class BasicVehicles : OpenSimTestCase
116 // Instead the appropriate values are set and calls are made just the parts of the 116 // Instead the appropriate values are set and calls are made just the parts of the
117 // controller we want to exercise. Stepping the physics engine then applies 117 // controller we want to exercise. Stepping the physics engine then applies
118 // the actions of that one feature. 118 // the actions of that one feature.
119 BSDynamics vehicleActor = TestVehicle.GetVehicleActor(); 119 BSDynamics vehicleActor = TestVehicle.GetVehicleActor(true /* createIfNone */);
120 if (vehicleActor != null) 120 if (vehicleActor != null)
121 { 121 {
122 vehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_EFFICIENCY, efficiency); 122 vehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_EFFICIENCY, efficiency);
diff --git a/OpenSim/Region/Physics/Manager/PhysicsActor.cs b/OpenSim/Region/Physics/Manager/PhysicsActor.cs
index 7cd364b..739e984 100644
--- a/OpenSim/Region/Physics/Manager/PhysicsActor.cs
+++ b/OpenSim/Region/Physics/Manager/PhysicsActor.cs
@@ -415,6 +415,11 @@ namespace OpenSim.Region.Physics.Manager
415 public virtual PhysicsActor ParentActor { get { return this; } } 415 public virtual PhysicsActor ParentActor { get { return this; } }
416 416
417 417
418 // Extendable interface for new, physics engine specific operations
419 public virtual object Extension(string pFunct, params object[] pParams)
420 {
421 throw new NotImplementedException();
422 }
418 } 423 }
419 424
420 public class NullPhysicsActor : PhysicsActor 425 public class NullPhysicsActor : PhysicsActor
diff --git a/OpenSim/Region/Physics/Manager/PhysicsScene.cs b/OpenSim/Region/Physics/Manager/PhysicsScene.cs
index 20a70b4..52f2809 100644
--- a/OpenSim/Region/Physics/Manager/PhysicsScene.cs
+++ b/OpenSim/Region/Physics/Manager/PhysicsScene.cs
@@ -25,10 +25,13 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System;
28using System.Collections.Generic; 29using System.Collections.Generic;
29using System.Reflection; 30using System.Reflection;
31
30using log4net; 32using log4net;
31using Nini.Config; 33using Nini.Config;
34
32using OpenSim.Framework; 35using OpenSim.Framework;
33using OpenMetaverse; 36using OpenMetaverse;
34 37
@@ -386,5 +389,11 @@ namespace OpenSim.Region.Physics.Manager
386 { 389 {
387 return 0; 390 return 0;
388 } 391 }
392
393 // Extendable interface for new, physics engine specific operations
394 public virtual object Extension(string pFunct, params object[] pParams)
395 {
396 throw new NotImplementedException();
397 }
389 } 398 }
390} 399}
diff --git a/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs b/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs
index 2567c8f..0601ece 100644
--- a/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs
+++ b/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs
@@ -493,6 +493,22 @@ namespace OpenSim.Services.HypergridService
493 return null; 493 return null;
494 } 494 }
495 495
496 private XInventoryFolder GetCurrentOutfitXFolder(UUID userID)
497 {
498 XInventoryFolder root = GetRootXFolder(userID);
499 if (root == null)
500 return null;
501
502 XInventoryFolder[] folders = m_Database.GetFolders(
503 new string[] { "agentID", "type", "parentFolderID" },
504 new string[] { userID.ToString(), ((int)AssetType.CurrentOutfitFolder).ToString(), root.folderID.ToString() });
505
506 if (folders.Length == 0)
507 return null;
508
509 return folders[0];
510 }
511
496 private XInventoryFolder GetSuitcaseXFolder(UUID principalID) 512 private XInventoryFolder GetSuitcaseXFolder(UUID principalID)
497 { 513 {
498 // Warp! Root folder for travelers 514 // Warp! Root folder for travelers
@@ -531,6 +547,7 @@ namespace OpenSim.Services.HypergridService
531 if (m_SuitcaseTrees.TryGetValue(principalID, out t)) 547 if (m_SuitcaseTrees.TryGetValue(principalID, out t))
532 return t; 548 return t;
533 549
550 // Get the tree of the suitcase folder
534 t = GetFolderTreeRecursive(folder); 551 t = GetFolderTreeRecursive(folder);
535 m_SuitcaseTrees.AddOrUpdate(principalID, t, 5*60); // 5minutes 552 m_SuitcaseTrees.AddOrUpdate(principalID, t, 5*60); // 5minutes
536 return t; 553 return t;
@@ -577,6 +594,9 @@ namespace OpenSim.Services.HypergridService
577 List<XInventoryFolder> tree = new List<XInventoryFolder>(); 594 List<XInventoryFolder> tree = new List<XInventoryFolder>();
578 tree.Add(suitcase); // Warp! the tree is the real root folder plus the children of the suitcase folder 595 tree.Add(suitcase); // Warp! the tree is the real root folder plus the children of the suitcase folder
579 tree.AddRange(GetFolderTree(principalID, suitcase.folderID)); 596 tree.AddRange(GetFolderTree(principalID, suitcase.folderID));
597 // Also add the Current Outfit folder to the list of available folders
598 tree.Add(GetCurrentOutfitXFolder(principalID));
599
580 XInventoryFolder f = tree.Find(delegate(XInventoryFolder fl) 600 XInventoryFolder f = tree.Find(delegate(XInventoryFolder fl)
581 { 601 {
582 if (fl.folderID == folderID) return true; 602 if (fl.folderID == folderID) return true;
diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs
index 6528d9a..df8cf27 100644
--- a/OpenSim/Tests/Common/Mock/TestClient.cs
+++ b/OpenSim/Tests/Common/Mock/TestClient.cs
@@ -107,6 +107,7 @@ namespace OpenSim.Tests.Common.Mock
107 public event Action<IClientAPI, bool> OnCompleteMovementToRegion; 107 public event Action<IClientAPI, bool> OnCompleteMovementToRegion;
108 public event UpdateAgent OnPreAgentUpdate; 108 public event UpdateAgent OnPreAgentUpdate;
109 public event UpdateAgent OnAgentUpdate; 109 public event UpdateAgent OnAgentUpdate;
110 public event UpdateAgent OnAgentCameraUpdate;
110 public event AgentRequestSit OnAgentRequestSit; 111 public event AgentRequestSit OnAgentRequestSit;
111 public event AgentSit OnAgentSit; 112 public event AgentSit OnAgentSit;
112 public event AvatarPickerRequest OnAvatarPickerRequest; 113 public event AvatarPickerRequest OnAvatarPickerRequest;
@@ -1266,7 +1267,7 @@ namespace OpenSim.Tests.Common.Mock
1266 { 1267 {
1267 } 1268 }
1268 1269
1269 public void StopFlying(ISceneEntity presence) 1270 public void SendAgentTerseUpdate(ISceneEntity presence)
1270 { 1271 {
1271 } 1272 }
1272 1273