From d44b50ee462978b4899c0b142f6ecbfb553f06b6 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Thu, 15 Oct 2009 15:25:02 -0700 Subject: * Removed some of the redundant broadcast functions in Scene and SceneGraph so it is clear who/what the broadcast is going to each time * Removed two redundant parameters from SceneObjectPart * Changed some code in terse update sending that was meant to work with references to work with value types (since Vector3 and Quaternion are structs) * Committing a preview of a new method for sending object updates efficiently (all commented out for now) --- .../Region/ClientStack/LindenUDP/LLClientView.cs | 229 ++++++++++++++++++++- .../Region/CoreModules/Avatar/Chat/ChatModule.cs | 11 +- .../World/Estate/EstateManagementModule.cs | 2 +- .../CoreModules/World/Land/LandManagementModule.cs | 6 +- OpenSim/Region/Framework/Scenes/Scene.cs | 31 +-- OpenSim/Region/Framework/Scenes/SceneGraph.cs | 17 -- OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 12 +- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 11 +- .../Scripting/Minimodule/MRMModule.cs | 4 +- 9 files changed, 255 insertions(+), 68 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 8487adc..82a2cdd 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -51,6 +51,44 @@ using Nini.Config; namespace OpenSim.Region.ClientStack.LindenUDP { + #region Enums + + /// + /// Specifies the fields that have been changed when sending a prim or + /// avatar update + /// + [Flags] + public enum PrimUpdateFlags : uint + { + None = 0, + AttachmentPoint = 1 << 0, + Material = 1 << 1, + ClickAction = 1 << 2, + Scale = 1 << 3, + ParentID = 1 << 4, + PrimFlags = 1 << 5, + PrimData = 1 << 6, + MediaURL = 1 << 7, + ScratchPad = 1 << 8, + Textures = 1 << 9, + TextureAnim = 1 << 10, + NameValue = 1 << 11, + Position = 1 << 12, + Rotation = 1 << 13, + Velocity = 1 << 14, + Acceleration = 1 << 15, + AngularVelocity = 1 << 16, + CollisionPlane = 1 << 17, + Text = 1 << 18, + Particles = 1 << 19, + ExtraData = 1 << 20, + Sound = 1 << 21, + Joint = 1 << 22, + FullUpdate = UInt32.MaxValue + } + + #endregion Enums + public delegate bool PacketMethod(IClientAPI simClient, Packet packet); /// @@ -3159,6 +3197,195 @@ namespace OpenSim.Region.ClientStack.LindenUDP #endregion + #region Prim/Avatar Updates + + /*void SendObjectUpdate(SceneObjectPart obj, PrimFlags creatorFlags, PrimUpdateFlags updateFlags) + { + bool canUseCompressed, canUseImproved; + UpdateFlagsToPacketType(creatorFlags, updateFlags, out canUseCompressed, out canUseImproved); + + if (!canUseImproved && !canUseCompressed) + SendFullObjectUpdate(obj, creatorFlags, updateFlags); + else if (!canUseImproved) + SendObjectUpdateCompressed(obj, creatorFlags, updateFlags); + else + SendImprovedTerseObjectUpdate(obj, creatorFlags, updateFlags); + } + + void SendFullObjectUpdate(SceneObjectPart obj, PrimFlags creatorFlags, PrimUpdateFlags updateFlags) + { + IClientAPI owner; + if (m_scene.ClientManager.TryGetValue(obj.OwnerID, out owner) && owner is LLClientView) + { + LLClientView llOwner = (LLClientView)owner; + + // Send an update out to the owner + ObjectUpdatePacket updateToOwner = new ObjectUpdatePacket(); + updateToOwner.RegionData.RegionHandle = obj.RegionHandle; + //updateToOwner.RegionData.TimeDilation = (ushort)(timeDilation * (float)UInt16.MaxValue); + updateToOwner.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1]; + updateToOwner.ObjectData[0] = BuildUpdateBlock(obj, obj.Flags | creatorFlags | PrimFlags.ObjectYouOwner, 0); + + m_udpServer.SendPacket(llOwner.UDPClient, updateToOwner, ThrottleOutPacketType.State, true); + } + + // Send an update out to everyone else + ObjectUpdatePacket updateToOthers = new ObjectUpdatePacket(); + updateToOthers.RegionData.RegionHandle = obj.RegionHandle; + //updateToOthers.RegionData.TimeDilation = (ushort)(timeDilation * (float)UInt16.MaxValue); + updateToOthers.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1]; + updateToOthers.ObjectData[0] = BuildUpdateBlock(obj, obj.Flags, 0); + + m_scene.ClientManager.ForEach( + delegate(IClientAPI client) + { + if (client.AgentId != obj.OwnerID && client is LLClientView) + { + LLClientView llClient = (LLClientView)client; + m_udpServer.SendPacket(llClient.UDPClient, updateToOthers, ThrottleOutPacketType.State, true); + } + } + ); + } + + void SendObjectUpdateCompressed(SceneObjectPart obj, PrimFlags creatorFlags, PrimUpdateFlags updateFlags) + { + } + + void SendImprovedTerseObjectUpdate(SceneObjectPart obj, PrimFlags creatorFlags, PrimUpdateFlags updateFlags) + { + } + + void UpdateFlagsToPacketType(PrimFlags creatorFlags, PrimUpdateFlags updateFlags, out bool canUseCompressed, out bool canUseImproved) + { + canUseCompressed = true; + canUseImproved = true; + + if ((updateFlags & PrimUpdateFlags.FullUpdate) == PrimUpdateFlags.FullUpdate || creatorFlags != PrimFlags.None) + { + canUseCompressed = false; + canUseImproved = false; + } + else + { + if ((updateFlags & PrimUpdateFlags.Velocity) != 0 || + (updateFlags & PrimUpdateFlags.Acceleration) != 0 || + (updateFlags & PrimUpdateFlags.CollisionPlane) != 0 || + (updateFlags & PrimUpdateFlags.Joint) != 0) + { + canUseCompressed = false; + } + + if ((updateFlags & PrimUpdateFlags.PrimFlags) != 0 || + (updateFlags & PrimUpdateFlags.ParentID) != 0 || + (updateFlags & PrimUpdateFlags.Scale) != 0 || + (updateFlags & PrimUpdateFlags.PrimData) != 0 || + (updateFlags & PrimUpdateFlags.Text) != 0 || + (updateFlags & PrimUpdateFlags.NameValue) != 0 || + (updateFlags & PrimUpdateFlags.ExtraData) != 0 || + (updateFlags & PrimUpdateFlags.TextureAnim) != 0 || + (updateFlags & PrimUpdateFlags.Sound) != 0 || + (updateFlags & PrimUpdateFlags.Particles) != 0 || + (updateFlags & PrimUpdateFlags.Material) != 0 || + (updateFlags & PrimUpdateFlags.ClickAction) != 0 || + (updateFlags & PrimUpdateFlags.MediaURL) != 0 || + (updateFlags & PrimUpdateFlags.Joint) != 0) + { + canUseImproved = false; + } + } + } + + static ObjectUpdatePacket.ObjectDataBlock BuildUpdateBlockFromPrim(SceneObjectPart prim, UUID assetID, PrimFlags flags, uint crc) + { + byte[] objectData = new byte[60]; + prim.OffsetPosition.ToBytes(objectData, 0); + prim.Velocity.ToBytes(objectData, 12); + prim.Acceleration.ToBytes(objectData, 24); + prim.RotationOffset.ToBytes(objectData, 36); + prim.AngularVelocity.ToBytes(objectData, 48); + + ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); + update.ClickAction = (byte)prim.ClickAction; + update.CRC = crc; + update.ExtraParams = prim.Shape.ExtraParams ?? Utils.EmptyBytes; + update.Flags = (byte)flags; + update.FullID = prim.UUID; + update.ID = prim.LocalId; + //update.JointAxisOrAnchor = Vector3.Zero; // These are deprecated + //update.JointPivot = Vector3.Zero; + //update.JointType = 0; + update.Material = prim.Material; + update.MediaURL = Utils.EmptyBytes; // FIXME: Support this in OpenSim + if (prim.IsAttachment) + update.NameValue = Util.StringToBytes256("AttachItemID STRING RW SV " + assetID); + else + update.NameValue = Utils.EmptyBytes; + update.ObjectData = objectData; + update.ParentID = prim.ParentID; + update.PathBegin = prim.Shape.PathBegin; + update.PathCurve = prim.Shape.PathCurve; + update.PathEnd = prim.Shape.PathEnd; + update.PathRadiusOffset = prim.Shape.PathRadiusOffset; + update.PathRevolutions = prim.Shape.PathRevolutions; + update.PathScaleX = prim.Shape.PathScaleX; + update.PathScaleY = prim.Shape.PathScaleY; + update.PathShearX = prim.Shape.PathShearX; + update.PathShearY = prim.Shape.PathShearY; + update.PathSkew = prim.Shape.PathSkew; + update.PathTaperX = prim.Shape.PathTaperX; + update.PathTaperY = prim.Shape.PathTaperY; + update.PathTwist = prim.Shape.PathTwist; + update.PathTwistBegin = prim.Shape.PathTwistBegin; + update.PCode = prim.Shape.PCode; + update.ProfileBegin = prim.Shape.ProfileBegin; + update.ProfileCurve = prim.Shape.ProfileCurve; + update.ProfileEnd = prim.Shape.ProfileEnd; + update.ProfileHollow = prim.Shape.ProfileHollow; + update.PSBlock = prim.ParticleSystem ?? Utils.EmptyBytes; + update.TextColor = new Color4(prim.Color).GetBytes(true); + update.TextureAnim = prim.TextureAnimation ?? Utils.EmptyBytes; + update.TextureEntry = prim.Shape.TextureEntry ?? Utils.EmptyBytes; + update.Scale = prim.Scale; + update.State = prim.Shape.State; + update.Text = Util.StringToBytes256(prim.Text); + update.UpdateFlags = (uint)flags; + + if (prim.Sound != UUID.Zero) + { + update.Sound = prim.Sound; + update.OwnerID = prim.OwnerID; + update.Gain = (float)prim.SoundGain; + update.Radius = (float)prim.SoundRadius; + } + + switch ((PCode)prim.Shape.PCode) + { + case PCode.Grass: + case PCode.Tree: + case PCode.NewTree: + update.Data = new byte[] { prim.Shape.State }; + break; + default: + // TODO: Support ScratchPad + //if (prim.ScratchPad != null) + //{ + // update.Data = new byte[prim.ScratchPad.Length]; + // Buffer.BlockCopy(prim.ScratchPad, 0, update.Data, 0, update.Data.Length); + //} + //else + //{ + // update.Data = Utils.EmptyBytes; + //} + update.Data = Utils.EmptyBytes; + break; + } + + return update; + }*/ + + #endregion Prim/Avatar Updates + #region Avatar Packet/data sending Methods /// @@ -3365,7 +3592,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP return; if (primShape.PCode == 9 && primShape.State != 0 && parentID == 0) return; - + if (rotation.X == rotation.Y && rotation.Y == rotation.Z && rotation.Z == rotation.W && rotation.W == 0) rotation = Quaternion.Identity; diff --git a/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs b/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs index 66a9b5a..cd59bdb 100644 --- a/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs @@ -224,11 +224,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat foreach (Scene s in m_scenes) { - s.ForEachScenePresence(delegate(ScenePresence presence) - { - TrySendChatMessage(presence, fromPos, regionPos, fromID, fromName, - c.Type, message, sourceType); - }); + s.ForEachScenePresence( + delegate(ScenePresence presence) + { + TrySendChatMessage(presence, fromPos, regionPos, fromID, fromName, c.Type, message, sourceType); + } + ); } } diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs index 4896edf..3bb162e 100644 --- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs @@ -756,7 +756,7 @@ namespace OpenSim.Region.CoreModules.World.Estate public void sendRegionHandshakeToAll() { - m_scene.Broadcast(sendRegionHandshake); + m_scene.ForEachClient(sendRegionHandshake); } public void handleEstateChangeInfo(IClientAPI remoteClient, UUID invoice, UUID senderID, UInt32 parms1, UInt32 parms2) diff --git a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs index d2b5cb1..332d3ce 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs @@ -1061,7 +1061,7 @@ namespace OpenSim.Region.CoreModules.World.Land { land.LandData.OwnerID = ownerID; - m_scene.Broadcast(SendParcelOverlay); + m_scene.ForEachClient(SendParcelOverlay); land.SendLandUpdateToClient(remote_client); } } @@ -1083,7 +1083,7 @@ namespace OpenSim.Region.CoreModules.World.Land land.LandData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner; else land.LandData.OwnerID = m_scene.RegionInfo.MasterAvatarAssignedUUID; - m_scene.Broadcast(SendParcelOverlay); + m_scene.ForEachClient(SendParcelOverlay); land.SendLandUpdateToClient(remote_client); } } @@ -1107,7 +1107,7 @@ namespace OpenSim.Region.CoreModules.World.Land land.LandData.OwnerID = m_scene.RegionInfo.MasterAvatarAssignedUUID; land.LandData.ClaimDate = Util.UnixTimeSinceEpoch(); land.LandData.IsGroupOwned = false; - m_scene.Broadcast(SendParcelOverlay); + m_scene.ForEachClient(SendParcelOverlay); land.SendLandUpdateToClient(remote_client); } } diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index d3d397d..d13d4fb 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -1194,15 +1194,6 @@ namespace OpenSim.Region.Framework.Scenes } /// - /// Perform delegate action on all clients subscribing to updates from this region. - /// - /// - public void Broadcast(Action whatToDo) - { - ForEachScenePresence(delegate(ScenePresence presence) { whatToDo(presence.ControllingClient); }); - } - - /// /// Backup the scene. This acts as the main method of the backup thread. /// /// @@ -3048,17 +3039,13 @@ namespace OpenSim.Region.Framework.Scenes } m_eventManager.TriggerOnRemovePresence(agentID); - Broadcast(delegate(IClientAPI client) - { - try - { - client.SendKillObject(avatar.RegionHandle, avatar.LocalId); - } - catch (NullReferenceException) - { - //We can safely ignore null reference exceptions. It means the avatar are dead and cleaned up anyway. - } - }); + ForEachClient( + delegate(IClientAPI client) + { + //We can safely ignore null reference exceptions. It means the avatar is dead and cleaned up anyway + try { client.SendKillObject(avatar.RegionHandle, avatar.LocalId); } + catch (NullReferenceException) { } + }); ForEachScenePresence( delegate(ScenePresence presence) { presence.CoarseLocationChange(); }); @@ -3143,7 +3130,7 @@ namespace OpenSim.Region.Framework.Scenes return; } } - Broadcast(delegate(IClientAPI client) { client.SendKillObject(m_regionHandle, localID); }); + ForEachClient(delegate(IClientAPI client) { client.SendKillObject(m_regionHandle, localID); }); } #endregion @@ -4211,7 +4198,7 @@ namespace OpenSim.Region.Framework.Scenes public void ForEachClient(Action action) { - m_sceneGraph.ForEachClient(action); + ClientManager.ForEach(action); } public void ForEachSOG(Action action) diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index 9cd2247..04397ad 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -1107,23 +1107,6 @@ namespace OpenSim.Region.Framework.Scenes return UUID.Zero; } - protected internal void ForEachClient(Action action) - { - List splist = GetScenePresences(); - foreach (ScenePresence presence in splist) - { - try - { - action(presence.ControllingClient); - } - catch (Exception e) - { - // Catch it and move on. This includes situations where splist has inconsistent info - m_log.WarnFormat("[SCENE]: Problem processing action in ForEachClient: ", e.Message); - } - } - } - protected internal void ForEachSOG(Action action) { List objlist = new List(SceneObjectGroupsByFullID.Values); diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 801a7db..377cb6e 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -853,16 +853,6 @@ if (m_shape != null) { return m_offsetPosition + m_groupPosition; } } - public UUID ObjectCreator - { - get { return _creatorID; } - } - - public UUID ObjectOwner - { - get { return _ownerID; } - } - public SceneObjectGroup ParentGroup { get { return m_parentGroup; } @@ -1440,7 +1430,7 @@ if (m_shape != null) { // Move afterwards ResetIDs as it clears the localID dupe.LocalId = localID; // This may be wrong... it might have to be applied in SceneObjectGroup to the object that's being duplicated. - dupe._lastOwnerID = ObjectOwner; + dupe._lastOwnerID = OwnerID; byte[] extraP = new byte[Shape.ExtraParams.Length]; Array.Copy(Shape.ExtraParams, extraP, extraP.Length); diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 2a06f9e..387db44 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -2455,11 +2455,10 @@ namespace OpenSim.Region.Framework.Scenes m_perfMonMS = Environment.TickCount; Vector3 pos = m_pos; - Vector3 vel = Velocity; - Quaternion rot = m_bodyRot; pos.Z -= m_appearance.HipOffset; - remoteClient.SendAvatarTerseUpdate(m_regionHandle, (ushort)(m_scene.TimeDilation * ushort.MaxValue), LocalId, new Vector3(pos.X, pos.Y, pos.Z), - new Vector3(vel.X, vel.Y, vel.Z), rot, m_uuid); + + remoteClient.SendAvatarTerseUpdate(m_regionHandle, (ushort)(m_scene.TimeDilation * ushort.MaxValue), + LocalId, pos, Velocity, m_bodyRot, m_uuid); m_scene.StatsReporter.AddAgentTime(Environment.TickCount - m_perfMonMS); m_scene.StatsReporter.AddAgentUpdates(1); @@ -2473,7 +2472,7 @@ namespace OpenSim.Region.Framework.Scenes { m_perfMonMS = Environment.TickCount; - m_scene.Broadcast(SendTerseUpdateToClient); + m_scene.ForEachClient(SendTerseUpdateToClient); m_lastVelocity = m_velocity; lastPhysPos = AbsolutePosition; @@ -2774,7 +2773,7 @@ namespace OpenSim.Region.Framework.Scenes if (m_isChildAgent) return; - m_scene.Broadcast( + m_scene.ForEachClient( delegate(IClientAPI client) { client.SendAnimations(animations, seqs, m_controllingClient.AgentId, objectIDs); }); } diff --git a/OpenSim/Region/OptionalModules/Scripting/Minimodule/MRMModule.cs b/OpenSim/Region/OptionalModules/Scripting/Minimodule/MRMModule.cs index ce50f9e..4521f8e 100644 --- a/OpenSim/Region/OptionalModules/Scripting/Minimodule/MRMModule.cs +++ b/OpenSim/Region/OptionalModules/Scripting/Minimodule/MRMModule.cs @@ -259,7 +259,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.Minimodule if (e.InnerException != null) m_log.Error("[MRM] " + e.InnerException); - m_scene.Broadcast(delegate(IClientAPI user) + m_scene.ForEachClient(delegate(IClientAPI user) { user.SendAlertMessage( "MRM UnAuthorizedAccess: " + e); @@ -268,7 +268,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.Minimodule catch (Exception e) { m_log.Info("[MRM] Error: " + e); - m_scene.Broadcast(delegate(IClientAPI user) + m_scene.ForEachClient(delegate(IClientAPI user) { user.SendAlertMessage( "Compile error while building MRM script, check OpenSim console for more information."); -- cgit v1.1 From df2d5a460f060129e5c09148b9fa4df2f241d8b1 Mon Sep 17 00:00:00 2001 From: jjgreens Date: Wed, 14 Oct 2009 23:15:03 -0700 Subject: Replaced the update lists with a priority queue implementation in LLClientView Replaced the update lists with a priority queue implementation in LLClientView. The priority queues are based on the MinHeap implementation also included in this commit within the OpneSim.Framework namespace. Initially setup to exactly mimic the behavior beofre the change which was a first come first serve queue. --- .../Region/ClientStack/LindenUDP/LLClientView.cs | 224 ++++++++++++++++----- 1 file changed, 179 insertions(+), 45 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 82a2cdd..93fdeef 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -321,11 +321,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP private int m_cachedTextureSerial; private Timer m_avatarTerseUpdateTimer; - private List m_avatarTerseUpdates = new List(); + private PriorityQueue m_avatarTerseUpdates_ = + new PriorityQueue(); private Timer m_primTerseUpdateTimer; - private List m_primTerseUpdates = new List(); + private PriorityQueue m_primTerseUpdates_ = + new PriorityQueue(); private Timer m_primFullUpdateTimer; - private List m_primFullUpdates = new List(); + private PriorityQueue m_primFullUpdates_ = + new PriorityQueue(); private int m_moneyBalance; private int m_animationSequenceNumber = 1; private bool m_SendLogoutPacketWhenClosing = true; @@ -3435,16 +3438,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP ImprovedTerseObjectUpdatePacket.ObjectDataBlock terseBlock = CreateAvatarImprovedBlock(localID, position, velocity,rotation); - lock (m_avatarTerseUpdates) + lock (m_avatarTerseUpdates_.SyncRoot) { - m_avatarTerseUpdates.Add(terseBlock); + m_avatarTerseUpdates_.Enqueue(DateTime.Now.ToOADate(), terseBlock, localID); // If packet is full or own movement packet, send it. - if (m_avatarTerseUpdates.Count >= m_avatarTerseUpdatesPerPacket) + if (m_avatarTerseUpdates_.Count >= m_avatarTerseUpdatesPerPacket) { ProcessAvatarTerseUpdates(this, null); } - else if (m_avatarTerseUpdates.Count == 1) + else if (m_avatarTerseUpdates_.Count == 1) { lock (m_avatarTerseUpdateTimer) m_avatarTerseUpdateTimer.Start(); @@ -3454,7 +3457,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP private void ProcessAvatarTerseUpdates(object sender, ElapsedEventArgs e) { - lock (m_avatarTerseUpdates) + lock (m_avatarTerseUpdates_.SyncRoot) { ImprovedTerseObjectUpdatePacket terse = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); @@ -3465,8 +3468,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP (ushort)(Scene.TimeDilation * ushort.MaxValue); int max = m_avatarTerseUpdatesPerPacket; - if (max > m_avatarTerseUpdates.Count) - max = m_avatarTerseUpdates.Count; + if (max > m_avatarTerseUpdates_.Count) + max = m_avatarTerseUpdates_.Count; int count = 0; int size = 0; @@ -3474,30 +3477,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP byte[] zerobuffer = new byte[1024]; byte[] blockbuffer = new byte[1024]; + Queue updates = new Queue(); + for (count = 0 ; count < max ; count++) { int length = 0; - m_avatarTerseUpdates[count].ToBytes(blockbuffer, ref length); + m_avatarTerseUpdates_.Peek().ToBytes(blockbuffer, ref length); length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer); if (size + length > Packet.MTU) break; size += length; + updates.Enqueue(m_avatarTerseUpdates_.Dequeue()); } terse.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[count]; for (int i = 0 ; i < count ; i++) - { - terse.ObjectData[i] = m_avatarTerseUpdates[0]; - m_avatarTerseUpdates.RemoveAt(0); - } + terse.ObjectData[i] = updates.Dequeue(); terse.Header.Reliable = false; terse.Header.Zerocoded = true; // FIXME: Move this to ThrottleOutPacketType.State when the real prioritization code is committed OutPacket(terse, ThrottleOutPacketType.Task); - if (m_avatarTerseUpdates.Count == 0) + if (m_avatarTerseUpdates_.Count == 0) { lock (m_avatarTerseUpdateTimer) m_avatarTerseUpdateTimer.Stop(); @@ -3660,14 +3663,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP objectData.TextureAnim = textureanim; } - lock (m_primFullUpdates) + lock (m_primFullUpdates_.SyncRoot) { - if (m_primFullUpdates.Count == 0) + if (m_primFullUpdates_.Count == 0) m_primFullUpdateTimer.Start(); - m_primFullUpdates.Add(objectData); + m_primFullUpdates_.Enqueue(DateTime.Now.ToOADate(), objectData, localID); - if (m_primFullUpdates.Count >= m_primFullUpdatesPerPacket) + if (m_primFullUpdates_.Count >= m_primFullUpdatesPerPacket) ProcessPrimFullUpdates(this, null); } } @@ -3690,9 +3693,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP void ProcessPrimFullUpdates(object sender, ElapsedEventArgs e) { - lock (m_primFullUpdates) + lock (m_primFullUpdates_.SyncRoot) { - if (m_primFullUpdates.Count == 0 && m_primFullUpdateTimer.Enabled) + if (m_primFullUpdates_.Count == 0 && m_primFullUpdateTimer.Enabled) { lock (m_primFullUpdateTimer) m_primFullUpdateTimer.Stop(); @@ -3709,7 +3712,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP outPacket.RegionData.TimeDilation = (ushort)(Scene.TimeDilation * ushort.MaxValue); - int max = m_primFullUpdates.Count; + int max = m_primFullUpdates_.Count; if (max > m_primFullUpdatesPerPacket) max = m_primFullUpdatesPerPacket; @@ -3719,29 +3722,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP byte[] zerobuffer = new byte[1024]; byte[] blockbuffer = new byte[1024]; + Queue updates = new Queue(); + for (count = 0 ; count < max ; count++) { int length = 0; - m_primFullUpdates[count].ToBytes(blockbuffer, ref length); + m_primFullUpdates_.Peek().ToBytes(blockbuffer, ref length); length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer); if (size + length > Packet.MTU) break; size += length; + updates.Enqueue(m_primFullUpdates_.Dequeue()); } outPacket.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[count]; for (int index = 0 ; index < count ; index++) - { - outPacket.ObjectData[index] = m_primFullUpdates[0]; - m_primFullUpdates.RemoveAt(0); - } + outPacket.ObjectData[index] = updates.Dequeue(); outPacket.Header.Zerocoded = true; OutPacket(outPacket, ThrottleOutPacketType.State); - if (m_primFullUpdates.Count == 0 && m_primFullUpdateTimer.Enabled) + if (m_primFullUpdates_.Count == 0 && m_primFullUpdateTimer.Enabled) lock (m_primFullUpdateTimer) m_primFullUpdateTimer.Stop(); } @@ -3763,23 +3766,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP CreatePrimImprovedBlock(localID, position, rotation, velocity, rotationalvelocity, state); - lock (m_primTerseUpdates) + lock (m_primTerseUpdates_.SyncRoot) { - if (m_primTerseUpdates.Count == 0) + if (m_primTerseUpdates_.Count == 0) m_primTerseUpdateTimer.Start(); - m_primTerseUpdates.Add(objectData); + m_primTerseUpdates_.Enqueue(DateTime.Now.ToOADate(), objectData, localID); - if (m_primTerseUpdates.Count >= m_primTerseUpdatesPerPacket) + if (m_primTerseUpdates_.Count >= m_primTerseUpdatesPerPacket) ProcessPrimTerseUpdates(this, null); } } void ProcessPrimTerseUpdates(object sender, ElapsedEventArgs e) { - lock (m_primTerseUpdates) + lock (m_primTerseUpdates_.SyncRoot) { - if (m_primTerseUpdates.Count == 0) + if (m_primTerseUpdates_.Count == 0) { lock (m_primTerseUpdateTimer) m_primTerseUpdateTimer.Stop(); @@ -3797,7 +3800,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP outPacket.RegionData.TimeDilation = (ushort)(Scene.TimeDilation * ushort.MaxValue); - int max = m_primTerseUpdates.Count; + int max = m_primTerseUpdates_.Count; if (max > m_primTerseUpdatesPerPacket) max = m_primTerseUpdatesPerPacket; @@ -3807,14 +3810,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP byte[] zerobuffer = new byte[1024]; byte[] blockbuffer = new byte[1024]; + Queue updates = new Queue(); + for (count = 0 ; count < max ; count++) { int length = 0; - m_primTerseUpdates[count].ToBytes(blockbuffer, ref length); + m_primTerseUpdates_.Peek().ToBytes(blockbuffer, ref length); length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer); if (size + length > Packet.MTU) break; size += length; + updates.Enqueue(m_primTerseUpdates_.Dequeue()); } outPacket.ObjectData = @@ -3822,16 +3828,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP ObjectDataBlock[count]; for (int index = 0 ; index < count ; index++) - { - outPacket.ObjectData[index] = m_primTerseUpdates[0]; - m_primTerseUpdates.RemoveAt(0); - } + outPacket.ObjectData[index] = updates.Dequeue(); outPacket.Header.Reliable = false; outPacket.Header.Zerocoded = true; OutPacket(outPacket, ThrottleOutPacketType.State); - if (m_primTerseUpdates.Count == 0) + if (m_primTerseUpdates_.Count == 0) lock (m_primTerseUpdateTimer) m_primTerseUpdateTimer.Stop(); } @@ -3839,15 +3842,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP public void FlushPrimUpdates() { - while (m_primFullUpdates.Count > 0) + while (m_primFullUpdates_.Count > 0) { ProcessPrimFullUpdates(this, null); } - while (m_primTerseUpdates.Count > 0) + while (m_primTerseUpdates_.Count > 0) { ProcessPrimTerseUpdates(this, null); } - while (m_avatarTerseUpdates.Count > 0) + while (m_avatarTerseUpdates_.Count > 0) { ProcessAvatarTerseUpdates(this, null); } @@ -10578,5 +10581,136 @@ namespace OpenSim.Region.ClientStack.LindenUDP pack.TextureData.TextureID = textureID; OutPacket(pack, ThrottleOutPacketType.Task); } + + #region PriorityQueue + private class PriorityQueue + { + private MinHeap[] heaps = new MinHeap[1]; + private Dictionary lookup_table = new Dictionary(); + private Comparison comparison; + private object sync_root = new object(); + + internal PriorityQueue() : + this(MinHeap.DEFAULT_CAPACITY, Comparer.Default) { } + internal PriorityQueue(int capacity) : + this(capacity, Comparer.Default) { } + internal PriorityQueue(IComparer comparer) : + this(new Comparison(comparer.Compare)) { } + internal PriorityQueue(Comparison comparison) : + this(MinHeap.DEFAULT_CAPACITY, comparison) { } + internal PriorityQueue(int capacity, IComparer comparer) : + this(capacity, new Comparison(comparer.Compare)) { } + internal PriorityQueue(int capacity, Comparison comparison) + { + for (int i = 0; i < heaps.Length; ++i) + heaps[i] = new MinHeap(capacity); + this.comparison = comparison; + } + + internal object SyncRoot { get { return this.sync_root; } } + internal int Count + { + get + { + int count = 0; + for (int i = 0; i < heaps.Length; ++i) + count = heaps[i].Count; + return count; + } + } + + internal bool Enqueue(TPriority priority, TValue value, uint local_id) + { + LookupItem item; + + if (lookup_table.TryGetValue(local_id, out item)) + { + item.Heap[item.Handle] = new MinHeapItem(priority, value, local_id, this.comparison); + return false; + } + else + { + item.Heap = heaps[0]; + item.Heap.Add(new MinHeapItem(priority, value, local_id, this.comparison), ref item.Handle); + lookup_table.Add(local_id, item); + return true; + } + } + + internal TValue Peek() + { + for (int i = 0; i < heaps.Length; ++i) + if (heaps[i].Count > 0) + return heaps[i].Min().Value; + throw new InvalidOperationException(string.Format("The {0} is empty", this.GetType().ToString())); + } + + internal TValue Dequeue() + { + for (int i = 0; i < heaps.Length; ++i) + { + if (heaps[i].Count > 0) + { + MinHeapItem item = heaps[i].RemoveMin(); + lookup_table.Remove(item.LocalID); + return item.Value; + } + } + throw new InvalidOperationException(string.Format("The {0} is empty", this.GetType().ToString())); + } + + #region MinHeapItem + private struct MinHeapItem : IComparable + { + private TPriority priority; + private TValue value; + private uint local_id; + private Comparison comparison; + + internal MinHeapItem(TPriority priority, TValue value, uint local_id) : + this(priority, value, local_id, Comparer.Default) { } + internal MinHeapItem(TPriority priority, TValue value, uint local_id, IComparer comparer) : + this(priority, value, local_id, new Comparison(comparer.Compare)) { } + internal MinHeapItem(TPriority priority, TValue value, uint local_id, Comparison comparison) + { + this.priority = priority; + this.value = value; + this.local_id = local_id; + this.comparison = comparison; + } + + internal TPriority Priority { get { return this.priority; } } + internal TValue Value { get { return this.value; } } + internal uint LocalID { get { return this.local_id; } } + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("["); + if (this.priority != null) + sb.Append(this.priority.ToString()); + sb.Append(","); + if (this.value != null) + sb.Append(this.value.ToString()); + sb.Append("]"); + return sb.ToString(); + } + + public int CompareTo(MinHeapItem other) + { + return this.comparison(this.priority, other.priority); + } + } + #endregion + + #region LookupItem + private struct LookupItem { + internal MinHeap Heap; + internal IHandle Handle; + } + #endregion + } + #endregion + } } -- cgit v1.1 From 4b75353cbf50de3cae4c48ec90b55f30c1612c92 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Thu, 15 Oct 2009 16:35:27 -0700 Subject: Object update prioritization by Jim Greensky of Intel Labs, part one. This implements a simple distance prioritizer based on initial agent positions. Re-prioritizing and more advanced priority algorithms will follow soon --- .../Region/ClientStack/LindenUDP/LLClientView.cs | 344 ++++++++------------- .../Region/Examples/SimpleModule/MyNpcCharacter.cs | 28 +- .../Region/Framework/Interfaces/ISceneViewer.cs | 1 - OpenSim/Region/Framework/Scenes/Scene.cs | 40 ++- OpenSim/Region/Framework/Scenes/SceneGraph.cs | 1 - .../Region/Framework/Scenes/SceneObjectGroup.cs | 74 ++++- OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 8 +- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 58 +++- OpenSim/Region/Framework/Scenes/SceneViewer.cs | 23 +- .../Framework/Scenes/Scripting/IScriptHost.cs | 4 +- .../Framework/Scenes/Scripting/NullScriptHost.cs | 4 +- .../Server/IRCClientView.cs | 13 +- .../SceneObjectGroupDiff.cs | 2 +- .../Region/OptionalModules/World/NPC/NPCAvatar.cs | 27 +- .../Shared/Api/Implementation/LSL_Api.cs | 18 +- .../Shared/Api/Implementation/OSSL_Api.cs | 4 +- 16 files changed, 320 insertions(+), 329 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 93fdeef..0a7d923 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -320,14 +320,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP private readonly IGroupsModule m_GroupsModule; private int m_cachedTextureSerial; - private Timer m_avatarTerseUpdateTimer; - private PriorityQueue m_avatarTerseUpdates_ = + private PriorityQueue m_avatarTerseUpdates = new PriorityQueue(); - private Timer m_primTerseUpdateTimer; - private PriorityQueue m_primTerseUpdates_ = + private PriorityQueue m_primTerseUpdates = new PriorityQueue(); - private Timer m_primFullUpdateTimer; - private PriorityQueue m_primFullUpdates_ = + private PriorityQueue m_primFullUpdates = new PriorityQueue(); private int m_moneyBalance; private int m_animationSequenceNumber = 1; @@ -353,9 +350,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP // LL uses these limits, apparently. Compressed terse would be 23, but we don't have that yet protected int m_primTerseUpdatesPerPacket = 10; protected int m_primFullUpdatesPerPacket = 14; - protected int m_primTerseUpdateRate = 10; - protected int m_primFullUpdateRate = 14; - protected int m_avatarTerseUpdateRate = 50; protected int m_avatarTerseUpdatesPerPacket = 5; /// Number of texture packets to put on the queue each time the /// OnQueueEmpty event is triggered for the texture category @@ -479,25 +473,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Remove ourselves from the scene m_scene.RemoveClient(AgentId); - // Shut down timers. Thread Context of this method is murky. Lock all timers - if (m_avatarTerseUpdateTimer.Enabled) - lock (m_avatarTerseUpdateTimer) - m_avatarTerseUpdateTimer.Stop(); - if (m_primTerseUpdateTimer.Enabled) - lock (m_primTerseUpdateTimer) - m_primTerseUpdateTimer.Stop(); - if (m_primFullUpdateTimer.Enabled) - lock (m_primFullUpdateTimer) - m_primFullUpdateTimer.Stop(); - // We can't reach into other scenes and close the connection // We need to do this over grid communications //m_scene.CloseAllAgents(CircuitCode); - m_avatarTerseUpdateTimer.Dispose(); - m_primTerseUpdateTimer.Dispose(); - m_primFullUpdateTimer.Dispose(); - // Disable UDP handling for this client m_udpClient.Shutdown(); @@ -524,18 +503,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP public void Stop() { - // Shut down timers. Thread Context is Murky, lock all timers! - if (m_avatarTerseUpdateTimer.Enabled) - lock (m_avatarTerseUpdateTimer) - m_avatarTerseUpdateTimer.Stop(); - - if (m_primTerseUpdateTimer.Enabled) - lock (m_primTerseUpdateTimer) - m_primTerseUpdateTimer.Stop(); - if (m_primFullUpdateTimer.Enabled) - lock (m_primFullUpdateTimer) - m_primFullUpdateTimer.Stop(); } #endregion Client Methods @@ -631,18 +599,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP public virtual void Start() { - m_avatarTerseUpdateTimer = new Timer(m_avatarTerseUpdateRate); - m_avatarTerseUpdateTimer.Elapsed += new ElapsedEventHandler(ProcessAvatarTerseUpdates); - m_avatarTerseUpdateTimer.AutoReset = false; - - m_primTerseUpdateTimer = new Timer(m_primTerseUpdateRate); - m_primTerseUpdateTimer.Elapsed += new ElapsedEventHandler(ProcessPrimTerseUpdates); - m_primTerseUpdateTimer.AutoReset = false; - - m_primFullUpdateTimer = new Timer(m_primFullUpdateRate); - m_primFullUpdateTimer.Elapsed += new ElapsedEventHandler(ProcessPrimFullUpdates); - m_primFullUpdateTimer.AutoReset = false; - m_scene.AddNewClient(this); RefreshGroupMembership(); @@ -3394,28 +3350,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// /// send a objectupdate packet with information about the clients avatar /// - public void SendAvatarData(ulong regionHandle, string firstName, string lastName, string grouptitle, UUID avatarID, - uint avatarLocalID, Vector3 Pos, byte[] textureEntry, uint parentID, Quaternion rotation) + public void SendAvatarData(SendAvatarData data) { ObjectUpdatePacket objupdate = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate); // TODO: don't create new blocks if recycling an old packet - objupdate.RegionData.RegionHandle = regionHandle; + objupdate.RegionData.RegionHandle = data.regionHandle; objupdate.RegionData.TimeDilation = ushort.MaxValue; objupdate.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1]; - objupdate.ObjectData[0] = CreateDefaultAvatarPacket(textureEntry); + objupdate.ObjectData[0] = CreateDefaultAvatarPacket(data.textureEntry); //give this avatar object a local id and assign the user a name - objupdate.ObjectData[0].ID = avatarLocalID; - objupdate.ObjectData[0].FullID = avatarID; - objupdate.ObjectData[0].ParentID = parentID; + objupdate.ObjectData[0].ID = data.avatarLocalID; + objupdate.ObjectData[0].FullID = data.avatarID; + objupdate.ObjectData[0].ParentID = data.parentID; objupdate.ObjectData[0].NameValue = - Utils.StringToBytes("FirstName STRING RW SV " + firstName + "\nLastName STRING RW SV " + lastName + "\nTitle STRING RW SV " + grouptitle); + Utils.StringToBytes("FirstName STRING RW SV " + data.firstName + "\nLastName STRING RW SV " + data.lastName + "\nTitle STRING RW SV " + data.grouptitle); - Vector3 pos2 = new Vector3(Pos.X, Pos.Y, Pos.Z); + Vector3 pos2 = new Vector3(data.Pos.X, data.Pos.Y, data.Pos.Z); byte[] pb = pos2.GetBytes(); Array.Copy(pb, 0, objupdate.ObjectData[0].ObjectData, 16, pb.Length); - byte[] rot = rotation.GetBytes(); + byte[] rot = data.rotation.GetBytes(); Array.Copy(rot, 0, objupdate.ObjectData[0].ObjectData, 52, rot.Length); objupdate.Header.Zerocoded = true; @@ -3426,38 +3381,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Send a terse positional/rotation/velocity update about an avatar /// to the client. This avatar can be that of the client itself. /// - public virtual void SendAvatarTerseUpdate(ulong regionHandle, - ushort timeDilation, uint localID, Vector3 position, - Vector3 velocity, Quaternion rotation, UUID agentid) + public virtual void SendAvatarTerseUpdate(SendAvatarTerseData data) { + if (data.priority == double.NaN) + { + m_log.Error("[LLClientView] SendAvatarTerseUpdate received a NaN priority, dropping update"); + return; + } + + Quaternion rotation = data.rotation; + if (rotation.X == rotation.Y && rotation.Y == rotation.Z && rotation.Z == rotation.W && rotation.W == 0) rotation = Quaternion.Identity; ImprovedTerseObjectUpdatePacket.ObjectDataBlock terseBlock = - CreateAvatarImprovedBlock(localID, position, velocity,rotation); + CreateAvatarImprovedBlock(data.localID, data.position, data.velocity, rotation); - lock (m_avatarTerseUpdates_.SyncRoot) - { - m_avatarTerseUpdates_.Enqueue(DateTime.Now.ToOADate(), terseBlock, localID); - - // If packet is full or own movement packet, send it. - if (m_avatarTerseUpdates_.Count >= m_avatarTerseUpdatesPerPacket) - { - ProcessAvatarTerseUpdates(this, null); - } - else if (m_avatarTerseUpdates_.Count == 1) - { - lock (m_avatarTerseUpdateTimer) - m_avatarTerseUpdateTimer.Start(); - } - } + lock (m_avatarTerseUpdates.SyncRoot) + m_avatarTerseUpdates.Enqueue(data.priority, terseBlock, data.localID); } - private void ProcessAvatarTerseUpdates(object sender, ElapsedEventArgs e) + private void ProcessAvatarTerseUpdates() { - lock (m_avatarTerseUpdates_.SyncRoot) + lock (m_avatarTerseUpdates.SyncRoot) { ImprovedTerseObjectUpdatePacket terse = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); @@ -3468,8 +3416,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP (ushort)(Scene.TimeDilation * ushort.MaxValue); int max = m_avatarTerseUpdatesPerPacket; - if (max > m_avatarTerseUpdates_.Count) - max = m_avatarTerseUpdates_.Count; + if (max > m_avatarTerseUpdates.Count) + max = m_avatarTerseUpdates.Count; int count = 0; int size = 0; @@ -3482,12 +3430,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP for (count = 0 ; count < max ; count++) { int length = 0; - m_avatarTerseUpdates_.Peek().ToBytes(blockbuffer, ref length); + m_avatarTerseUpdates.Peek().ToBytes(blockbuffer, ref length); length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer); if (size + length > Packet.MTU) break; size += length; - updates.Enqueue(m_avatarTerseUpdates_.Dequeue()); + updates.Enqueue(m_avatarTerseUpdates.Dequeue()); } terse.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[count]; @@ -3497,14 +3445,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP terse.Header.Reliable = false; terse.Header.Zerocoded = true; - // FIXME: Move this to ThrottleOutPacketType.State when the real prioritization code is committed - OutPacket(terse, ThrottleOutPacketType.Task); - if (m_avatarTerseUpdates_.Count == 0) - { - lock (m_avatarTerseUpdateTimer) - m_avatarTerseUpdateTimer.Stop(); - } + OutPacket(terse, ThrottleOutPacketType.State); } } @@ -3569,54 +3511,42 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(attach, ThrottleOutPacketType.Task); } - public void SendPrimitiveToClient( - ulong regionHandle, ushort timeDilation, uint localID, PrimitiveBaseShape primShape, - Vector3 pos, Vector3 vel, Vector3 acc, Quaternion rotation, Vector3 rvel, - uint flags, UUID objectID, UUID ownerID, string text, byte[] color, - uint parentID, byte[] particleSystem, byte clickAction, byte material) + public void SendPrimitiveToClient(SendPrimitiveData data) { - byte[] textureanim = new byte[0]; + if (data.priority == double.NaN) + { + m_log.Error("[LLClientView] SendPrimitiveToClient received a NaN priority, dropping update"); + return; + } - SendPrimitiveToClient(regionHandle, timeDilation, localID, primShape, pos, vel, - acc, rotation, rvel, flags, - objectID, ownerID, text, color, parentID, particleSystem, - clickAction, material, textureanim, false, 0, UUID.Zero, UUID.Zero, 0, 0, 0); - } + Quaternion rotation = data.rotation; - public void SendPrimitiveToClient( - ulong regionHandle, ushort timeDilation, uint localID, PrimitiveBaseShape primShape, - Vector3 pos, Vector3 velocity, Vector3 acceleration, Quaternion rotation, Vector3 rotational_velocity, - uint flags, - UUID objectID, UUID ownerID, string text, byte[] color, uint parentID, byte[] particleSystem, - byte clickAction, byte material, byte[] textureanim, bool attachment, uint AttachPoint, UUID AssetId, UUID SoundId, double SoundGain, byte SoundFlags, double SoundRadius) - { - - if (AttachPoint > 30 && ownerID != AgentId) // Someone else's HUD + if (data.AttachPoint > 30 && data.ownerID != AgentId) // Someone else's HUD return; - if (primShape.PCode == 9 && primShape.State != 0 && parentID == 0) + if (data.primShape.PCode == 9 && data.primShape.State != 0 && data.parentID == 0) return; - if (rotation.X == rotation.Y && rotation.Y == rotation.Z && rotation.Z == rotation.W && rotation.W == 0) + if (rotation.X == rotation.Y && rotation.Y == rotation.Z && rotation.Z == rotation.W && rotation.W == 0.0f) rotation = Quaternion.Identity; - ObjectUpdatePacket.ObjectDataBlock objectData = CreatePrimUpdateBlock(primShape, flags); - - objectData.ID = localID; - objectData.FullID = objectID; - objectData.OwnerID = ownerID; - - objectData.Text = Util.StringToBytes256(text); - objectData.TextColor[0] = color[0]; - objectData.TextColor[1] = color[1]; - objectData.TextColor[2] = color[2]; - objectData.TextColor[3] = color[3]; - objectData.ParentID = parentID; - objectData.PSBlock = particleSystem; - objectData.ClickAction = clickAction; - objectData.Material = material; + ObjectUpdatePacket.ObjectDataBlock objectData = CreatePrimUpdateBlock(data.primShape, data.flags); + + objectData.ID = data.localID; + objectData.FullID = data.objectID; + objectData.OwnerID = data.ownerID; + + objectData.Text = Util.StringToBytes256(data.text); + objectData.TextColor[0] = data.color[0]; + objectData.TextColor[1] = data.color[1]; + objectData.TextColor[2] = data.color[2]; + objectData.TextColor[3] = data.color[3]; + objectData.ParentID = data.parentID; + objectData.PSBlock = data.particleSystem; + objectData.ClickAction = data.clickAction; + objectData.Material = data.material; objectData.Flags = 0; - if (attachment) + if (data.attachment) { // Necessary??? objectData.JointAxisOrAnchor = new Vector3(0, 0, 2); @@ -3624,14 +3554,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Item from inventory??? objectData.NameValue = - Utils.StringToBytes("AttachItemID STRING RW SV " + AssetId.Guid); - objectData.State = (byte)((AttachPoint % 16) * 16 + (AttachPoint / 16)); + Utils.StringToBytes("AttachItemID STRING RW SV " + data.AssetId.Guid); + objectData.State = (byte)((data.AttachPoint % 16) * 16 + (data.AttachPoint / 16)); } // Xantor 20080528: Send sound info as well // Xantor 20080530: Zero out everything if there's no SoundId, so zerocompression will work again - objectData.Sound = SoundId; - if (SoundId == UUID.Zero) + objectData.Sound = data.SoundId; + if (data.SoundId == UUID.Zero) { objectData.OwnerID = UUID.Zero; objectData.Gain = 0.0f; @@ -3640,39 +3570,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP } else { - objectData.OwnerID = ownerID; - objectData.Gain = (float)SoundGain; - objectData.Radius = (float)SoundRadius; - objectData.Flags = SoundFlags; + objectData.OwnerID = data.ownerID; + objectData.Gain = (float)data.SoundVolume; + objectData.Radius = (float)data.SoundRadius; + objectData.Flags = data.SoundFlags; } - byte[] pb = pos.GetBytes(); - Array.Copy(pb, 0, objectData.ObjectData, 0, pb.Length); + byte[] pb = data.pos.GetBytes(); + Buffer.BlockCopy(pb, 0, objectData.ObjectData, 0, pb.Length); - byte[] vel = velocity.GetBytes(); - Array.Copy(vel, 0, objectData.ObjectData, pb.Length, vel.Length); + byte[] vel = data.vel.GetBytes(); + Buffer.BlockCopy(vel, 0, objectData.ObjectData, pb.Length, vel.Length); byte[] rot = rotation.GetBytes(); - Array.Copy(rot, 0, objectData.ObjectData, 36, rot.Length); + Buffer.BlockCopy(rot, 0, objectData.ObjectData, 36, rot.Length); - byte[] rvel = rotational_velocity.GetBytes(); - Array.Copy(rvel, 0, objectData.ObjectData, 36 + rot.Length, rvel.Length); + byte[] rvel = data.rvel.GetBytes(); + Buffer.BlockCopy(rvel, 0, objectData.ObjectData, 36 + rot.Length, rvel.Length); - if (textureanim.Length > 0) + if (data.textureanim.Length > 0) { - objectData.TextureAnim = textureanim; + objectData.TextureAnim = data.textureanim; } - lock (m_primFullUpdates_.SyncRoot) - { - if (m_primFullUpdates_.Count == 0) - m_primFullUpdateTimer.Start(); - - m_primFullUpdates_.Enqueue(DateTime.Now.ToOADate(), objectData, localID); - - if (m_primFullUpdates_.Count >= m_primFullUpdatesPerPacket) - ProcessPrimFullUpdates(this, null); - } + lock (m_primFullUpdates.SyncRoot) + m_primFullUpdates.Enqueue(data.priority, objectData, data.localID); } void HandleQueueEmpty(ThrottleOutPacketType queue) @@ -3682,6 +3604,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP case ThrottleOutPacketType.Texture: ProcessTextureRequests(); break; + case ThrottleOutPacketType.State: + int count = 0; + + lock (m_avatarTerseUpdates.SyncRoot) + count = m_avatarTerseUpdates.Count; + if (count > 0) + { + ProcessAvatarTerseUpdates(); + return; + } + + lock (m_primFullUpdates.SyncRoot) + count = m_primFullUpdates.Count; + if (count > 0) + { + ProcessPrimFullUpdates(); + return; + } + + lock (m_primTerseUpdates.SyncRoot) + count = m_primTerseUpdates.Count; + if (count > 0) + { + ProcessPrimTerseUpdates(); + return; + } + break; } } @@ -3691,18 +3640,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_imageManager.ProcessImageQueue(m_textureSendLimit); } - void ProcessPrimFullUpdates(object sender, ElapsedEventArgs e) + void ProcessPrimFullUpdates() { - lock (m_primFullUpdates_.SyncRoot) + lock (m_primFullUpdates.SyncRoot) { - if (m_primFullUpdates_.Count == 0 && m_primFullUpdateTimer.Enabled) - { - lock (m_primFullUpdateTimer) - m_primFullUpdateTimer.Stop(); - - return; - } - ObjectUpdatePacket outPacket = (ObjectUpdatePacket)PacketPool.Instance.GetPacket( PacketType.ObjectUpdate); @@ -3712,7 +3653,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP outPacket.RegionData.TimeDilation = (ushort)(Scene.TimeDilation * ushort.MaxValue); - int max = m_primFullUpdates_.Count; + int max = m_primFullUpdates.Count; if (max > m_primFullUpdatesPerPacket) max = m_primFullUpdatesPerPacket; @@ -3727,12 +3668,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP for (count = 0 ; count < max ; count++) { int length = 0; - m_primFullUpdates_.Peek().ToBytes(blockbuffer, ref length); + m_primFullUpdates.Peek().ToBytes(blockbuffer, ref length); length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer); if (size + length > Packet.MTU) break; size += length; - updates.Enqueue(m_primFullUpdates_.Dequeue()); + updates.Enqueue(m_primFullUpdates.Dequeue()); } outPacket.ObjectData = @@ -3743,53 +3684,42 @@ namespace OpenSim.Region.ClientStack.LindenUDP outPacket.Header.Zerocoded = true; OutPacket(outPacket, ThrottleOutPacketType.State); - - if (m_primFullUpdates_.Count == 0 && m_primFullUpdateTimer.Enabled) - lock (m_primFullUpdateTimer) - m_primFullUpdateTimer.Stop(); } } /// /// /// - public void SendPrimTerseUpdate(ulong regionHandle, ushort timeDilation, uint localID, Vector3 position, - Quaternion rotation, Vector3 velocity, Vector3 rotationalvelocity, byte state, UUID AssetId, UUID ownerID, int attachPoint) + //public void SendPrimTerseUpdate(ulong regionHandle, ushort timeDilation, uint localID, Vector3 position, + // Quaternion rotation, Vector3 velocity, Vector3 rotationalvelocity, byte state, UUID AssetId, UUID ownerID, int attachPoint) + public void SendPrimTerseUpdate(SendPrimitiveTerseData data) { - if (attachPoint > 30 && ownerID != AgentId) // Someone else's HUD + if (data.priority == double.NaN) + { + m_log.Error("[LLClientView] SendPrimTerseUpdate received a NaN priority, dropping update"); + return; + } + + Quaternion rotation = data.rotation; + + if (data.attachPoint > 30 && data.owner != AgentId) // Someone else's HUD return; if (rotation.X == rotation.Y && rotation.Y == rotation.Z && rotation.Z == rotation.W && rotation.W == 0) rotation = Quaternion.Identity; ImprovedTerseObjectUpdatePacket.ObjectDataBlock objectData = - CreatePrimImprovedBlock(localID, position, rotation, - velocity, rotationalvelocity, state); - - lock (m_primTerseUpdates_.SyncRoot) - { - if (m_primTerseUpdates_.Count == 0) - m_primTerseUpdateTimer.Start(); - - m_primTerseUpdates_.Enqueue(DateTime.Now.ToOADate(), objectData, localID); + CreatePrimImprovedBlock(data.localID, data.position, rotation, + data.velocity, data.rotationalvelocity, data.state); - if (m_primTerseUpdates_.Count >= m_primTerseUpdatesPerPacket) - ProcessPrimTerseUpdates(this, null); - } + lock (m_primTerseUpdates.SyncRoot) + m_primTerseUpdates.Enqueue(data.priority, objectData, data.localID); } - void ProcessPrimTerseUpdates(object sender, ElapsedEventArgs e) + void ProcessPrimTerseUpdates() { - lock (m_primTerseUpdates_.SyncRoot) + lock (m_primTerseUpdates.SyncRoot) { - if (m_primTerseUpdates_.Count == 0) - { - lock (m_primTerseUpdateTimer) - m_primTerseUpdateTimer.Stop(); - - return; - } - ImprovedTerseObjectUpdatePacket outPacket = (ImprovedTerseObjectUpdatePacket) PacketPool.Instance.GetPacket( @@ -3800,7 +3730,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP outPacket.RegionData.TimeDilation = (ushort)(Scene.TimeDilation * ushort.MaxValue); - int max = m_primTerseUpdates_.Count; + int max = m_primTerseUpdates.Count; if (max > m_primTerseUpdatesPerPacket) max = m_primTerseUpdatesPerPacket; @@ -3815,12 +3745,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP for (count = 0 ; count < max ; count++) { int length = 0; - m_primTerseUpdates_.Peek().ToBytes(blockbuffer, ref length); + m_primTerseUpdates.Peek().ToBytes(blockbuffer, ref length); length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer); if (size + length > Packet.MTU) break; size += length; - updates.Enqueue(m_primTerseUpdates_.Dequeue()); + updates.Enqueue(m_primTerseUpdates.Dequeue()); } outPacket.ObjectData = @@ -3833,26 +3763,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP outPacket.Header.Reliable = false; outPacket.Header.Zerocoded = true; OutPacket(outPacket, ThrottleOutPacketType.State); - - if (m_primTerseUpdates_.Count == 0) - lock (m_primTerseUpdateTimer) - m_primTerseUpdateTimer.Stop(); } } public void FlushPrimUpdates() { - while (m_primFullUpdates_.Count > 0) + while (m_primFullUpdates.Count > 0) { - ProcessPrimFullUpdates(this, null); + ProcessPrimFullUpdates(); } - while (m_primTerseUpdates_.Count > 0) + while (m_primTerseUpdates.Count > 0) { - ProcessPrimTerseUpdates(this, null); + ProcessPrimTerseUpdates(); } - while (m_avatarTerseUpdates_.Count > 0) + while (m_avatarTerseUpdates.Count > 0) { - ProcessAvatarTerseUpdates(this, null); + ProcessAvatarTerseUpdates(); } } diff --git a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs index d651fd4..3799a02 100644 --- a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs +++ b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs @@ -499,13 +499,11 @@ namespace OpenSim.Region.Examples.SimpleModule { } - public virtual void SendAvatarData(ulong regionHandle, string firstName, string lastName, string grouptitle, UUID avatarID, - uint avatarLocalID, Vector3 Pos, byte[] textureEntry, uint parentID, Quaternion rotation) + public virtual void SendAvatarData(SendAvatarData data) { } - public virtual void SendAvatarTerseUpdate(ulong regionHandle, ushort timeDilation, uint localID, - Vector3 position, Vector3 velocity, Quaternion rotation, UUID agentid) + public virtual void SendAvatarTerseUpdate(SendAvatarTerseData data) { } @@ -521,27 +519,11 @@ namespace OpenSim.Region.Examples.SimpleModule { } - public virtual void SendPrimitiveToClient(ulong regionHandle, ushort timeDilation, uint localID, - PrimitiveBaseShape primShape, Vector3 pos, Vector3 vel, - Vector3 acc, Quaternion rotation, Vector3 rvel, uint flags, - UUID objectID, UUID ownerID, string text, byte[] color, - uint parentID, - byte[] particleSystem, byte clickAction, byte material) + public virtual void SendPrimitiveToClient(SendPrimitiveData data) { } - public virtual void SendPrimitiveToClient(ulong regionHandle, ushort timeDilation, uint localID, - PrimitiveBaseShape primShape, Vector3 pos, Vector3 vel, - Vector3 acc, Quaternion rotation, Vector3 rvel, uint flags, - UUID objectID, UUID ownerID, string text, byte[] color, - uint parentID, - byte[] particleSystem, byte clickAction, byte material, byte[] textureanimation, - bool attachment, uint AttachmentPoint, UUID AssetId, UUID SoundId, double SoundVolume, byte SoundFlags, double SoundRadius) - { - } - public virtual void SendPrimTerseUpdate(ulong regionHandle, ushort timeDilation, uint localID, - Vector3 position, Quaternion rotation, Vector3 velocity, - Vector3 rotationalvelocity, byte state, UUID AssetId, - UUID ownerID, int attachPoint) + + public virtual void SendPrimTerseUpdate(SendPrimitiveTerseData data) { } diff --git a/OpenSim/Region/Framework/Interfaces/ISceneViewer.cs b/OpenSim/Region/Framework/Interfaces/ISceneViewer.cs index 8e3f4a0..7251d57 100644 --- a/OpenSim/Region/Framework/Interfaces/ISceneViewer.cs +++ b/OpenSim/Region/Framework/Interfaces/ISceneViewer.cs @@ -34,7 +34,6 @@ namespace OpenSim.Region.Framework.Interfaces { void Reset(); void Close(); - int MaxPrimsPerFrame { get; set; } void QueuePartForUpdate(SceneObjectPart part); void SendPrimUpdates(); } diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index d13d4fb..c7efc19 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -57,6 +57,12 @@ namespace OpenSim.Region.Framework.Scenes public partial class Scene : SceneBase { + public enum UpdatePrioritizationSchemes { + Time = 0, + Distance = 1, + SimpleAngularDistance = 2, + } + public delegate void SynchronizeSceneHandler(Scene scene); public SynchronizeSceneHandler SynchronizeScene = null; @@ -268,9 +274,10 @@ namespace OpenSim.Region.Framework.Scenes private volatile bool shuttingdown = false; private int m_lastUpdate = Environment.TickCount; - private int m_maxPrimsPerFrame = 200; private bool m_firstHeartbeat = true; + private UpdatePrioritizationSchemes m_update_prioritization_scheme = UpdatePrioritizationSchemes.Time; + private object m_deleting_scene_object = new object(); // the minimum time that must elapse before a changed object will be considered for persisted @@ -282,6 +289,8 @@ namespace OpenSim.Region.Framework.Scenes #region Properties + public UpdatePrioritizationSchemes UpdatePrioritizationScheme { get { return this.m_update_prioritization_scheme; } } + public AgentCircuitManager AuthenticateHandler { get { return m_authenticateHandler; } @@ -326,12 +335,6 @@ namespace OpenSim.Region.Framework.Scenes get { return m_sceneGraph.m_syncRoot; } } - public int MaxPrimsPerFrame - { - get { return m_maxPrimsPerFrame; } - set { m_maxPrimsPerFrame = value; } - } - /// /// This is for llGetRegionFPS /// @@ -509,7 +512,6 @@ namespace OpenSim.Region.Framework.Scenes m_defaultScriptEngine = startupConfig.GetString("DefaultScriptEngine", "DotNetEngine"); - m_maxPrimsPerFrame = startupConfig.GetInt("MaxPrimsPerFrame", 200); IConfig packetConfig = m_config.Configs["PacketPool"]; if (packetConfig != null) { @@ -518,6 +520,28 @@ namespace OpenSim.Region.Framework.Scenes } m_strictAccessControl = startupConfig.GetBoolean("StrictAccessControl", m_strictAccessControl); + + IConfig interest_management_config = m_config.Configs["InterestManagement"]; + if (interest_management_config != null) + { + string update_prioritization_scheme = interest_management_config.GetString("UpdatePrioritizationScheme", "Time").Trim().ToLower(); + switch (update_prioritization_scheme) + { + case "time": + m_update_prioritization_scheme = UpdatePrioritizationSchemes.Time; + break; + case "distance": + m_update_prioritization_scheme = UpdatePrioritizationSchemes.Distance; + break; + case "simpleangulardistance": + m_update_prioritization_scheme = UpdatePrioritizationSchemes.SimpleAngularDistance; + break; + default: + m_log.Warn("[SCENE]: UpdatePrioritizationScheme was not recognized, setting to default settomg of Time"); + m_update_prioritization_scheme = UpdatePrioritizationSchemes.Time; + break; + } + } } catch { diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index 04397ad..b9872ca 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -613,7 +613,6 @@ namespace OpenSim.Region.Framework.Scenes newAvatar = new ScenePresence(client, m_parentScene, m_regInfo, appearance); newAvatar.IsChildAgent = true; - newAvatar.MaxPrimsPerFrame = m_parentScene.MaxPrimsPerFrame; AddScenePresence(newAvatar); diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index d4cef7d..2153b9b 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -1817,7 +1817,7 @@ namespace OpenSim.Region.Framework.Scenes public void ServiceObjectPropertiesFamilyRequest(IClientAPI remoteClient, UUID AgentID, uint RequestFlags) { - remoteClient.SendObjectPropertiesFamilyData(RequestFlags, RootPart.UUID, RootPart.ObjectOwner, RootPart.GroupID, RootPart.BaseMask, + remoteClient.SendObjectPropertiesFamilyData(RequestFlags, RootPart.UUID, RootPart.OwnerID, RootPart.GroupID, RootPart.BaseMask, RootPart.OwnerMask, RootPart.GroupMask, RootPart.EveryoneMask, RootPart.NextOwnerMask, RootPart.OwnershipCost, RootPart.ObjectSaleType, RootPart.SalePrice, RootPart.Category, RootPart.CreatorID, RootPart.Name, RootPart.Description); @@ -3343,5 +3343,77 @@ namespace OpenSim.Region.Framework.Scenes return true; } + + public double GetUpdatePriority(IClientAPI client) + { + switch (Scene.UpdatePrioritizationScheme) + { + case Scene.UpdatePrioritizationSchemes.Time: + return GetPriorityByTime(); + case Scene.UpdatePrioritizationSchemes.Distance: + return GetPriorityByDistance(client); + case Scene.UpdatePrioritizationSchemes.SimpleAngularDistance: + return GetPriorityBySimpleAngularDistance(client); + default: + throw new InvalidOperationException("UpdatePrioritizationScheme not defined"); + } + } + + private double GetPriorityByTime() + { + return DateTime.Now.ToOADate(); + } + + private double GetPriorityByDistance(IClientAPI client) + { + ScenePresence presence = Scene.GetScenePresence(client.AgentId); + if (presence != null) + { + return GetPriorityByDistance((presence.IsChildAgent) ? + presence.AbsolutePosition : presence.CameraPosition); + } + return double.NaN; + } + + private double GetPriorityBySimpleAngularDistance(IClientAPI client) + { + ScenePresence presence = Scene.GetScenePresence(client.AgentId); + if (presence != null) + { + return GetPriorityBySimpleAngularDistance((presence.IsChildAgent) ? + presence.AbsolutePosition : presence.CameraPosition); + } + return double.NaN; + } + + public double GetPriorityByDistance(Vector3 position) + { + return Vector3.Distance(AbsolutePosition, position); + } + + public double GetPriorityBySimpleAngularDistance(Vector3 position) + { + double distance = Vector3.Distance(position, AbsolutePosition); + if (distance >= double.Epsilon) + { + float height; + Vector3 box = GetAxisAlignedBoundingBox(out height); + + double angle = box.X / distance; + double max = angle; + + angle = box.Y / distance; + if (max < angle) + max = angle; + + angle = box.Z / distance; + if (max < angle) + max = angle; + + return -max; + } + else + return double.MinValue; + } } } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 377cb6e..79f6366 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -2400,10 +2400,10 @@ if (m_shape != null) { //isattachment = ParentGroup.RootPart.IsAttachment; byte[] color = new byte[] {m_color.R, m_color.G, m_color.B, m_color.A}; - remoteClient.SendPrimitiveToClient(m_regionHandle, (ushort)(m_parentGroup.GetTimeDilation() * (float)ushort.MaxValue), LocalId, m_shape, + remoteClient.SendPrimitiveToClient(new SendPrimitiveData(m_regionHandle, (ushort)(m_parentGroup.GetTimeDilation() * (float)ushort.MaxValue), LocalId, m_shape, lPos, Velocity, Acceleration, RotationOffset, RotationalVelocity, clientFlags, m_uuid, _ownerID, m_text, color, _parentID, m_particleSystem, m_clickAction, (byte)m_material, m_TextureAnimation, IsAttachment, - AttachmentPoint,FromItemID, Sound, SoundGain, SoundFlags, SoundRadius); + AttachmentPoint,FromItemID, Sound, SoundGain, SoundFlags, SoundRadius, ParentGroup.GetUpdatePriority(remoteClient))); } /// @@ -3794,12 +3794,12 @@ if (m_shape != null) { // Causes this thread to dig into the Client Thread Data. // Remember your locking here! - remoteClient.SendPrimTerseUpdate(m_regionHandle, + remoteClient.SendPrimTerseUpdate(new SendPrimitiveTerseData(m_regionHandle, (ushort)(m_parentGroup.GetTimeDilation() * (float)ushort.MaxValue), LocalId, lPos, RotationOffset, Velocity, RotationalVelocity, state, FromItemID, - OwnerID, (int)AttachmentPoint); + OwnerID, (int)AttachmentPoint, ParentGroup.GetUpdatePriority(remoteClient))); } public void AddScriptLPS(int count) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 387db44..a5b88c6 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -403,12 +403,6 @@ namespace OpenSim.Region.Framework.Scenes set { m_parentPosition = value; } } - public int MaxPrimsPerFrame - { - get { return m_sceneViewer.MaxPrimsPerFrame; } - set { m_sceneViewer.MaxPrimsPerFrame = value; } - } - /// /// Absolute position of this avatar in 'region cordinates' /// @@ -2457,8 +2451,8 @@ namespace OpenSim.Region.Framework.Scenes Vector3 pos = m_pos; pos.Z -= m_appearance.HipOffset; - remoteClient.SendAvatarTerseUpdate(m_regionHandle, (ushort)(m_scene.TimeDilation * ushort.MaxValue), - LocalId, pos, Velocity, m_bodyRot, m_uuid); + remoteClient.SendAvatarTerseUpdate(new SendAvatarTerseData(m_regionHandle, (ushort)(m_scene.TimeDilation * ushort.MaxValue), LocalId, + pos, m_velocity, m_rotation, m_uuid, GetUpdatePriority(remoteClient))); m_scene.StatsReporter.AddAgentTime(Environment.TickCount - m_perfMonMS); m_scene.StatsReporter.AddAgentUpdates(1); @@ -2563,9 +2557,9 @@ namespace OpenSim.Region.Framework.Scenes Vector3 pos = m_pos; pos.Z -= m_appearance.HipOffset; - remoteAvatar.m_controllingClient.SendAvatarData(m_regionInfo.RegionHandle, m_firstname, m_lastname, m_grouptitle, m_uuid, + remoteAvatar.m_controllingClient.SendAvatarData(new SendAvatarData(m_regionInfo.RegionHandle, m_firstname, m_lastname, m_grouptitle, m_uuid, LocalId, m_pos, m_appearance.Texture.GetBytes(), - m_parentID, rot); + m_parentID, rot)); m_scene.StatsReporter.AddAgentUpdates(1); } @@ -2634,8 +2628,8 @@ namespace OpenSim.Region.Framework.Scenes Vector3 pos = m_pos; pos.Z -= m_appearance.HipOffset; - m_controllingClient.SendAvatarData(m_regionInfo.RegionHandle, m_firstname, m_lastname, m_grouptitle, m_uuid, LocalId, - m_pos, m_appearance.Texture.GetBytes(), m_parentID, rot); + m_controllingClient.SendAvatarData(new SendAvatarData(m_regionInfo.RegionHandle, m_firstname, m_lastname, m_grouptitle, m_uuid, LocalId, + m_pos, m_appearance.Texture.GetBytes(), m_parentID, rot)); if (!m_isChildAgent) { @@ -2741,8 +2735,8 @@ namespace OpenSim.Region.Framework.Scenes } Quaternion rot = m_bodyRot; - m_controllingClient.SendAvatarData(m_regionInfo.RegionHandle, m_firstname, m_lastname, m_grouptitle, m_uuid, LocalId, - m_pos, m_appearance.Texture.GetBytes(), m_parentID, rot); + m_controllingClient.SendAvatarData(new SendAvatarData(m_regionInfo.RegionHandle, m_firstname, m_lastname, m_grouptitle, m_uuid, LocalId, + m_pos, m_appearance.Texture.GetBytes(), m_parentID, rot)); } @@ -3870,5 +3864,41 @@ namespace OpenSim.Region.Framework.Scenes } } } + + public double GetUpdatePriority(IClientAPI client) + { + switch (Scene.UpdatePrioritizationScheme) + { + case Scene.UpdatePrioritizationSchemes.Time: + return GetPriorityByTime(); + case Scene.UpdatePrioritizationSchemes.Distance: + return GetPriorityByDistance(client); + case Scene.UpdatePrioritizationSchemes.SimpleAngularDistance: + return GetPriorityByDistance(client); + default: + throw new InvalidOperationException("UpdatePrioritizationScheme not defined."); + } + } + + private double GetPriorityByTime() + { + return DateTime.Now.ToOADate(); + } + + private double GetPriorityByDistance(IClientAPI client) + { + ScenePresence presence = Scene.GetScenePresence(client.AgentId); + if (presence != null) + { + return GetPriorityByDistance((presence.IsChildAgent) ? + presence.AbsolutePosition : presence.CameraPosition); + } + return double.NaN; + } + + private double GetPriorityByDistance(Vector3 position) + { + return Vector3.Distance(AbsolutePosition, position); + } } } diff --git a/OpenSim/Region/Framework/Scenes/SceneViewer.cs b/OpenSim/Region/Framework/Scenes/SceneViewer.cs index 8ab0552..e4296ef 100644 --- a/OpenSim/Region/Framework/Scenes/SceneViewer.cs +++ b/OpenSim/Region/Framework/Scenes/SceneViewer.cs @@ -45,14 +45,6 @@ namespace OpenSim.Region.Framework.Scenes protected Dictionary m_updateTimes = new Dictionary(); - protected int m_maxPrimsPerFrame = 200; - - public int MaxPrimsPerFrame - { - get { return m_maxPrimsPerFrame; } - set { m_maxPrimsPerFrame = value; } - } - public SceneViewer() { } @@ -82,16 +74,7 @@ namespace OpenSim.Region.Framework.Scenes { m_pendingObjects = new Queue(); - List ents = new List(m_presence.Scene.Entities); - if (!m_presence.IsChildAgent) // Proximity sort makes no sense for - { // Child agents - ents.Sort(delegate(EntityBase a, EntityBase b) - { - return Vector3.Distance(m_presence.AbsolutePosition, a.AbsolutePosition).CompareTo(Vector3.Distance(m_presence.AbsolutePosition, b.AbsolutePosition)); - }); - } - - foreach (EntityBase e in ents) + foreach (EntityBase e in m_presence.Scene.Entities) { if (e is SceneObjectGroup) m_pendingObjects.Enqueue((SceneObjectGroup)e); @@ -99,7 +82,7 @@ namespace OpenSim.Region.Framework.Scenes } } - while (m_pendingObjects != null && m_pendingObjects.Count > 0 && m_partsUpdateQueue.Count < m_maxPrimsPerFrame) + while (m_pendingObjects != null && m_pendingObjects.Count > 0) { SceneObjectGroup g = m_pendingObjects.Dequeue(); @@ -183,8 +166,6 @@ namespace OpenSim.Region.Framework.Scenes m_presence.GenerateClientFlags(part.UUID)); } } - - m_presence.ControllingClient.FlushPrimUpdates(); } public void Reset() diff --git a/OpenSim/Region/Framework/Scenes/Scripting/IScriptHost.cs b/OpenSim/Region/Framework/Scenes/Scripting/IScriptHost.cs index 29c4672..f3be028 100644 --- a/OpenSim/Region/Framework/Scenes/Scripting/IScriptHost.cs +++ b/OpenSim/Region/Framework/Scenes/Scripting/IScriptHost.cs @@ -35,8 +35,8 @@ namespace OpenSim.Region.Framework.Scenes.Scripting string Description { get; set; } UUID UUID { get; } - UUID ObjectOwner { get; } - UUID ObjectCreator { get; } + UUID OwnerID { get; } + UUID CreatorID { get; } Vector3 AbsolutePosition { get; } string SitName { get; set; } diff --git a/OpenSim/Region/Framework/Scenes/Scripting/NullScriptHost.cs b/OpenSim/Region/Framework/Scenes/Scripting/NullScriptHost.cs index af18a98..d7198f0 100644 --- a/OpenSim/Region/Framework/Scenes/Scripting/NullScriptHost.cs +++ b/OpenSim/Region/Framework/Scenes/Scripting/NullScriptHost.cs @@ -68,12 +68,12 @@ namespace OpenSim.Region.Framework.Scenes.Scripting get { return UUID.Zero; } } - public UUID ObjectOwner + public UUID OwnerID { get { return UUID.Zero; } } - public UUID ObjectCreator + public UUID CreatorID { get { return UUID.Zero; } } diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs index a8acf0d..8ad9327 100644 --- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs +++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs @@ -1011,12 +1011,12 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server } - public void SendAvatarData(ulong regionHandle, string firstName, string lastName, string grouptitle, UUID avatarID, uint avatarLocalID, Vector3 Pos, byte[] textureEntry, uint parentID, Quaternion rotation) + public void SendAvatarData(SendAvatarData data) { } - public void SendAvatarTerseUpdate(ulong regionHandle, ushort timeDilation, uint localID, Vector3 position, Vector3 velocity, Quaternion rotation, UUID agentid) + public void SendAvatarTerseUpdate(SendAvatarTerseData data) { } @@ -1036,17 +1036,12 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server } - public void SendPrimitiveToClient(ulong regionHandle, ushort timeDilation, uint localID, PrimitiveBaseShape primShape, Vector3 pos, Vector3 vel, Vector3 acc, Quaternion rotation, Vector3 rvel, uint flags, UUID objectID, UUID ownerID, string text, byte[] color, uint parentID, byte[] particleSystem, byte clickAction, byte material, byte[] textureanim, bool attachment, uint AttachPoint, UUID AssetId, UUID SoundId, double SoundVolume, byte SoundFlags, double SoundRadius) + public void SendPrimitiveToClient(SendPrimitiveData data) { } - public void SendPrimitiveToClient(ulong regionHandle, ushort timeDilation, uint localID, PrimitiveBaseShape primShape, Vector3 pos, Vector3 vel, Vector3 acc, Quaternion rotation, Vector3 rvel, uint flags, UUID objectID, UUID ownerID, string text, byte[] color, uint parentID, byte[] particleSystem, byte clickAction, byte material) - { - - } - - public void SendPrimTerseUpdate(ulong regionHandle, ushort timeDilation, uint localID, Vector3 position, Quaternion rotation, Vector3 velocity, Vector3 rotationalvelocity, byte state, UUID AssetId, UUID owner, int attachPoint) + public void SendPrimTerseUpdate(SendPrimitiveTerseData data) { } diff --git a/OpenSim/Region/OptionalModules/ContentManagementSystem/SceneObjectGroupDiff.cs b/OpenSim/Region/OptionalModules/ContentManagementSystem/SceneObjectGroupDiff.cs index 0379180..e185351 100644 --- a/OpenSim/Region/OptionalModules/ContentManagementSystem/SceneObjectGroupDiff.cs +++ b/OpenSim/Region/OptionalModules/ContentManagementSystem/SceneObjectGroupDiff.cs @@ -188,7 +188,7 @@ namespace OpenSim.Region.OptionalModules.ContentManagement // MISC COMPARISONS (UUID, Byte) if (first.ClickAction != second.ClickAction) result |= Diff.CLICKACTION; - if (first.ObjectOwner != second.ObjectOwner) + if (first.OwnerID != second.OwnerID) result |= Diff.OBJECTOWNER; diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs index f7c63ac..6c58f2d 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs @@ -588,13 +588,11 @@ namespace OpenSim.Region.OptionalModules.World.NPC { } - public virtual void SendAvatarData(ulong regionHandle, string firstName, string lastName, string grouptitle, UUID avatarID, - uint avatarLocalID, Vector3 Pos, byte[] textureEntry, uint parentID, Quaternion rotation) + public virtual void SendAvatarData(SendAvatarData data) { } - public virtual void SendAvatarTerseUpdate(ulong regionHandle, ushort timeDilation, uint localID, - Vector3 position, Vector3 velocity, Quaternion rotation, UUID agentId) + public virtual void SendAvatarTerseUpdate(SendAvatarTerseData data) { } @@ -610,26 +608,11 @@ namespace OpenSim.Region.OptionalModules.World.NPC { } - public virtual void SendPrimitiveToClient(ulong regionHandle, ushort timeDilation, uint localID, - PrimitiveBaseShape primShape, Vector3 pos, Vector3 vel, - Vector3 acc, Quaternion rotation, Vector3 rvel, uint flags, - UUID objectID, UUID ownerID, string text, byte[] color, - uint parentID, - byte[] particleSystem, byte clickAction, byte material) + public virtual void SendPrimitiveToClient(SendPrimitiveData data) { } - public virtual void SendPrimitiveToClient(ulong regionHandle, ushort timeDilation, uint localID, - PrimitiveBaseShape primShape, Vector3 pos, Vector3 vel, - Vector3 acc, Quaternion rotation, Vector3 rvel, uint flags, - UUID objectID, UUID ownerID, string text, byte[] color, - uint parentID, - byte[] particleSystem, byte clickAction, byte material, byte[] textureanimation, - bool attachment, uint AttachmentPoint, UUID AssetId, UUID SoundId, double SoundVolume, byte SoundFlags, double SoundRadius) - { - } - public virtual void SendPrimTerseUpdate(ulong regionHandle, ushort timeDilation, uint localID, - Vector3 position, Quaternion rotation, Vector3 velocity, - Vector3 rotationalvelocity, byte state, UUID AssetId, UUID ownerID, int attachPoint) + + public virtual void SendPrimTerseUpdate(SendPrimitiveTerseData data) { } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index e10e612..57b14f7 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -2875,7 +2875,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); - return m_host.ObjectOwner.ToString(); + return m_host.OwnerID.ToString(); } public void llInstantMessage(string user, string message) @@ -5634,7 +5634,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api ILandObject parcel = World.LandChannel.GetLandObject(av.AbsolutePosition.X, av.AbsolutePosition.Y); if (parcel != null) { - if (m_host.ObjectOwner == parcel.LandData.OwnerID || + if (m_host.OwnerID == parcel.LandData.OwnerID || (m_host.OwnerID == m_host.GroupID && m_host.GroupID == parcel.LandData.GroupID && parcel.LandData.IsGroupOwned) || World.Permissions.IsGod(m_host.OwnerID)) { @@ -7157,7 +7157,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); - if (land.LandData.OwnerID != m_host.ObjectOwner) + if (land.LandData.OwnerID != m_host.OwnerID) return; land.SetMusicUrl(url); @@ -7215,7 +7215,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_String llGetCreator() { m_host.AddScriptLPS(1); - return m_host.ObjectCreator.ToString(); + return m_host.CreatorID.ToString(); } public LSL_String llGetTimestamp() @@ -8396,7 +8396,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api IDialogModule dm = World.RequestModuleInterface(); if (null != dm) dm.SendUrlToUser( - new UUID(avatar_id), m_host.Name, m_host.UUID, m_host.ObjectOwner, false, message, url); + new UUID(avatar_id), m_host.Name, m_host.UUID, m_host.OwnerID, false, message, url); ConditionalScriptSleep(10000); } @@ -8411,7 +8411,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // according to the docs, this command only works if script owner and land owner are the same // lets add estate owners and gods, too, and use the generic permission check. ILandObject landObject = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); - if (!World.Permissions.CanEditParcel(m_host.ObjectOwner, landObject)) return; + if (!World.Permissions.CanEditParcel(m_host.OwnerID, landObject)) return; bool update = false; // send a ParcelMediaUpdate (and possibly change the land's media URL)? byte loop = 0; @@ -9081,9 +9081,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api Vector3 velocity = m_host.Velocity; Quaternion rotation = m_host.RotationOffset; string ownerName = String.Empty; - ScenePresence scenePresence = World.GetScenePresence(m_host.ObjectOwner); + ScenePresence scenePresence = World.GetScenePresence(m_host.OwnerID); if (scenePresence == null) - ownerName = resolveName(m_host.ObjectOwner); + ownerName = resolveName(m_host.OwnerID); else ownerName = scenePresence.Name; @@ -9108,7 +9108,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api httpHeaders["X-SecondLife-Local-Velocity"] = string.Format("({0:0.000000}, {1:0.000000}, {2:0.000000})", velocity.X, velocity.Y, velocity.Z); httpHeaders["X-SecondLife-Local-Rotation"] = string.Format("({0:0.000000}, {1:0.000000}, {2:0.000000}, {3:0.000000})", rotation.X, rotation.Y, rotation.Z, rotation.W); httpHeaders["X-SecondLife-Owner-Name"] = ownerName; - httpHeaders["X-SecondLife-Owner-Key"] = m_host.ObjectOwner.ToString(); + httpHeaders["X-SecondLife-Owner-Key"] = m_host.OwnerID.ToString(); string userAgent = config.Configs["Network"].GetString("user_agent", null); if (userAgent != null) httpHeaders["User-Agent"] = userAgent; diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index 4cb4b61..52396b6 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -1164,7 +1164,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); - if (land.LandData.OwnerID != m_host.ObjectOwner) + if (land.LandData.OwnerID != m_host.OwnerID) return; land.SetMediaUrl(url); @@ -1182,7 +1182,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); - if (land.LandData.OwnerID != m_host.ObjectOwner) + if (land.LandData.OwnerID != m_host.OwnerID) { OSSLError("osSetParcelSIPAddress: Sorry, you need to own the land to use this function"); return; -- cgit v1.1 From 5a4fda9dc3aca873bcf034877eed1f9c5914493f Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Fri, 16 Oct 2009 11:09:18 -0700 Subject: Updating OpenSim.ini.example with the section required to enable a useful prioritization scheme --- OpenSim/Region/Framework/Scenes/Scene.cs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index c7efc19..0d8c241 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -542,6 +542,8 @@ namespace OpenSim.Region.Framework.Scenes break; } } + + m_log.Info("[SCENE]: Using the " + m_update_prioritization_scheme + " prioritization scheme"); } catch { -- cgit v1.1 From a18489dc9badfccd775145f5a1a800a763d0c554 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Fri, 16 Oct 2009 12:20:01 -0700 Subject: * Change appearance packets from State to Task. This will hopefully fix the cloud issues * Changed the throttling logic to obey the requested client bandwidth limit but also share bandwidth between some of the categories to improve throughput on high prim or heavily trafficked regions --- .../Region/ClientStack/LindenUDP/LLClientView.cs | 2 +- .../Region/ClientStack/LindenUDP/LLUDPClient.cs | 79 ++++++++++++---------- .../Region/ClientStack/LindenUDP/LLUDPServer.cs | 2 +- 3 files changed, 46 insertions(+), 37 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 58fd2e7..630b6e6 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -3124,7 +3124,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP avp.Sender.IsTrial = false; avp.Sender.ID = agentID; - OutPacket(avp, ThrottleOutPacketType.State); + OutPacket(avp, ThrottleOutPacketType.Task); } public void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs) diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs index 4eee6b6..8c42ca4 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs @@ -170,7 +170,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP { ThrottleOutPacketType type = (ThrottleOutPacketType)i; + // Initialize the packet outboxes, where packets sit while they are waiting for tokens m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue(); + // Initialize the token buckets that control the throttling for each category m_throttleCategories[i] = new TokenBucket(m_throttle, rates.GetLimit(type), rates.GetRate(type)); } @@ -293,36 +295,54 @@ namespace OpenSim.Region.ClientStack.LindenUDP int state = (int)((float)task * STATE_TASK_PERCENTAGE); task -= state; - int ceiling = Int32.MaxValue; - if (m_defaultThrottleRates.Total != 0) - { - ceiling = m_defaultThrottleRates.Total; - if (ceiling < Packet.MTU) ceiling = Packet.MTU; - } - - resend = Utils.Clamp(resend, Packet.MTU, ceiling); - land = Utils.Clamp(land, Packet.MTU, ceiling); - wind = Utils.Clamp(wind, Packet.MTU, ceiling); - cloud = Utils.Clamp(cloud, Packet.MTU, ceiling); - task = Utils.Clamp(task, Packet.MTU, ceiling); - texture = Utils.Clamp(texture, Packet.MTU, ceiling); - asset = Utils.Clamp(asset, Packet.MTU, ceiling); - state = Utils.Clamp(state, Packet.MTU, ceiling); + // Make sure none of the throttles are set below our packet MTU, + // otherwise a throttle could become permanently clogged + resend = Math.Max(resend, Packet.MTU); + land = Math.Max(land, Packet.MTU); + wind = Math.Max(wind, Packet.MTU); + cloud = Math.Max(cloud, Packet.MTU); + task = Math.Max(task, Packet.MTU); + texture = Math.Max(texture, Packet.MTU); + asset = Math.Max(asset, Packet.MTU); + state = Math.Max(state, Packet.MTU); int total = resend + land + wind + cloud + task + texture + asset + state; - int taskTotal = task + state; m_log.DebugFormat("[LLUDPCLIENT]: {0} is setting throttles. Resend={1}, Land={2}, Wind={3}, Cloud={4}, Task={5}, Texture={6}, Asset={7}, State={8}, Total={9}", AgentID, resend, land, wind, cloud, task, texture, asset, state, total); - SetThrottle(ThrottleOutPacketType.Resend, resend, resend); - SetThrottle(ThrottleOutPacketType.Land, land, land); - SetThrottle(ThrottleOutPacketType.Wind, wind, wind); - SetThrottle(ThrottleOutPacketType.Cloud, cloud, cloud); - SetThrottle(ThrottleOutPacketType.Task, task, taskTotal); - SetThrottle(ThrottleOutPacketType.Texture, texture, texture); - SetThrottle(ThrottleOutPacketType.Asset, asset, asset); - SetThrottle(ThrottleOutPacketType.State, state, taskTotal); + // Update the token buckets with new throttle values + TokenBucket bucket; + + bucket = m_throttle; + bucket.MaxBurst = total; + + bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend]; + bucket.DripRate = bucket.MaxBurst = resend; + + bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land]; + bucket.DripRate = bucket.MaxBurst = land; + + bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind]; + bucket.DripRate = bucket.MaxBurst = wind; + + bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud]; + bucket.DripRate = bucket.MaxBurst = cloud; + + bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset]; + bucket.DripRate = bucket.MaxBurst = asset; + + bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task]; + bucket.DripRate = task + state + texture; + bucket.MaxBurst = task + state + texture; + + bucket = m_throttleCategories[(int)ThrottleOutPacketType.State]; + bucket.DripRate = state + texture; + bucket.MaxBurst = state + texture; + + bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture]; + bucket.DripRate = texture; + bucket.MaxBurst = texture; } public byte[] GetThrottlesPacked() @@ -342,17 +362,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP return data; } - public void SetThrottle(ThrottleOutPacketType category, int rate, int maxBurst) - { - int i = (int)category; - if (i >= 0 && i < m_throttleCategories.Length) - { - TokenBucket bucket = m_throttleCategories[(int)category]; - bucket.DripRate = rate; - bucket.MaxBurst = maxBurst; - } - } - public bool EnqueueOutgoing(OutgoingPacket packet) { int category = (int)packet.Category; diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 545a0bc..ee3e754 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -513,7 +513,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP IClientAPI client; if (!m_scene.ClientManager.TryGetValue(address, out client) || !(client is LLClientView)) { - m_log.Warn("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + + m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName + ", currently tracking " + m_scene.ClientManager.Count + " clients"); return; } -- cgit v1.1 From e776dfb1d71ea7f8de37399f84fceb005870e861 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Fri, 16 Oct 2009 13:22:45 -0700 Subject: * Changing the "clean dropped attachments" MySQL command to a using statement inside a try/catch. This statement times out for me very frequently * More verbose logging when zerocoding fails on an outbound packet --- OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index ee3e754..b11a80d 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -285,7 +285,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP // The packet grew larger than the bufferSize while zerocoding. // Remove the MSG_ZEROCODED flag and send the unencoded data // instead - m_log.Debug("[LLUDPSERVER]: Packet exceeded buffer size during zerocoding for " + type + ". Removing MSG_ZEROCODED flag"); + m_log.Debug("[LLUDPSERVER]: Packet exceeded buffer size during zerocoding for " + type + ". DataLength=" + dataLength + + " and BufferLength=" + buffer.Data.Length + ". Removing MSG_ZEROCODED flag"); data[0] = (byte)(data[0] & ~Helpers.MSG_ZEROCODED); Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); } -- cgit v1.1 From 1bd9202f2439ac73a70fa2a881f824797f61f589 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Fri, 16 Oct 2009 14:17:13 -0700 Subject: * Simplified the prioritization packet creation code to reduce CPU usage and increase throughput. Apologies to Jim for hacking on your code while it's only halfway done, I'll take responsibility for the manual merge * Changed LLUDP to use its own MTU value of 1400 instead of the 1200 value pulled from the currently shipped libomv --- .../Region/ClientStack/LindenUDP/LLClientView.cs | 101 ++++----------------- .../Region/ClientStack/LindenUDP/LLUDPClient.cs | 20 ++-- .../Region/ClientStack/LindenUDP/LLUDPServer.cs | 9 +- 3 files changed, 35 insertions(+), 95 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 630b6e6..383eac0 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -347,10 +347,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP protected Dictionary m_groupPowers = new Dictionary(); protected int m_terrainCheckerCount; - // LL uses these limits, apparently. Compressed terse would be 23, but we don't have that yet - protected int m_primTerseUpdatesPerPacket = 10; - protected int m_primFullUpdatesPerPacket = 14; - protected int m_avatarTerseUpdatesPerPacket = 5; + // These numbers are guesses at a decent tradeoff between responsiveness + // of the interest list and throughput. Lower is more responsive, higher + // is better throughput + protected int m_primTerseUpdatesPerPacket = 25; + protected int m_primFullUpdatesPerPacket = 100; + protected int m_avatarTerseUpdatesPerPacket = 10; /// Number of texture packets to put on the queue each time the /// OnQueueEmpty event is triggered for the texture category protected int m_textureSendLimit = 20; @@ -3415,33 +3417,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP terse.RegionData.TimeDilation = (ushort)(Scene.TimeDilation * ushort.MaxValue); - int max = m_avatarTerseUpdatesPerPacket; - if (max > m_avatarTerseUpdates.Count) - max = m_avatarTerseUpdates.Count; - - int count = 0; - int size = 0; - - byte[] zerobuffer = new byte[1024]; - byte[] blockbuffer = new byte[1024]; - - Queue updates = new Queue(); - - for (count = 0 ; count < max ; count++) - { - int length = 0; - m_avatarTerseUpdates.Peek().ToBytes(blockbuffer, ref length); - length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer); - if (size + length > Packet.MTU) - break; - size += length; - updates.Enqueue(m_avatarTerseUpdates.Dequeue()); - } + int count = Math.Min(m_avatarTerseUpdates.Count, m_avatarTerseUpdatesPerPacket); terse.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[count]; - - for (int i = 0 ; i < count ; i++) - terse.ObjectData[i] = updates.Dequeue(); + for (int i = 0; i < count; i++) + terse.ObjectData[i] = m_avatarTerseUpdates.Dequeue(); terse.Header.Reliable = false; terse.Header.Zerocoded = true; @@ -3656,34 +3636,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP outPacket.RegionData.TimeDilation = (ushort)(Scene.TimeDilation * ushort.MaxValue); - int max = m_primFullUpdates.Count; - if (max > m_primFullUpdatesPerPacket) - max = m_primFullUpdatesPerPacket; - - int count = 0; - int size = 0; + int count = Math.Min(m_primFullUpdates.Count, m_primFullUpdatesPerPacket); - byte[] zerobuffer = new byte[1024]; - byte[] blockbuffer = new byte[1024]; - - Queue updates = new Queue(); - - for (count = 0 ; count < max ; count++) - { - int length = 0; - m_primFullUpdates.Peek().ToBytes(blockbuffer, ref length); - length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer); - if (size + length > Packet.MTU) - break; - size += length; - updates.Enqueue(m_primFullUpdates.Dequeue()); - } - - outPacket.ObjectData = - new ObjectUpdatePacket.ObjectDataBlock[count]; - - for (int index = 0 ; index < count ; index++) - outPacket.ObjectData[index] = updates.Dequeue(); + outPacket.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[count]; + for (int i = 0; i < count; i++) + outPacket.ObjectData[i] = m_primFullUpdates.Dequeue(); outPacket.Header.Zerocoded = true; OutPacket(outPacket, ThrottleOutPacketType.State); @@ -3733,35 +3690,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP outPacket.RegionData.TimeDilation = (ushort)(Scene.TimeDilation * ushort.MaxValue); - int max = m_primTerseUpdates.Count; - if (max > m_primTerseUpdatesPerPacket) - max = m_primTerseUpdatesPerPacket; - - int count = 0; - int size = 0; - - byte[] zerobuffer = new byte[1024]; - byte[] blockbuffer = new byte[1024]; - - Queue updates = new Queue(); - - for (count = 0 ; count < max ; count++) - { - int length = 0; - m_primTerseUpdates.Peek().ToBytes(blockbuffer, ref length); - length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer); - if (size + length > Packet.MTU) - break; - size += length; - updates.Enqueue(m_primTerseUpdates.Dequeue()); - } - - outPacket.ObjectData = - new ImprovedTerseObjectUpdatePacket. - ObjectDataBlock[count]; + int count = Math.Min(m_primTerseUpdates.Count, m_primTerseUpdatesPerPacket); - for (int index = 0 ; index < count ; index++) - outPacket.ObjectData[index] = updates.Dequeue(); + outPacket.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[count]; + for (int i = 0; i < count; i++) + outPacket.ObjectData[i] = m_primTerseUpdates.Dequeue(); outPacket.Header.Reliable = false; outPacket.Header.Zerocoded = true; diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs index 8c42ca4..9476eed 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs @@ -297,14 +297,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Make sure none of the throttles are set below our packet MTU, // otherwise a throttle could become permanently clogged - resend = Math.Max(resend, Packet.MTU); - land = Math.Max(land, Packet.MTU); - wind = Math.Max(wind, Packet.MTU); - cloud = Math.Max(cloud, Packet.MTU); - task = Math.Max(task, Packet.MTU); - texture = Math.Max(texture, Packet.MTU); - asset = Math.Max(asset, Packet.MTU); - state = Math.Max(state, Packet.MTU); + resend = Math.Max(resend, LLUDPServer.MTU); + land = Math.Max(land, LLUDPServer.MTU); + wind = Math.Max(wind, LLUDPServer.MTU); + cloud = Math.Max(cloud, LLUDPServer.MTU); + task = Math.Max(task, LLUDPServer.MTU); + texture = Math.Max(texture, LLUDPServer.MTU); + asset = Math.Max(asset, LLUDPServer.MTU); + state = Math.Max(state, LLUDPServer.MTU); int total = resend + land + wind + cloud + task + texture + asset + state; @@ -404,9 +404,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP TokenBucket bucket; bool packetSent = false; + //string queueDebugOutput = String.Empty; // Serious debug business + for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) { bucket = m_throttleCategories[i]; + //queueDebugOutput += m_packetOutboxes[i].Count + " "; // Serious debug business if (m_nextPackets[i] != null) { @@ -458,6 +461,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } } + //m_log.Info("[LLUDPCLIENT]: Queues: " + queueDebugOutput); // Serious debug business return packetSent; } diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index b11a80d..f2b8720 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -89,6 +89,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// public class LLUDPServer : OpenSimUDPBase { + /// Maximum transmission unit, or UDP packet size, for the LLUDP protocol + public const int MTU = 1400; + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); /// Handlers for incoming packets @@ -272,7 +275,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP // The vast majority of packets are less than 200 bytes, although due to asset transfers and packet splitting // there are a decent number of packets in the 1000-1140 byte range. We allocate one of two sizes of data here // to accomodate for both common scenarios and provide ample room for ACK appending in both - int bufferSize = (dataLength > 180) ? Packet.MTU : 200; + int bufferSize = (dataLength > 180) ? LLUDPServer.MTU : 200; UDPPacketBuffer buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize); @@ -569,9 +572,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP // client.BytesSinceLastACK. Lockless thread safety int bytesSinceLastACK = Interlocked.Exchange(ref udpClient.BytesSinceLastACK, 0); bytesSinceLastACK += buffer.DataLength; - if (bytesSinceLastACK > Packet.MTU * 2) + if (bytesSinceLastACK > LLUDPServer.MTU * 2) { - bytesSinceLastACK -= Packet.MTU * 2; + bytesSinceLastACK -= LLUDPServer.MTU * 2; SendAcks(udpClient); } Interlocked.Add(ref udpClient.BytesSinceLastACK, bytesSinceLastACK); -- cgit v1.1 From 31dfe87570c952378060179139249af39290473f Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Fri, 16 Oct 2009 14:26:58 -0700 Subject: Prevent oversized packets from crashing the LLUDP server. It will now print a friendly error message and drop the packet --- .../Region/ClientStack/LindenUDP/LLUDPServer.cs | 25 +++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index f2b8720..8bfab6a 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -270,6 +270,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP { int dataLength = data.Length; bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0; + bool doCopy = true; // Frequency analysis of outgoing packet sizes shows a large clump of packets at each end of the spectrum. // The vast majority of packets are less than 200 bytes, although due to asset transfers and packet splitting @@ -282,7 +283,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Zerocode if needed if (doZerocode) { - try { dataLength = Helpers.ZeroEncode(data, dataLength, buffer.Data); } + try + { + dataLength = Helpers.ZeroEncode(data, dataLength, buffer.Data); + doCopy = false; + } catch (IndexOutOfRangeException) { // The packet grew larger than the bufferSize while zerocoding. @@ -291,18 +296,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_log.Debug("[LLUDPSERVER]: Packet exceeded buffer size during zerocoding for " + type + ". DataLength=" + dataLength + " and BufferLength=" + buffer.Data.Length + ". Removing MSG_ZEROCODED flag"); data[0] = (byte)(data[0] & ~Helpers.MSG_ZEROCODED); - Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); } } - else + + // If the packet data wasn't already copied during zerocoding, copy it now + if (doCopy) { - Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); + if (dataLength <= buffer.Data.Length) + { + Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); + } + else + { + m_log.Error("[LLUDPSERVER]: Packet exceeded buffer size! This could be an indication of packet assembly not obeying the MTU. Type=" + + type + ", DataLength=" + dataLength + ", BufferLength=" + buffer.Data.Length + ". Dropping packet"); + return; + } } + buffer.DataLength = dataLength; #region Queue or Send - // Look up the UDPClient this is going to OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category); if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) -- cgit v1.1 From 7d6d94a7b58c91ce2720d57235768813938efa85 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Fri, 16 Oct 2009 16:49:13 -0700 Subject: More debugging of RegionCombinerModule.RegionLoaded() by making RegionLoaded() a two line function --- OpenSim/Region/CoreModules/World/Land/RegionCombinerModule.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/CoreModules/World/Land/RegionCombinerModule.cs b/OpenSim/Region/CoreModules/World/Land/RegionCombinerModule.cs index 6499915..d8c5ed9 100644 --- a/OpenSim/Region/CoreModules/World/Land/RegionCombinerModule.cs +++ b/OpenSim/Region/CoreModules/World/Land/RegionCombinerModule.cs @@ -81,8 +81,12 @@ namespace OpenSim.Region.CoreModules.World.Land public void RegionLoaded(Scene scene) { - if (!enabledYN) - return; + if (enabledYN) + RegionLoadedDoWork(scene); + } + + private void RegionLoadedDoWork(Scene scene) + { /* // For testing on a single instance if (scene.RegionInfo.RegionLocX == 1004 && scene.RegionInfo.RegionLocY == 1000) -- cgit v1.1 From c81378dc22499ccb03f827e4821214ce7eb87dc1 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Fri, 16 Oct 2009 17:33:41 -0700 Subject: Changing avatar movement updates to the Task throttle category until we get finer grained prioritization of avatars vs. prims --- OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 383eac0..43c3c7c 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -3426,7 +3426,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP terse.Header.Reliable = false; terse.Header.Zerocoded = true; - OutPacket(terse, ThrottleOutPacketType.State); + OutPacket(terse, ThrottleOutPacketType.Task); } } @@ -3582,14 +3582,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP void HandleQueueEmpty(ThrottleOutPacketType queue) { + int count = 0; + switch (queue) { case ThrottleOutPacketType.Texture: ProcessTextureRequests(); break; - case ThrottleOutPacketType.State: - int count = 0; - + case ThrottleOutPacketType.Task: lock (m_avatarTerseUpdates.SyncRoot) count = m_avatarTerseUpdates.Count; if (count > 0) @@ -3597,7 +3597,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP ProcessAvatarTerseUpdates(); return; } - + break; + case ThrottleOutPacketType.State: lock (m_primFullUpdates.SyncRoot) count = m_primFullUpdates.Count; if (count > 0) -- cgit v1.1 From e28ac424861deafe6083b497b546cb64352f5512 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Sat, 17 Oct 2009 17:19:18 -0700 Subject: Wrapped the contents of the IncomingPacketHandler loop in a try/catch statement --- OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 8bfab6a..7a403aa 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -716,8 +716,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP while (base.IsRunning) { - if (packetInbox.Dequeue(100, ref incomingPacket)) - Util.FireAndForget(ProcessInPacket, incomingPacket); + try + { + if (packetInbox.Dequeue(100, ref incomingPacket)) + Util.FireAndForget(ProcessInPacket, incomingPacket); + } + catch (Exception ex) + { + m_log.Error("[LLUDPSERVER]: Error in the incoming packet handler loop: " + ex.Message, ex); + } } if (packetInbox.Count > 0) -- cgit v1.1 From fdb2a75ad357668b860fc5055e0630ef75a3ad20 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Sat, 17 Oct 2009 18:01:22 -0700 Subject: Committing the second part of Jim Greensky @ Intel Lab's patch, re-prioritizing updates --- .../Region/ClientStack/LindenUDP/LLClientView.cs | 107 ++++++++++++++++---- .../Region/Examples/SimpleModule/MyNpcCharacter.cs | 4 + OpenSim/Region/Framework/Scenes/Scene.cs | 13 +++ OpenSim/Region/Framework/Scenes/SceneGraph.cs | 2 +- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 112 ++++++++++++++++++++- .../Server/IRCClientView.cs | 5 + .../Region/OptionalModules/World/NPC/NPCAvatar.cs | 4 + 7 files changed, 227 insertions(+), 20 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 43c3c7c..3b2a604 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -3582,37 +3582,51 @@ namespace OpenSim.Region.ClientStack.LindenUDP void HandleQueueEmpty(ThrottleOutPacketType queue) { - int count = 0; - switch (queue) { case ThrottleOutPacketType.Texture: ProcessTextureRequests(); break; case ThrottleOutPacketType.Task: - lock (m_avatarTerseUpdates.SyncRoot) - count = m_avatarTerseUpdates.Count; - if (count > 0) + if (Monitor.TryEnter(m_avatarTerseUpdates.SyncRoot, 1)) { - ProcessAvatarTerseUpdates(); - return; + try + { + if (m_avatarTerseUpdates.Count > 0) + { + + ProcessAvatarTerseUpdates(); + return; + } + } + finally { Monitor.Exit(m_avatarTerseUpdates.SyncRoot); } } break; case ThrottleOutPacketType.State: - lock (m_primFullUpdates.SyncRoot) - count = m_primFullUpdates.Count; - if (count > 0) + if (Monitor.TryEnter(m_primFullUpdates.SyncRoot, 1)) { - ProcessPrimFullUpdates(); - return; + try + { + if (m_primFullUpdates.Count > 0) + { + ProcessPrimFullUpdates(); + return; + } + } + finally { Monitor.Exit(m_primFullUpdates.SyncRoot); } } - lock (m_primTerseUpdates.SyncRoot) - count = m_primTerseUpdates.Count; - if (count > 0) + if (Monitor.TryEnter(m_primTerseUpdates.SyncRoot, 1)) { - ProcessPrimTerseUpdates(); - return; + try + { + if (m_primTerseUpdates.Count > 0) + { + ProcessPrimTerseUpdates(); + return; + } + } + finally { Monitor.Exit(m_primTerseUpdates.SyncRoot); } } break; } @@ -3703,6 +3717,37 @@ namespace OpenSim.Region.ClientStack.LindenUDP } } + public void ReprioritizeUpdates(StateUpdateTypes type, UpdatePriorityHandler handler) + { + PriorityQueue.UpdatePriorityHandler terse_update_priority_handler = + delegate(ref double priority, uint local_id) + { + priority = handler(new UpdatePriorityData(priority, local_id)); + return priority != double.NaN; + }; + PriorityQueue.UpdatePriorityHandler update_priority_handler = + delegate(ref double priority, uint local_id) + { + priority = handler(new UpdatePriorityData(priority, local_id)); + return priority != double.NaN; + }; + + if ((type & StateUpdateTypes.AvatarTerse) != 0) { + lock (m_avatarTerseUpdates.SyncRoot) + m_avatarTerseUpdates.Reprioritize(terse_update_priority_handler); + } + + if ((type & StateUpdateTypes.PrimitiveFull) != 0) { + lock (m_primFullUpdates.SyncRoot) + m_primFullUpdates.Reprioritize(update_priority_handler); + } + + if ((type & StateUpdateTypes.PrimitiveTerse) != 0) { + lock (m_primTerseUpdates.SyncRoot) + m_primTerseUpdates.Reprioritize(terse_update_priority_handler); + } + } + public void FlushPrimUpdates() { while (m_primFullUpdates.Count > 0) @@ -10465,6 +10510,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP #region PriorityQueue private class PriorityQueue { + internal delegate bool UpdatePriorityHandler(ref TPriority priority, uint local_id); + private MinHeap[] heaps = new MinHeap[1]; private Dictionary lookup_table = new Dictionary(); private Comparison comparison; @@ -10539,6 +10586,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP throw new InvalidOperationException(string.Format("The {0} is empty", this.GetType().ToString())); } + internal void Reprioritize(UpdatePriorityHandler handler) + { + MinHeapItem item; + TPriority priority; + + foreach (LookupItem lookup in new List(this.lookup_table.Values)) + { + if (lookup.Heap.TryGetValue(lookup.Handle, out item)) + { + priority = item.Priority; + if (handler(ref priority, item.LocalID)) + { + if (lookup.Heap.ContainsHandle(lookup.Handle)) + lookup.Heap[lookup.Handle] = + new MinHeapItem(priority, item.Value, item.LocalID); + } + else + { + m_log.Warn("[LLClientView] UpdatePriorityHandle returned false, dropping update"); + lookup.Heap.Remove(lookup.Handle); + this.lookup_table.Remove(item.LocalID); + } + } + } + } + #region MinHeapItem private struct MinHeapItem : IComparable { diff --git a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs index 3799a02..5a5fcfe 100644 --- a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs +++ b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs @@ -527,6 +527,10 @@ namespace OpenSim.Region.Examples.SimpleModule { } + public virtual void ReprioritizeUpdates(StateUpdateTypes type, UpdatePriorityHandler handler) + { + } + public void FlushPrimUpdates() { } diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 49c1ebf..30fe976 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -278,6 +278,10 @@ namespace OpenSim.Region.Framework.Scenes private bool m_firstHeartbeat = true; private UpdatePrioritizationSchemes m_update_prioritization_scheme = UpdatePrioritizationSchemes.Time; + private bool m_reprioritization_enabled = true; + private double m_reprioritization_interval = 2000.0; + private double m_root_reprioritization_distance = 5.0; + private double m_child_reprioritization_distance = 10.0; private object m_deleting_scene_object = new object(); @@ -291,6 +295,10 @@ namespace OpenSim.Region.Framework.Scenes #region Properties public UpdatePrioritizationSchemes UpdatePrioritizationScheme { get { return this.m_update_prioritization_scheme; } } + public bool IsReprioritizationEnabled { get { return m_reprioritization_enabled; } } + public double ReprioritizationInterval { get { return m_reprioritization_interval; } } + public double RootReprioritizationDistance { get { return m_root_reprioritization_distance; } } + public double ChildReprioritizationDistance { get { return m_child_reprioritization_distance; } } public AgentCircuitManager AuthenticateHandler { @@ -542,6 +550,11 @@ namespace OpenSim.Region.Framework.Scenes m_update_prioritization_scheme = UpdatePrioritizationSchemes.Time; break; } + + m_reprioritization_enabled = interest_management_config.GetBoolean("ReprioritizationEnabled", true); + m_reprioritization_interval = interest_management_config.GetDouble("ReprioritizationInterval", 5000.0); + m_root_reprioritization_distance = interest_management_config.GetDouble("RootReprioritizationDistance", 10.0); + m_child_reprioritization_distance = interest_management_config.GetDouble("ChildReprioritizationDistance", 20.0); } m_log.Info("[SCENE]: Using the " + m_update_prioritization_scheme + " prioritization scheme"); diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index b9872ca..8ee26c3 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -846,7 +846,7 @@ namespace OpenSim.Region.Framework.Scenes /// /// /// null if no scene object group containing that prim is found - private SceneObjectGroup GetGroupByPrim(uint localID) + public SceneObjectGroup GetGroupByPrim(uint localID) { if (Entities.ContainsKey(localID)) return Entities[localID] as SceneObjectGroup; diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 9d13ad4..f05c3d8 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -28,6 +28,7 @@ using System; using System.Collections.Generic; using System.Reflection; +using System.Timers; using OpenMetaverse; using log4net; using OpenSim.Framework; @@ -172,6 +173,11 @@ namespace OpenSim.Region.Framework.Scenes // Position of agent's camera in world (region cordinates) protected Vector3 m_CameraCenter = Vector3.Zero; + protected Vector3 m_lastCameraCenter = Vector3.Zero; + + protected Timer m_reprioritization_timer; + protected bool m_reprioritizing = false; + protected bool m_reprioritization_called = false; // Use these three vectors to figure out what the agent is looking at // Convert it to a Matrix and/or Quaternion @@ -639,7 +645,14 @@ namespace OpenSim.Region.Framework.Scenes m_scriptEngines = m_scene.RequestModuleInterfaces(); - AbsolutePosition = m_controllingClient.StartPos; + AbsolutePosition = posLastSignificantMove = m_CameraCenter = + m_lastCameraCenter = m_controllingClient.StartPos; + + m_reprioritization_timer = new Timer(world.ReprioritizationInterval); + m_reprioritization_timer.Elapsed += new ElapsedEventHandler(Reprioritize); + m_reprioritization_timer.AutoReset = false; + + AdjustKnownSeeds(); TrySetMovementAnimation("STAND"); // TODO: I think, this won't send anything, as we are still a child here... @@ -1219,6 +1232,11 @@ namespace OpenSim.Region.Framework.Scenes // Camera location in world. We'll need to raytrace // from this location from time to time. m_CameraCenter = agentData.CameraCenter; + if (Vector3.Distance(m_lastCameraCenter, m_CameraCenter) >= Scene.RootReprioritizationDistance) + { + ReprioritizeUpdates(); + m_lastCameraCenter = m_CameraCenter; + } // Use these three vectors to figure out what the agent is looking at // Convert it to a Matrix and/or Quaternion @@ -2823,7 +2841,7 @@ namespace OpenSim.Region.Framework.Scenes } // Minimum Draw distance is 64 meters, the Radius of the draw distance sphere is 32m - if (Util.GetDistanceTo(AbsolutePosition,m_LastChildAgentUpdatePosition) > 32) + if (Util.GetDistanceTo(AbsolutePosition, m_LastChildAgentUpdatePosition) >= Scene.ChildReprioritizationDistance) { ChildAgentDataUpdate cadu = new ChildAgentDataUpdate(); cadu.ActiveGroupID = UUID.Zero.Guid; @@ -3118,6 +3136,12 @@ namespace OpenSim.Region.Framework.Scenes if (cAgentData.Position != new Vector3(-1, -1, -1)) // UGH!! m_pos = new Vector3(cAgentData.Position.X + shiftx, cAgentData.Position.Y + shifty, cAgentData.Position.Z); + if (Vector3.Distance(AbsolutePosition, posLastSignificantMove) >= Scene.ChildReprioritizationDistance) + { + posLastSignificantMove = AbsolutePosition; + ReprioritizeUpdates(); + } + // It's hard to say here.. We can't really tell where the camera position is unless it's in world cordinates from the sending region m_CameraCenter = cAgentData.Center; @@ -3498,6 +3522,16 @@ namespace OpenSim.Region.Framework.Scenes { m_knownChildRegions.Clear(); } + + lock (m_reprioritization_timer) + { + m_reprioritization_timer.Enabled = false; + m_reprioritization_timer.Elapsed -= new ElapsedEventHandler(Reprioritize); + } + // I don't get it but mono crashes when you try to dispose of this timer, + // unsetting the elapsed callback should be enough to allow for cleanup however. + //m_reprioritizationTimer.Dispose(); + m_sceneViewer.Close(); RemoveFromPhysicalScene(); @@ -3913,5 +3947,79 @@ namespace OpenSim.Region.Framework.Scenes { return Vector3.Distance(AbsolutePosition, position); } + + private double GetSOGUpdatePriority(SceneObjectGroup sog) + { + switch (Scene.UpdatePrioritizationScheme) + { + case Scene.UpdatePrioritizationSchemes.Time: + throw new InvalidOperationException("UpdatePrioritizationScheme for time not supported for reprioritization"); + case Scene.UpdatePrioritizationSchemes.Distance: + return sog.GetPriorityByDistance((IsChildAgent) ? AbsolutePosition : CameraPosition); + case Scene.UpdatePrioritizationSchemes.SimpleAngularDistance: + return sog.GetPriorityBySimpleAngularDistance((IsChildAgent) ? AbsolutePosition : CameraPosition); + default: + throw new InvalidOperationException("UpdatePrioritizationScheme not defined"); + } + } + + private double UpdatePriority(UpdatePriorityData data) + { + EntityBase entity; + SceneObjectGroup group; + + if (Scene.Entities.TryGetValue(data.localID, out entity)) + { + group = entity as SceneObjectGroup; + if (group != null) + return GetSOGUpdatePriority(group); + + ScenePresence presence = entity as ScenePresence; + if (presence == null) + throw new InvalidOperationException("entity found is neither SceneObjectGroup nor ScenePresence"); + switch (Scene.UpdatePrioritizationScheme) + { + case Scene.UpdatePrioritizationSchemes.Time: + throw new InvalidOperationException("UpdatePrioritization for time not supported for reprioritization"); + case Scene.UpdatePrioritizationSchemes.Distance: + case Scene.UpdatePrioritizationSchemes.SimpleAngularDistance: + return GetPriorityByDistance((IsChildAgent) ? AbsolutePosition : CameraPosition); + default: + throw new InvalidOperationException("UpdatePrioritizationScheme not defined"); + } + } + else + { + group = Scene.SceneGraph.GetGroupByPrim(data.localID); + if (group != null) + return GetSOGUpdatePriority(group); + } + return double.NaN; + } + + private void ReprioritizeUpdates() + { + if (Scene.IsReprioritizationEnabled && Scene.UpdatePrioritizationScheme != Scene.UpdatePrioritizationSchemes.Time) + { + lock (m_reprioritization_timer) + { + if (!m_reprioritizing) + m_reprioritization_timer.Enabled = m_reprioritizing = true; + else + m_reprioritization_called = true; + } + } + } + + private void Reprioritize(object sender, ElapsedEventArgs e) + { + m_controllingClient.ReprioritizeUpdates(StateUpdateTypes.All, UpdatePriority); + + lock (m_reprioritization_timer) + { + m_reprioritization_timer.Enabled = m_reprioritizing = m_reprioritization_called; + m_reprioritization_called = false; + } + } } } diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs index 1a24dec..df03b8d 100644 --- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs +++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs @@ -1048,6 +1048,11 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server } + public void ReprioritizeUpdates(StateUpdateTypes type, UpdatePriorityHandler handler) + { + + } + public void SendInventoryFolderDetails(UUID ownerID, UUID folderID, List items, List folders, bool fetchFolders, bool fetchItems) { diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs index 6c58f2d..f7cadaa 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs @@ -616,6 +616,10 @@ namespace OpenSim.Region.OptionalModules.World.NPC { } + public virtual void ReprioritizeUpdates(StateUpdateTypes type, UpdatePriorityHandler handler) + { + } + public void FlushPrimUpdates() { } -- cgit v1.1 From a3f93cffb4fb9cb9865fe5a1815c547fa02d092c Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Sat, 17 Oct 2009 22:06:36 -0700 Subject: * Committing Nini.dll with the patch from #3773 applied * Fixing a log message typo --- OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 3b2a604..2773a5e 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -10604,7 +10604,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } else { - m_log.Warn("[LLClientView] UpdatePriorityHandle returned false, dropping update"); + m_log.Warn("[LLCLIENTVIEW]: UpdatePriorityHandler returned false, dropping update"); lookup.Heap.Remove(lookup.Handle); this.lookup_table.Remove(item.LocalID); } -- cgit v1.1 From b4526a5a6d170e04655990c8edb8e355156a2061 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Sun, 18 Oct 2009 02:00:42 -0700 Subject: * Big performance increase in loading prims from the region database with MySQL * Handle the AgentFOV packet * Bypass queuing and throttles for ping checks to make ping times more closely match network latency * Only track reliable bytes in LLUDPCLient.BytesSinceLastACK --- .../Region/ClientStack/LindenUDP/LLClientView.cs | 24 +++++----- .../Region/ClientStack/LindenUDP/LLUDPServer.cs | 51 +++++++++++++++------- 2 files changed, 50 insertions(+), 25 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 2773a5e..b93e905 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -295,6 +295,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP public event MuteListRequest OnMuteListRequest; public event AvatarInterestUpdate OnAvatarInterestUpdate; public event PlacesQuery OnPlacesQuery; + public event AgentFOV OnAgentFOV; #endregion Events @@ -346,6 +347,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP protected ulong m_activeGroupPowers; protected Dictionary m_groupPowers = new Dictionary(); protected int m_terrainCheckerCount; + protected uint m_agentFOVCounter; // These numbers are guesses at a decent tradeoff between responsiveness // of the interest list and throughput. Lower is more responsive, higher @@ -8871,19 +8873,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP #endregion + case PacketType.AgentFOV: + AgentFOVPacket fovPacket = (AgentFOVPacket)Pack; - #region unimplemented handlers - - case PacketType.StartPingCheck: - StartPingCheckPacket pingStart = (StartPingCheckPacket)Pack; - CompletePingCheckPacket pingComplete = new CompletePingCheckPacket(); - pingComplete.PingID.PingID = pingStart.PingID.PingID; - m_udpServer.SendPacket(m_udpClient, pingComplete, ThrottleOutPacketType.Unknown, false); + if (fovPacket.FOVBlock.GenCounter > m_agentFOVCounter) + { + m_agentFOVCounter = fovPacket.FOVBlock.GenCounter; + AgentFOV handlerAgentFOV = OnAgentFOV; + if (handlerAgentFOV != null) + { + handlerAgentFOV(this, fovPacket.FOVBlock.VerticalAngle); + } + } break; - case PacketType.CompletePingCheck: - // TODO: Do stats tracking or something with these? - break; + #region unimplemented handlers case PacketType.ViewerStats: // TODO: handle this packet diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 7a403aa..4f3478b 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -572,6 +572,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP for (int i = 0; i < ackPacket.Packets.Length; i++) AcknowledgePacket(udpClient, ackPacket.Packets[i].ID, now, packet.Header.Resent); } + + // We don't need to do anything else with PacketAck packets + return; } #endregion ACK Receiving @@ -579,20 +582,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP #region ACK Sending if (packet.Header.Reliable) + { udpClient.PendingAcks.Enqueue(packet.Header.Sequence); - // This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out, - // add the current received bytes to it, test if 2*MTU bytes have been sent, if so remove - // 2*MTU bytes from the value and send ACKs, and finally add the local value back to - // client.BytesSinceLastACK. Lockless thread safety - int bytesSinceLastACK = Interlocked.Exchange(ref udpClient.BytesSinceLastACK, 0); - bytesSinceLastACK += buffer.DataLength; - if (bytesSinceLastACK > LLUDPServer.MTU * 2) - { - bytesSinceLastACK -= LLUDPServer.MTU * 2; - SendAcks(udpClient); + // This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out, + // add the current received bytes to it, test if 2*MTU bytes have been sent, if so remove + // 2*MTU bytes from the value and send ACKs, and finally add the local value back to + // client.BytesSinceLastACK. Lockless thread safety + int bytesSinceLastACK = Interlocked.Exchange(ref udpClient.BytesSinceLastACK, 0); + bytesSinceLastACK += buffer.DataLength; + if (bytesSinceLastACK > LLUDPServer.MTU * 2) + { + bytesSinceLastACK -= LLUDPServer.MTU * 2; + SendAcks(udpClient); + } + Interlocked.Add(ref udpClient.BytesSinceLastACK, bytesSinceLastACK); } - Interlocked.Add(ref udpClient.BytesSinceLastACK, bytesSinceLastACK); #endregion ACK Sending @@ -612,12 +617,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP #endregion Incoming Packet Accounting - // Don't bother clogging up the queue with PacketAck packets that are already handled here - if (packet.Type != PacketType.PacketAck) + #region Ping Check Handling + + if (packet.Type == PacketType.StartPingCheck) { - // Inbox insertion - packetInbox.Enqueue(new IncomingPacket(udpClient, packet)); + // We don't need to do anything else with ping checks + StartPingCheckPacket startPing = (StartPingCheckPacket)packet; + + CompletePingCheckPacket completePing = new CompletePingCheckPacket(); + completePing.PingID.PingID = startPing.PingID.PingID; + SendPacket(udpClient, completePing, ThrottleOutPacketType.Unknown, false); + return; } + else if (packet.Type == PacketType.CompletePingCheck) + { + // We don't currently track client ping times + return; + } + + #endregion Ping Check Handling + + // Inbox insertion + packetInbox.Enqueue(new IncomingPacket(udpClient, packet)); } protected override void PacketSent(UDPPacketBuffer buffer, int bytesSent) -- cgit v1.1 From 2f2eeb6731f4b692dafd17afa88019c24e361a36 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Sun, 18 Oct 2009 02:53:36 -0700 Subject: Zero out PrimitiveBaseShape.SculptData after the JPEG2000 data has been decoded to allow garbage collection on it --- OpenSim/Region/Physics/Meshing/Meshmerizer.cs | 3 +++ 1 file changed, 3 insertions(+) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs index 1ea08e2..f609e73 100644 --- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs +++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs @@ -289,6 +289,9 @@ namespace OpenSim.Region.Physics.Meshing ManagedImage managedImage; // we never use this OpenJPEG.DecodeToImage(primShape.SculptData, out managedImage, out idata); + // Remove the reference to the encoded JPEG2000 data so it can be GCed + primShape.SculptData = Utils.EmptyBytes; + if (cacheSculptMaps) { try { idata.Save(decodedSculptFileName, ImageFormat.MemoryBmp); } -- cgit v1.1 From 1dbbf6edb6c913697ac3248ef5b74c943a7a9c23 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Sun, 18 Oct 2009 03:15:36 -0700 Subject: * Process the avatar terse update priority queue as soon as an update for our own avatar is ready to send * Reduce the scope of the locks when processing the update queues * Reuse the ImprovedTerseObjectUpdate.RegionData block --- .../Region/ClientStack/LindenUDP/LLClientView.cs | 79 +++++++++++----------- 1 file changed, 39 insertions(+), 40 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index b93e905..83a7184 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -3402,34 +3402,37 @@ namespace OpenSim.Region.ClientStack.LindenUDP ImprovedTerseObjectUpdatePacket.ObjectDataBlock terseBlock = CreateAvatarImprovedBlock(data.localID, data.position, data.velocity, rotation); - + lock (m_avatarTerseUpdates.SyncRoot) m_avatarTerseUpdates.Enqueue(data.priority, terseBlock, data.localID); + + // If we received an update about our own avatar, process the avatar update priority queue immediately + if (data.agentid == m_agentId) + ProcessAvatarTerseUpdates(); } private void ProcessAvatarTerseUpdates() { - lock (m_avatarTerseUpdates.SyncRoot) - { - ImprovedTerseObjectUpdatePacket terse = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); + ImprovedTerseObjectUpdatePacket terse = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); + terse.Header.Reliable = false; + terse.Header.Zerocoded = true; - terse.RegionData = new ImprovedTerseObjectUpdatePacket.RegionDataBlock(); - - terse.RegionData.RegionHandle = Scene.RegionInfo.RegionHandle; - terse.RegionData.TimeDilation = - (ushort)(Scene.TimeDilation * ushort.MaxValue); + //terse.RegionData = new ImprovedTerseObjectUpdatePacket.RegionDataBlock(); + terse.RegionData.RegionHandle = Scene.RegionInfo.RegionHandle; + terse.RegionData.TimeDilation = (ushort)(Scene.TimeDilation * ushort.MaxValue); + lock (m_avatarTerseUpdates.SyncRoot) + { int count = Math.Min(m_avatarTerseUpdates.Count, m_avatarTerseUpdatesPerPacket); + if (count == 0) + return; terse.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[count]; for (int i = 0; i < count; i++) terse.ObjectData[i] = m_avatarTerseUpdates.Dequeue(); - - terse.Header.Reliable = false; - terse.Header.Zerocoded = true; - - OutPacket(terse, ThrottleOutPacketType.Task); } + + OutPacket(terse, ThrottleOutPacketType.Task); } public void SendCoarseLocationUpdate(List users, List CoarseLocations) @@ -3642,26 +3645,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP void ProcessPrimFullUpdates() { - lock (m_primFullUpdates.SyncRoot) - { - ObjectUpdatePacket outPacket = - (ObjectUpdatePacket)PacketPool.Instance.GetPacket( - PacketType.ObjectUpdate); + ObjectUpdatePacket outPacket = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate); + outPacket.Header.Zerocoded = true; - outPacket.RegionData.RegionHandle = - Scene.RegionInfo.RegionHandle; - outPacket.RegionData.TimeDilation = - (ushort)(Scene.TimeDilation * ushort.MaxValue); + //outPacket.RegionData = new ObjectUpdatePacket.RegionDataBlock(); + outPacket.RegionData.RegionHandle = Scene.RegionInfo.RegionHandle; + outPacket.RegionData.TimeDilation = (ushort)(Scene.TimeDilation * ushort.MaxValue); + lock (m_primFullUpdates.SyncRoot) + { int count = Math.Min(m_primFullUpdates.Count, m_primFullUpdatesPerPacket); + if (count == 0) + return; outPacket.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[count]; for (int i = 0; i < count; i++) outPacket.ObjectData[i] = m_primFullUpdates.Dequeue(); - - outPacket.Header.Zerocoded = true; - OutPacket(outPacket, ThrottleOutPacketType.State); } + + OutPacket(outPacket, ThrottleOutPacketType.State); } /// @@ -3695,28 +3697,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP void ProcessPrimTerseUpdates() { - lock (m_primTerseUpdates.SyncRoot) - { - ImprovedTerseObjectUpdatePacket outPacket = - (ImprovedTerseObjectUpdatePacket) - PacketPool.Instance.GetPacket( - PacketType.ImprovedTerseObjectUpdate); + ImprovedTerseObjectUpdatePacket outPacket = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); + outPacket.Header.Reliable = false; + outPacket.Header.Zerocoded = true; - outPacket.RegionData.RegionHandle = - Scene.RegionInfo.RegionHandle; - outPacket.RegionData.TimeDilation = - (ushort)(Scene.TimeDilation * ushort.MaxValue); + outPacket.RegionData.RegionHandle = Scene.RegionInfo.RegionHandle; + outPacket.RegionData.TimeDilation = (ushort)(Scene.TimeDilation * ushort.MaxValue); + lock (m_primTerseUpdates.SyncRoot) + { int count = Math.Min(m_primTerseUpdates.Count, m_primTerseUpdatesPerPacket); + if (count == 0) + return; outPacket.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[count]; for (int i = 0; i < count; i++) outPacket.ObjectData[i] = m_primTerseUpdates.Dequeue(); - - outPacket.Header.Reliable = false; - outPacket.Header.Zerocoded = true; - OutPacket(outPacket, ThrottleOutPacketType.State); } + + OutPacket(outPacket, ThrottleOutPacketType.State); } public void ReprioritizeUpdates(StateUpdateTypes type, UpdatePriorityHandler handler) -- cgit v1.1 From baed19d0688fe03fe8fba233bc6bd8306c71779f Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 18 Oct 2009 16:48:44 -0700 Subject: A bit of instrumentation to figure out what's going on with physics actors. --- OpenSim/Region/Physics/OdePlugin/ODECharacter.cs | 9 ++++++++- OpenSim/Region/Physics/OdePlugin/OdePlugin.cs | 6 ++++++ 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs index 1fff846..ef0e56e 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs @@ -139,8 +139,14 @@ namespace OpenSim.Region.Physics.OdePlugin public int m_eventsubscription = 0; private CollisionEventUpdate CollisionEventsThisFrame = new CollisionEventUpdate(); + // unique UUID of this character object + public UUID m_uuid; + public bool bad = false; + public OdeCharacter(String avName, OdeScene parent_scene, PhysicsVector pos, CollisionLocker dode, PhysicsVector size, float pid_d, float pid_p, float capsule_radius, float tensor, float density, float height_fudge_factor, float walk_divisor, float rundivisor) { + m_uuid = UUID.Random(); + // ode = dode; _velocity = new PhysicsVector(); _target_velocity = new PhysicsVector(); @@ -1112,10 +1118,11 @@ namespace OpenSim.Region.Physics.OdePlugin } catch (NullReferenceException) { + bad = true; _parent_scene.BadCharacter(this); vec = new d.Vector3(_position.X, _position.Y, _position.Z); base.RaiseOutOfBounds(_position); // Tells ScenePresence that there's a problem! - m_log.WarnFormat("[ODEPLUGIN]: Avatar Null reference for Avatar: {0}", m_name); + m_log.WarnFormat("[ODEPLUGIN]: Avatar Null reference for Avatar {0}, physical actor {1}", m_name, m_uuid); } diff --git a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs index 0e03e81..7187fbe 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs @@ -1664,6 +1664,8 @@ namespace OpenSim.Region.Physics.OdePlugin if (!_characters.Contains(chr)) { _characters.Add(chr); + if (chr.bad) + m_log.DebugFormat("[PHYSICS] Added BAD actor {0} to characters list", chr.m_uuid); } } } @@ -2581,7 +2583,11 @@ namespace OpenSim.Region.Physics.OdePlugin lock (_taintedActors) { if (!(_taintedActors.Contains(taintedchar))) + { _taintedActors.Add(taintedchar); + if (taintedchar.bad) + m_log.DebugFormat("[PHYSICS]: Added BAD actor {0} to tainted actors", taintedchar.m_uuid); + } } } } -- cgit v1.1 From 233e16b99cc80190d41143ecdfe01308eb39932a Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Sun, 18 Oct 2009 20:24:20 -0700 Subject: * Rewrote the methods that build ObjectUpdate and ImprovedTerseObjectUpdate packets to fill in the data more accurately and avoid allocating memory that is immediately thrown away * Changed the Send*Data structs in IClientAPI to use public readonly members instead of private members and getters * Made Parallel.ProcessorCount public * Started switching over packet building methods in LLClientView to use Util.StringToBytes[256/1024]() instead of Utils.StringToBytes() * More cleanup of the ScenePresences vs. ClientManager nightmare * ScenePresence.HandleAgentUpdate() will now time out and drop incoming AgentUpdate packets after three seconds. This fixes a deadlock on m_AgentUpdates that was blocking up the LLUDP server --- .../Region/ClientStack/LindenUDP/LLClientView.cs | 1015 +++++++------------- .../Region/ClientStack/LindenUDP/LLUDPServer.cs | 4 +- OpenSim/Region/Framework/Scenes/Scene.cs | 35 +- OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 6 +- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 22 +- 5 files changed, 398 insertions(+), 684 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 83a7184..1c463ea 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -342,7 +342,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP protected Thread m_clientThread; protected Vector3 m_startpos; protected EndPoint m_userEndPoint; - protected UUID m_activeGroupID = UUID.Zero; + protected UUID m_activeGroupID; protected string m_activeGroupName = String.Empty; protected ulong m_activeGroupPowers; protected Dictionary m_groupPowers = new Dictionary(); @@ -422,7 +422,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_hyperAssets = m_scene.RequestModuleInterface(); m_GroupsModule = scene.RequestModuleInterface(); m_imageManager = new LLImageManager(this, m_assetService, Scene.RequestModuleInterface()); - m_channelVersion = Utils.StringToBytes(scene.GetSimulatorVersion()); + m_channelVersion = Util.StringToBytes256(scene.GetSimulatorVersion()); m_agentId = agentId; m_sessionId = sessionId; m_secureSessionId = sessionInfo.LoginInfo.SecureSession; @@ -498,7 +498,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP kupack.UserInfo.SessionID = SessionId; kupack.TargetBlock.TargetIP = 0; kupack.TargetBlock.TargetPort = 0; - kupack.UserInfo.Reason = Utils.StringToBytes(message); + kupack.UserInfo.Reason = Util.StringToBytes256(message); OutPacket(kupack, ThrottleOutPacketType.Task); // You must sleep here or users get no message! Thread.Sleep(500); @@ -643,7 +643,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP handshake.RegionInfo.WaterHeight = args.waterHeight; handshake.RegionInfo.RegionFlags = args.regionFlags; - handshake.RegionInfo.SimName = Utils.StringToBytes(args.regionName); + handshake.RegionInfo.SimName = Util.StringToBytes256(args.regionName); handshake.RegionInfo.SimOwner = args.SimOwner; handshake.RegionInfo.TerrainBase0 = args.terrainBase0; handshake.RegionInfo.TerrainBase1 = args.terrainBase1; @@ -699,11 +699,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP { ChatFromSimulatorPacket reply = (ChatFromSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.ChatFromSimulator); reply.ChatData.Audible = audible; - reply.ChatData.Message = Utils.StringToBytes(message); + reply.ChatData.Message = Util.StringToBytes1024(message); reply.ChatData.ChatType = type; reply.ChatData.SourceType = source; reply.ChatData.Position = fromPos; - reply.ChatData.FromName = Utils.StringToBytes(fromName); + reply.ChatData.FromName = Util.StringToBytes256(fromName); reply.ChatData.OwnerID = fromAgentID; reply.ChatData.SourceID = fromAgentID; @@ -724,7 +724,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP msg.AgentData.AgentID = new UUID(im.fromAgentID); msg.AgentData.SessionID = UUID.Zero; - msg.MessageBlock.FromAgentName = Utils.StringToBytes(im.fromAgentName); + msg.MessageBlock.FromAgentName = Util.StringToBytes256(im.fromAgentName); msg.MessageBlock.Dialog = im.dialog; msg.MessageBlock.FromGroup = im.fromGroup; if (im.imSessionID == UUID.Zero.Guid) @@ -737,12 +737,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP msg.MessageBlock.RegionID = new UUID(im.RegionID); msg.MessageBlock.Timestamp = im.timestamp; msg.MessageBlock.ToAgentID = new UUID(im.toAgentID); - // Cap the message length at 1099. There is a limit in ImprovedInstantMessagePacket - // the limit is 1100 but a 0 byte gets added to mark the end of the string - if (im.message != null && im.message.Length > 1099) - msg.MessageBlock.Message = Utils.StringToBytes(im.message.Substring(0, 1099)); - else - msg.MessageBlock.Message = Utils.StringToBytes(im.message); + msg.MessageBlock.Message = Util.StringToBytes1024(im.message); msg.MessageBlock.BinaryBucket = im.binaryBucket; if (im.message.StartsWith("[grouptest]")) @@ -760,7 +755,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP eq.ChatterboxInvitation( new UUID("00000000-68f9-1111-024e-222222111123"), "OpenSimulator Testing", new UUID(im.fromAgentID), im.message, new UUID(im.toAgentID), im.fromAgentName, im.dialog, 0, - false, 0, new Vector3(), 1, new UUID(im.imSessionID), im.fromGroup, Utils.StringToBytes("OpenSimulator Testing")); + false, 0, new Vector3(), 1, new UUID(im.imSessionID), im.fromGroup, Util.StringToBytes256("OpenSimulator Testing")); eq.ChatterBoxSessionAgentListUpdates( new UUID("00000000-68f9-1111-024e-222222111123"), @@ -777,13 +772,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP public void SendGenericMessage(string method, List message) { GenericMessagePacket gmp = new GenericMessagePacket(); - gmp.MethodData.Method = Utils.StringToBytes(method); + gmp.MethodData.Method = Util.StringToBytes256(method); gmp.ParamList = new GenericMessagePacket.ParamListBlock[message.Count]; int i = 0; foreach (string val in message) { gmp.ParamList[i] = new GenericMessagePacket.ParamListBlock(); - gmp.ParamList[i++].Parameter = Utils.StringToBytes(val); + gmp.ParamList[i++].Parameter = Util.StringToBytes256(val); } OutPacket(gmp, ThrottleOutPacketType.Task); } @@ -1047,7 +1042,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP newSimPack.RegionData.SimIP += (uint)byteIP[1] << 8; newSimPack.RegionData.SimIP += (uint)byteIP[0]; newSimPack.RegionData.SimPort = (ushort)externalIPEndPoint.Port; - newSimPack.RegionData.SeedCapability = Utils.StringToBytes(capsURL); + newSimPack.RegionData.SeedCapability = Util.StringToBytes256(capsURL); // Hack to get this out immediately and skip throttles OutPacket(newSimPack, ThrottleOutPacketType.Unknown); @@ -1125,7 +1120,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP teleport.Info.RegionHandle = regionHandle; teleport.Info.SimAccess = simAccess; - teleport.Info.SeedCapability = Utils.StringToBytes(capsURL); + teleport.Info.SeedCapability = Util.StringToBytes256(capsURL); IPAddress oIP = newRegionEndPoint.Address; byte[] byteIP = oIP.GetAddressBytes(); @@ -1150,7 +1145,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP { TeleportFailedPacket tpFailed = (TeleportFailedPacket)PacketPool.Instance.GetPacket(PacketType.TeleportFailed); tpFailed.Info.AgentID = AgentId; - tpFailed.Info.Reason = Utils.StringToBytes(reason); + tpFailed.Info.Reason = Util.StringToBytes256(reason); tpFailed.AlertInfo = new TeleportFailedPacket.AlertInfoBlock[0]; // Hack to get this out immediately and skip throttles @@ -1882,11 +1877,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP AgentDataUpdatePacket sendAgentDataUpdate = (AgentDataUpdatePacket)PacketPool.Instance.GetPacket(PacketType.AgentDataUpdate); sendAgentDataUpdate.AgentData.ActiveGroupID = activegroupid; sendAgentDataUpdate.AgentData.AgentID = agentid; - sendAgentDataUpdate.AgentData.FirstName = Utils.StringToBytes(firstname); - sendAgentDataUpdate.AgentData.GroupName = Utils.StringToBytes(groupname); + sendAgentDataUpdate.AgentData.FirstName = Util.StringToBytes256(firstname); + sendAgentDataUpdate.AgentData.GroupName = Util.StringToBytes256(groupname); sendAgentDataUpdate.AgentData.GroupPowers = grouppowers; - sendAgentDataUpdate.AgentData.GroupTitle = Utils.StringToBytes(grouptitle); - sendAgentDataUpdate.AgentData.LastName = Utils.StringToBytes(lastname); + sendAgentDataUpdate.AgentData.GroupTitle = Util.StringToBytes256(grouptitle); + sendAgentDataUpdate.AgentData.LastName = Util.StringToBytes256(lastname); OutPacket(sendAgentDataUpdate, ThrottleOutPacketType.Task); } @@ -1899,7 +1894,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP { AlertMessagePacket alertPack = (AlertMessagePacket)PacketPool.Instance.GetPacket(PacketType.AlertMessage); alertPack.AlertData = new AlertMessagePacket.AlertDataBlock(); - alertPack.AlertData.Message = Utils.StringToBytes(message); + alertPack.AlertData.Message = Util.StringToBytes256(message); alertPack.AlertInfo = new AlertMessagePacket.AlertInfoBlock[0]; OutPacket(alertPack, ThrottleOutPacketType.Task); } @@ -1926,7 +1921,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP { AgentAlertMessagePacket alertPack = (AgentAlertMessagePacket)PacketPool.Instance.GetPacket(PacketType.AgentAlertMessage); alertPack.AgentData.AgentID = AgentId; - alertPack.AlertData.Message = Utils.StringToBytes(message); + alertPack.AlertData.Message = Util.StringToBytes256(message); alertPack.AlertData.Modal = modal; return alertPack; @@ -1936,12 +1931,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP string url) { LoadURLPacket loadURL = (LoadURLPacket)PacketPool.Instance.GetPacket(PacketType.LoadURL); - loadURL.Data.ObjectName = Utils.StringToBytes(objectname); + loadURL.Data.ObjectName = Util.StringToBytes256(objectname); loadURL.Data.ObjectID = objectID; loadURL.Data.OwnerID = ownerID; loadURL.Data.OwnerIsGroup = groupOwned; - loadURL.Data.Message = Utils.StringToBytes(message); - loadURL.Data.URL = Utils.StringToBytes(url); + loadURL.Data.Message = Util.StringToBytes256(message); + loadURL.Data.URL = Util.StringToBytes256(url); OutPacket(loadURL, ThrottleOutPacketType.Task); } @@ -1949,18 +1944,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP { ScriptDialogPacket dialog = (ScriptDialogPacket)PacketPool.Instance.GetPacket(PacketType.ScriptDialog); dialog.Data.ObjectID = objectID; - dialog.Data.ObjectName = Utils.StringToBytes(objectname); + dialog.Data.ObjectName = Util.StringToBytes256(objectname); // this is the username of the *owner* - dialog.Data.FirstName = Utils.StringToBytes(ownerFirstName); - dialog.Data.LastName = Utils.StringToBytes(ownerLastName); - dialog.Data.Message = Utils.StringToBytes(msg); + dialog.Data.FirstName = Util.StringToBytes256(ownerFirstName); + dialog.Data.LastName = Util.StringToBytes256(ownerLastName); + dialog.Data.Message = Util.StringToBytes1024(msg); dialog.Data.ImageID = textureID; dialog.Data.ChatChannel = ch; ScriptDialogPacket.ButtonsBlock[] buttons = new ScriptDialogPacket.ButtonsBlock[buttonlabels.Length]; for (int i = 0; i < buttonlabels.Length; i++) { buttons[i] = new ScriptDialogPacket.ButtonsBlock(); - buttons[i].ButtonLabel = Utils.StringToBytes(buttonlabels[i]); + buttons[i].ButtonLabel = Util.StringToBytes256(buttonlabels[i]); } dialog.Buttons = buttons; OutPacket(dialog, ThrottleOutPacketType.Task); @@ -2116,19 +2111,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP avatarReply.AgentData.AgentID = AgentId; avatarReply.AgentData.AvatarID = avatarID; if (aboutText != null) - avatarReply.PropertiesData.AboutText = Utils.StringToBytes(aboutText); + avatarReply.PropertiesData.AboutText = Util.StringToBytes1024(aboutText); else - avatarReply.PropertiesData.AboutText = Utils.StringToBytes(""); - avatarReply.PropertiesData.BornOn = Utils.StringToBytes(bornOn); + avatarReply.PropertiesData.AboutText = Utils.EmptyBytes; + avatarReply.PropertiesData.BornOn = Util.StringToBytes256(bornOn); avatarReply.PropertiesData.CharterMember = charterMember; if (flAbout != null) - avatarReply.PropertiesData.FLAboutText = Utils.StringToBytes(flAbout); + avatarReply.PropertiesData.FLAboutText = Util.StringToBytes256(flAbout); else - avatarReply.PropertiesData.FLAboutText = Utils.StringToBytes(""); + avatarReply.PropertiesData.FLAboutText = Utils.EmptyBytes; avatarReply.PropertiesData.Flags = flags; avatarReply.PropertiesData.FLImageID = flImageID; avatarReply.PropertiesData.ImageID = imageID; - avatarReply.PropertiesData.ProfileURL = Utils.StringToBytes(profileURL); + avatarReply.PropertiesData.ProfileURL = Util.StringToBytes256(profileURL); avatarReply.PropertiesData.PartnerID = partnerID; OutPacket(avatarReply, ThrottleOutPacketType.Task); } @@ -2255,7 +2250,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP Group.Contribution = GroupMembership[i].Contribution; Group.GroupID = GroupMembership[i].GroupID; Group.GroupInsigniaID = GroupMembership[i].GroupPicture; - Group.GroupName = Utils.StringToBytes(GroupMembership[i].GroupName); + Group.GroupName = Util.StringToBytes256(GroupMembership[i].GroupName); Group.GroupPowers = GroupMembership[i].GroupPowers; Groups[i] = Group; @@ -2289,7 +2284,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP UUIDGroupNameReplyPacket.UUIDNameBlockBlock[] uidnameblock = new UUIDGroupNameReplyPacket.UUIDNameBlockBlock[1]; UUIDGroupNameReplyPacket.UUIDNameBlockBlock uidnamebloc = new UUIDGroupNameReplyPacket.UUIDNameBlockBlock(); uidnamebloc.ID = groupLLUID; - uidnamebloc.GroupName = Utils.StringToBytes(GroupName); + uidnamebloc.GroupName = Util.StringToBytes256(GroupName); uidnameblock[0] = uidnamebloc; pack.UUIDNameBlock = uidnameblock; OutPacket(pack, ThrottleOutPacketType.Task); @@ -2314,8 +2309,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP lsrepdb.Score = lsrpia[i].Score; lsrepdb.TaskID = lsrpia[i].TaskID; lsrepdb.TaskLocalID = lsrpia[i].TaskLocalID; - lsrepdb.TaskName = Utils.StringToBytes(lsrpia[i].TaskName); - lsrepdb.OwnerName = Utils.StringToBytes(lsrpia[i].OwnerName); + lsrepdb.TaskName = Util.StringToBytes256(lsrpia[i].TaskName); + lsrepdb.OwnerName = Util.StringToBytes256(lsrpia[i].OwnerName); lsrepdba[i] = lsrepdb; } lsrp.ReportData = lsrepdba; @@ -3257,127 +3252,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP canUseImproved = false; } } - } - - static ObjectUpdatePacket.ObjectDataBlock BuildUpdateBlockFromPrim(SceneObjectPart prim, UUID assetID, PrimFlags flags, uint crc) - { - byte[] objectData = new byte[60]; - prim.OffsetPosition.ToBytes(objectData, 0); - prim.Velocity.ToBytes(objectData, 12); - prim.Acceleration.ToBytes(objectData, 24); - prim.RotationOffset.ToBytes(objectData, 36); - prim.AngularVelocity.ToBytes(objectData, 48); - - ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); - update.ClickAction = (byte)prim.ClickAction; - update.CRC = crc; - update.ExtraParams = prim.Shape.ExtraParams ?? Utils.EmptyBytes; - update.Flags = (byte)flags; - update.FullID = prim.UUID; - update.ID = prim.LocalId; - //update.JointAxisOrAnchor = Vector3.Zero; // These are deprecated - //update.JointPivot = Vector3.Zero; - //update.JointType = 0; - update.Material = prim.Material; - update.MediaURL = Utils.EmptyBytes; // FIXME: Support this in OpenSim - if (prim.IsAttachment) - update.NameValue = Util.StringToBytes256("AttachItemID STRING RW SV " + assetID); - else - update.NameValue = Utils.EmptyBytes; - update.ObjectData = objectData; - update.ParentID = prim.ParentID; - update.PathBegin = prim.Shape.PathBegin; - update.PathCurve = prim.Shape.PathCurve; - update.PathEnd = prim.Shape.PathEnd; - update.PathRadiusOffset = prim.Shape.PathRadiusOffset; - update.PathRevolutions = prim.Shape.PathRevolutions; - update.PathScaleX = prim.Shape.PathScaleX; - update.PathScaleY = prim.Shape.PathScaleY; - update.PathShearX = prim.Shape.PathShearX; - update.PathShearY = prim.Shape.PathShearY; - update.PathSkew = prim.Shape.PathSkew; - update.PathTaperX = prim.Shape.PathTaperX; - update.PathTaperY = prim.Shape.PathTaperY; - update.PathTwist = prim.Shape.PathTwist; - update.PathTwistBegin = prim.Shape.PathTwistBegin; - update.PCode = prim.Shape.PCode; - update.ProfileBegin = prim.Shape.ProfileBegin; - update.ProfileCurve = prim.Shape.ProfileCurve; - update.ProfileEnd = prim.Shape.ProfileEnd; - update.ProfileHollow = prim.Shape.ProfileHollow; - update.PSBlock = prim.ParticleSystem ?? Utils.EmptyBytes; - update.TextColor = new Color4(prim.Color).GetBytes(true); - update.TextureAnim = prim.TextureAnimation ?? Utils.EmptyBytes; - update.TextureEntry = prim.Shape.TextureEntry ?? Utils.EmptyBytes; - update.Scale = prim.Scale; - update.State = prim.Shape.State; - update.Text = Util.StringToBytes256(prim.Text); - update.UpdateFlags = (uint)flags; - - if (prim.Sound != UUID.Zero) - { - update.Sound = prim.Sound; - update.OwnerID = prim.OwnerID; - update.Gain = (float)prim.SoundGain; - update.Radius = (float)prim.SoundRadius; - } - - switch ((PCode)prim.Shape.PCode) - { - case PCode.Grass: - case PCode.Tree: - case PCode.NewTree: - update.Data = new byte[] { prim.Shape.State }; - break; - default: - // TODO: Support ScratchPad - //if (prim.ScratchPad != null) - //{ - // update.Data = new byte[prim.ScratchPad.Length]; - // Buffer.BlockCopy(prim.ScratchPad, 0, update.Data, 0, update.Data.Length); - //} - //else - //{ - // update.Data = Utils.EmptyBytes; - //} - update.Data = Utils.EmptyBytes; - break; - } - - return update; }*/ #endregion Prim/Avatar Updates - #region Avatar Packet/data sending Methods + #region Avatar Packet/Data Sending Methods /// - /// send a objectupdate packet with information about the clients avatar + /// Send an ObjectUpdate packet with information about an avatar /// public void SendAvatarData(SendAvatarData data) { ObjectUpdatePacket objupdate = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate); - // TODO: don't create new blocks if recycling an old packet - objupdate.RegionData.RegionHandle = data.regionHandle; + objupdate.Header.Zerocoded = true; + + objupdate.RegionData.RegionHandle = data.RegionHandle; objupdate.RegionData.TimeDilation = ushort.MaxValue; + objupdate.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1]; - objupdate.ObjectData[0] = CreateDefaultAvatarPacket(data.textureEntry); - - //give this avatar object a local id and assign the user a name - objupdate.ObjectData[0].ID = data.avatarLocalID; - objupdate.ObjectData[0].FullID = data.avatarID; - objupdate.ObjectData[0].ParentID = data.parentID; - objupdate.ObjectData[0].NameValue = - Utils.StringToBytes("FirstName STRING RW SV " + data.firstName + "\nLastName STRING RW SV " + data.lastName + "\nTitle STRING RW SV " + data.grouptitle); - - Vector3 pos2 = new Vector3(data.Pos.X, data.Pos.Y, data.Pos.Z); - byte[] pb = pos2.GetBytes(); - Array.Copy(pb, 0, objupdate.ObjectData[0].ObjectData, 16, pb.Length); - - byte[] rot = data.rotation.GetBytes(); - Array.Copy(rot, 0, objupdate.ObjectData[0].ObjectData, 52, rot.Length); + objupdate.ObjectData[0] = CreateAvatarUpdateBlock(data); - objupdate.Header.Zerocoded = true; OutPacket(objupdate, ThrottleOutPacketType.Task); } @@ -3387,27 +3281,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// public virtual void SendAvatarTerseUpdate(SendAvatarTerseData data) { - if (data.priority == double.NaN) + if (data.Priority == double.NaN) { m_log.Error("[LLClientView] SendAvatarTerseUpdate received a NaN priority, dropping update"); return; } - Quaternion rotation = data.rotation; + Quaternion rotation = data.Rotation; if (rotation.X == rotation.Y && rotation.Y == rotation.Z && - rotation.Z == rotation.W && rotation.W == 0) + rotation.Z == rotation.W && rotation.W == 0.0f) rotation = Quaternion.Identity; - ImprovedTerseObjectUpdatePacket.ObjectDataBlock terseBlock = - CreateAvatarImprovedBlock(data.localID, data.position, data.velocity, rotation); + ImprovedTerseObjectUpdatePacket.ObjectDataBlock terseBlock = CreateImprovedTerseBlock(data); lock (m_avatarTerseUpdates.SyncRoot) - m_avatarTerseUpdates.Enqueue(data.priority, terseBlock, data.localID); + m_avatarTerseUpdates.Enqueue(data.Priority, terseBlock, data.LocalID); // If we received an update about our own avatar, process the avatar update priority queue immediately - if (data.agentid == m_agentId) + if (data.AgentID == m_agentId) ProcessAvatarTerseUpdates(); } @@ -3471,33 +3364,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(loc, ThrottleOutPacketType.Task); } - #endregion + #endregion Avatar Packet/Data Sending Methods - #region Primitive Packet/data Sending Methods - - /// - /// - /// - /// - /// - /// - public void AttachObject(uint localID, Quaternion rotation, byte attachPoint, UUID ownerID) - { - if (attachPoint > 30 && ownerID != AgentId) // Someone else's HUD - return; - - ObjectAttachPacket attach = (ObjectAttachPacket)PacketPool.Instance.GetPacket(PacketType.ObjectAttach); - // TODO: don't create new blocks if recycling an old packet - attach.AgentData.AgentID = AgentId; - attach.AgentData.SessionID = m_sessionId; - attach.AgentData.AttachmentPoint = attachPoint; - attach.ObjectData = new ObjectAttachPacket.ObjectDataBlock[1]; - attach.ObjectData[0] = new ObjectAttachPacket.ObjectDataBlock(); - attach.ObjectData[0].ObjectLocalID = localID; - attach.ObjectData[0].Rotation = rotation; - attach.Header.Zerocoded = true; - OutPacket(attach, ThrottleOutPacketType.Task); - } + #region Primitive Packet/Data Sending Methods public void SendPrimitiveToClient(SendPrimitiveData data) { @@ -3513,136 +3382,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP return; if (data.primShape.PCode == 9 && data.primShape.State != 0 && data.parentID == 0) return; - + if (rotation.X == rotation.Y && rotation.Y == rotation.Z && rotation.Z == rotation.W && rotation.W == 0.0f) rotation = Quaternion.Identity; - ObjectUpdatePacket.ObjectDataBlock objectData = CreatePrimUpdateBlock(data.primShape, data.flags); - - objectData.ID = data.localID; - objectData.FullID = data.objectID; - objectData.OwnerID = data.ownerID; - - objectData.Text = Util.StringToBytes256(data.text); - objectData.TextColor[0] = data.color[0]; - objectData.TextColor[1] = data.color[1]; - objectData.TextColor[2] = data.color[2]; - objectData.TextColor[3] = data.color[3]; - objectData.ParentID = data.parentID; - objectData.PSBlock = data.particleSystem; - objectData.ClickAction = data.clickAction; - objectData.Material = data.material; - objectData.Flags = 0; - - if (data.attachment) - { - // Necessary??? - objectData.JointAxisOrAnchor = new Vector3(0, 0, 2); - objectData.JointPivot = new Vector3(0, 0, 0); - - // Item from inventory??? - objectData.NameValue = - Utils.StringToBytes("AttachItemID STRING RW SV " + data.AssetId.Guid); - objectData.State = (byte)((data.AttachPoint % 16) * 16 + (data.AttachPoint / 16)); - } - - // Xantor 20080528: Send sound info as well - // Xantor 20080530: Zero out everything if there's no SoundId, so zerocompression will work again - objectData.Sound = data.SoundId; - if (data.SoundId == UUID.Zero) - { - objectData.OwnerID = UUID.Zero; - objectData.Gain = 0.0f; - objectData.Radius = 0.0f; - objectData.Flags = 0; - } - else - { - objectData.OwnerID = data.ownerID; - objectData.Gain = (float)data.SoundVolume; - objectData.Radius = (float)data.SoundRadius; - objectData.Flags = data.SoundFlags; - } - - byte[] pb = data.pos.GetBytes(); - Buffer.BlockCopy(pb, 0, objectData.ObjectData, 0, pb.Length); - - byte[] vel = data.vel.GetBytes(); - Buffer.BlockCopy(vel, 0, objectData.ObjectData, pb.Length, vel.Length); - - byte[] rot = rotation.GetBytes(); - Buffer.BlockCopy(rot, 0, objectData.ObjectData, 36, rot.Length); - - byte[] rvel = data.rvel.GetBytes(); - Buffer.BlockCopy(rvel, 0, objectData.ObjectData, 36 + rot.Length, rvel.Length); - - if (data.textureanim.Length > 0) - { - objectData.TextureAnim = data.textureanim; - } + ObjectUpdatePacket.ObjectDataBlock objectData = CreatePrimUpdateBlock(data); lock (m_primFullUpdates.SyncRoot) m_primFullUpdates.Enqueue(data.priority, objectData, data.localID); } - void HandleQueueEmpty(ThrottleOutPacketType queue) - { - switch (queue) - { - case ThrottleOutPacketType.Texture: - ProcessTextureRequests(); - break; - case ThrottleOutPacketType.Task: - if (Monitor.TryEnter(m_avatarTerseUpdates.SyncRoot, 1)) - { - try - { - if (m_avatarTerseUpdates.Count > 0) - { - - ProcessAvatarTerseUpdates(); - return; - } - } - finally { Monitor.Exit(m_avatarTerseUpdates.SyncRoot); } - } - break; - case ThrottleOutPacketType.State: - if (Monitor.TryEnter(m_primFullUpdates.SyncRoot, 1)) - { - try - { - if (m_primFullUpdates.Count > 0) - { - ProcessPrimFullUpdates(); - return; - } - } - finally { Monitor.Exit(m_primFullUpdates.SyncRoot); } - } - - if (Monitor.TryEnter(m_primTerseUpdates.SyncRoot, 1)) - { - try - { - if (m_primTerseUpdates.Count > 0) - { - ProcessPrimTerseUpdates(); - return; - } - } - finally { Monitor.Exit(m_primTerseUpdates.SyncRoot); } - } - break; - } - } - - void ProcessTextureRequests() - { - if (m_imageManager != null) - m_imageManager.ProcessImageQueue(m_textureSendLimit); - } - void ProcessPrimFullUpdates() { ObjectUpdatePacket outPacket = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate); @@ -3666,33 +3415,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(outPacket, ThrottleOutPacketType.State); } - /// - /// - /// - //public void SendPrimTerseUpdate(ulong regionHandle, ushort timeDilation, uint localID, Vector3 position, - // Quaternion rotation, Vector3 velocity, Vector3 rotationalvelocity, byte state, UUID AssetId, UUID ownerID, int attachPoint) public void SendPrimTerseUpdate(SendPrimitiveTerseData data) { - if (data.priority == double.NaN) + if (data.Priority == double.NaN) { m_log.Error("[LLClientView] SendPrimTerseUpdate received a NaN priority, dropping update"); return; } - Quaternion rotation = data.rotation; + Quaternion rotation = data.Rotation; - if (data.attachPoint > 30 && data.owner != AgentId) // Someone else's HUD + if (data.AttachPoint > 30 && data.OwnerID != AgentId) // Someone else's HUD return; if (rotation.X == rotation.Y && rotation.Y == rotation.Z && rotation.Z == rotation.W && rotation.W == 0) rotation = Quaternion.Identity; - ImprovedTerseObjectUpdatePacket.ObjectDataBlock objectData = - CreatePrimImprovedBlock(data.localID, data.position, rotation, - data.velocity, data.rotationalvelocity, data.state); + ImprovedTerseObjectUpdatePacket.ObjectDataBlock objectData = CreateImprovedTerseBlock(data); lock (m_primTerseUpdates.SyncRoot) - m_primTerseUpdates.Enqueue(data.priority, objectData, data.localID); + m_primTerseUpdates.Enqueue(data.Priority, objectData, data.LocalID); } void ProcessPrimTerseUpdates() @@ -3733,17 +3475,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP return priority != double.NaN; }; - if ((type & StateUpdateTypes.AvatarTerse) != 0) { + if ((type & StateUpdateTypes.AvatarTerse) != 0) + { lock (m_avatarTerseUpdates.SyncRoot) m_avatarTerseUpdates.Reprioritize(terse_update_priority_handler); } - if ((type & StateUpdateTypes.PrimitiveFull) != 0) { + if ((type & StateUpdateTypes.PrimitiveFull) != 0) + { lock (m_primFullUpdates.SyncRoot) m_primFullUpdates.Reprioritize(update_priority_handler); } - if ((type & StateUpdateTypes.PrimitiveTerse) != 0) { + if ((type & StateUpdateTypes.PrimitiveTerse) != 0) + { lock (m_primTerseUpdates.SyncRoot) m_primTerseUpdates.Reprioritize(terse_update_priority_handler); } @@ -3765,6 +3510,90 @@ namespace OpenSim.Region.ClientStack.LindenUDP } } + #endregion Primitive Packet/Data Sending Methods + + /// + /// + /// + /// + /// + /// + public void AttachObject(uint localID, Quaternion rotation, byte attachPoint, UUID ownerID) + { + if (attachPoint > 30 && ownerID != AgentId) // Someone else's HUD + return; + + ObjectAttachPacket attach = (ObjectAttachPacket)PacketPool.Instance.GetPacket(PacketType.ObjectAttach); + // TODO: don't create new blocks if recycling an old packet + attach.AgentData.AgentID = AgentId; + attach.AgentData.SessionID = m_sessionId; + attach.AgentData.AttachmentPoint = attachPoint; + attach.ObjectData = new ObjectAttachPacket.ObjectDataBlock[1]; + attach.ObjectData[0] = new ObjectAttachPacket.ObjectDataBlock(); + attach.ObjectData[0].ObjectLocalID = localID; + attach.ObjectData[0].Rotation = rotation; + attach.Header.Zerocoded = true; + OutPacket(attach, ThrottleOutPacketType.Task); + } + + void HandleQueueEmpty(ThrottleOutPacketType queue) + { + switch (queue) + { + case ThrottleOutPacketType.Texture: + ProcessTextureRequests(); + break; + case ThrottleOutPacketType.Task: + if (Monitor.TryEnter(m_avatarTerseUpdates.SyncRoot, 1)) + { + try + { + if (m_avatarTerseUpdates.Count > 0) + { + + ProcessAvatarTerseUpdates(); + return; + } + } + finally { Monitor.Exit(m_avatarTerseUpdates.SyncRoot); } + } + break; + case ThrottleOutPacketType.State: + if (Monitor.TryEnter(m_primFullUpdates.SyncRoot, 1)) + { + try + { + if (m_primFullUpdates.Count > 0) + { + ProcessPrimFullUpdates(); + return; + } + } + finally { Monitor.Exit(m_primFullUpdates.SyncRoot); } + } + + if (Monitor.TryEnter(m_primTerseUpdates.SyncRoot, 1)) + { + try + { + if (m_primTerseUpdates.Count > 0) + { + ProcessPrimTerseUpdates(); + return; + } + } + finally { Monitor.Exit(m_primTerseUpdates.SyncRoot); } + } + break; + } + } + + void ProcessTextureRequests() + { + if (m_imageManager != null) + m_imageManager.ProcessImageQueue(m_textureSendLimit); + } + public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID) { AssetUploadCompletePacket newPack = new AssetUploadCompletePacket(); @@ -3946,8 +3775,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(proper, ThrottleOutPacketType.Task); } - #endregion - #region Estate Data Sending Methods private static bool convertParamStringToBool(byte[] field) @@ -4354,325 +4181,221 @@ namespace OpenSim.Region.ClientStack.LindenUDP #region Helper Methods - protected ImprovedTerseObjectUpdatePacket.ObjectDataBlock CreateAvatarImprovedBlock(uint localID, Vector3 pos, - Vector3 velocity, - Quaternion rotation) + protected ImprovedTerseObjectUpdatePacket.ObjectDataBlock CreateImprovedTerseBlock(SendAvatarTerseData data) { - byte[] bytes = new byte[60]; - int i = 0; - ImprovedTerseObjectUpdatePacket.ObjectDataBlock dat = PacketPool.GetDataBlock(); - - dat.TextureEntry = new byte[0]; // AvatarTemplate.TextureEntry; - - uint ID = localID; - - bytes[i++] = (byte)(ID % 256); - bytes[i++] = (byte)((ID >> 8) % 256); - bytes[i++] = (byte)((ID >> 16) % 256); - bytes[i++] = (byte)((ID >> 24) % 256); - bytes[i++] = 0; - bytes[i++] = 1; - i += 14; - bytes[i++] = 128; - bytes[i++] = 63; - - byte[] pb = pos.GetBytes(); - Array.Copy(pb, 0, bytes, i, pb.Length); - i += 12; - - Vector3 internDirec = new Vector3(velocity.X, velocity.Y, velocity.Z); - - internDirec = internDirec / 128.0f; - internDirec.X += 1; - internDirec.Y += 1; - internDirec.Z += 1; - - ushort InternVelocityX = (ushort)(32768 * internDirec.X); - ushort InternVelocityY = (ushort)(32768 * internDirec.Y); - ushort InternVelocityZ = (ushort)(32768 * internDirec.Z); - - ushort ac = 32767; - bytes[i++] = (byte)(InternVelocityX % 256); - bytes[i++] = (byte)((InternVelocityX >> 8) % 256); - bytes[i++] = (byte)(InternVelocityY % 256); - bytes[i++] = (byte)((InternVelocityY >> 8) % 256); - bytes[i++] = (byte)(InternVelocityZ % 256); - bytes[i++] = (byte)((InternVelocityZ >> 8) % 256); - - //accel - bytes[i++] = (byte)(ac % 256); - bytes[i++] = (byte)((ac >> 8) % 256); - bytes[i++] = (byte)(ac % 256); - bytes[i++] = (byte)((ac >> 8) % 256); - bytes[i++] = (byte)(ac % 256); - bytes[i++] = (byte)((ac >> 8) % 256); - - //rotation - ushort rw, rx, ry, rz; - rw = (ushort)(32768 * (rotation.W + 1)); - rx = (ushort)(32768 * (rotation.X + 1)); - ry = (ushort)(32768 * (rotation.Y + 1)); - rz = (ushort)(32768 * (rotation.Z + 1)); - - //rot - bytes[i++] = (byte)(rx % 256); - bytes[i++] = (byte)((rx >> 8) % 256); - bytes[i++] = (byte)(ry % 256); - bytes[i++] = (byte)((ry >> 8) % 256); - bytes[i++] = (byte)(rz % 256); - bytes[i++] = (byte)((rz >> 8) % 256); - bytes[i++] = (byte)(rw % 256); - bytes[i++] = (byte)((rw >> 8) % 256); - - //rotation vel - bytes[i++] = (byte)(ac % 256); - bytes[i++] = (byte)((ac >> 8) % 256); - bytes[i++] = (byte)(ac % 256); - bytes[i++] = (byte)((ac >> 8) % 256); - bytes[i++] = (byte)(ac % 256); - bytes[i++] = (byte)((ac >> 8) % 256); - - dat.Data = bytes; - - return (dat); + return CreateImprovedTerseBlock(true, data.LocalID, 0, data.CollisionPlane, data.Position, data.Velocity, + data.Acceleration, data.Rotation, Vector3.Zero, data.TextureEntry); } - /// - /// - /// - /// - /// - /// - /// - protected ImprovedTerseObjectUpdatePacket.ObjectDataBlock CreatePrimImprovedBlock(uint localID, - Vector3 position, - Quaternion rotation, - Vector3 velocity, - Vector3 rotationalvelocity, - byte state) + protected ImprovedTerseObjectUpdatePacket.ObjectDataBlock CreateImprovedTerseBlock(SendPrimitiveTerseData data) { - uint ID = localID; - byte[] bytes = new byte[60]; - - int i = 0; - ImprovedTerseObjectUpdatePacket.ObjectDataBlock dat = PacketPool.GetDataBlock(); - dat.TextureEntry = new byte[0]; - bytes[i++] = (byte)(ID % 256); - bytes[i++] = (byte)((ID >> 8) % 256); - bytes[i++] = (byte)((ID >> 16) % 256); - bytes[i++] = (byte)((ID >> 24) % 256); - bytes[i++] = (byte)(((state & 0xf0) >> 4) | ((state & 0x0f) << 4)); - bytes[i++] = 0; - - byte[] pb = position.GetBytes(); - Array.Copy(pb, 0, bytes, i, pb.Length); - i += 12; - ushort ac = 32767; - - ushort velx, vely, velz; - Vector3 vel = new Vector3(velocity.X, velocity.Y, velocity.Z); - - vel = vel / 128.0f; - vel.X += 1; - vel.Y += 1; - vel.Z += 1; - //vel - velx = (ushort)(32768 * (vel.X)); - vely = (ushort)(32768 * (vel.Y)); - velz = (ushort)(32768 * (vel.Z)); - - bytes[i++] = (byte)(velx % 256); - bytes[i++] = (byte)((velx >> 8) % 256); - bytes[i++] = (byte)(vely % 256); - bytes[i++] = (byte)((vely >> 8) % 256); - bytes[i++] = (byte)(velz % 256); - bytes[i++] = (byte)((velz >> 8) % 256); - - //accel - bytes[i++] = (byte)(ac % 256); - bytes[i++] = (byte)((ac >> 8) % 256); - bytes[i++] = (byte)(ac % 256); - bytes[i++] = (byte)((ac >> 8) % 256); - bytes[i++] = (byte)(ac % 256); - bytes[i++] = (byte)((ac >> 8) % 256); - - ushort rw, rx, ry, rz; - rw = (ushort)(32768 * (rotation.W + 1)); - rx = (ushort)(32768 * (rotation.X + 1)); - ry = (ushort)(32768 * (rotation.Y + 1)); - rz = (ushort)(32768 * (rotation.Z + 1)); - - //rot - bytes[i++] = (byte)(rx % 256); - bytes[i++] = (byte)((rx >> 8) % 256); - bytes[i++] = (byte)(ry % 256); - bytes[i++] = (byte)((ry >> 8) % 256); - bytes[i++] = (byte)(rz % 256); - bytes[i++] = (byte)((rz >> 8) % 256); - bytes[i++] = (byte)(rw % 256); - bytes[i++] = (byte)((rw >> 8) % 256); - - //rotation vel - Vector3 rvel = new Vector3(rotationalvelocity.X, rotationalvelocity.Y, rotationalvelocity.Z); - - rvel = rvel / 128.0f; - rvel.X += 1; - rvel.Y += 1; - rvel.Z += 1; - //vel - ushort rvelx = (ushort)(32768 * (rvel.X)); - ushort rvely = (ushort)(32768 * (rvel.Y)); - ushort rvelz = (ushort)(32768 * (rvel.Z)); - - bytes[i++] = (byte)(rvelx % 256); - bytes[i++] = (byte)((rvelx >> 8) % 256); - bytes[i++] = (byte)(rvely % 256); - bytes[i++] = (byte)((rvely >> 8) % 256); - bytes[i++] = (byte)(rvelz % 256); - bytes[i++] = (byte)((rvelz >> 8) % 256); - dat.Data = bytes; - - return dat; + return CreateImprovedTerseBlock(false, data.LocalID, data.State, Vector4.Zero, data.Position, data.Velocity, + data.Acceleration, data.Rotation, data.AngularVelocity, data.TextureEntry); } - /// - /// Create the ObjectDataBlock for a ObjectUpdatePacket (for a Primitive) - /// - /// - /// - protected ObjectUpdatePacket.ObjectDataBlock CreatePrimUpdateBlock(PrimitiveBaseShape primShape, uint flags) - { - ObjectUpdatePacket.ObjectDataBlock objupdate = PacketPool.GetDataBlock(); - SetDefaultPrimPacketValues(objupdate); - objupdate.UpdateFlags = flags; - SetPrimPacketShapeData(objupdate, primShape); - - if ((primShape.PCode == (byte)PCode.NewTree) || (primShape.PCode == (byte)PCode.Tree) || (primShape.PCode == (byte)PCode.Grass)) - { - objupdate.Data = new byte[1]; - objupdate.Data[0] = primShape.State; - } - return objupdate; - } - - protected void SetPrimPacketShapeData(ObjectUpdatePacket.ObjectDataBlock objectData, PrimitiveBaseShape primData) - { - objectData.TextureEntry = primData.TextureEntry; - objectData.PCode = primData.PCode; - objectData.State = primData.State; - objectData.PathBegin = primData.PathBegin; - objectData.PathEnd = primData.PathEnd; - objectData.PathScaleX = primData.PathScaleX; - objectData.PathScaleY = primData.PathScaleY; - objectData.PathShearX = primData.PathShearX; - objectData.PathShearY = primData.PathShearY; - objectData.PathSkew = primData.PathSkew; - objectData.ProfileBegin = primData.ProfileBegin; - objectData.ProfileEnd = primData.ProfileEnd; - objectData.Scale = primData.Scale; - objectData.PathCurve = primData.PathCurve; - objectData.ProfileCurve = primData.ProfileCurve; - objectData.ProfileHollow = primData.ProfileHollow; - objectData.PathRadiusOffset = primData.PathRadiusOffset; - objectData.PathRevolutions = primData.PathRevolutions; - objectData.PathTaperX = primData.PathTaperX; - objectData.PathTaperY = primData.PathTaperY; - objectData.PathTwist = primData.PathTwist; - objectData.PathTwistBegin = primData.PathTwistBegin; - objectData.ExtraParams = primData.ExtraParams; + protected ImprovedTerseObjectUpdatePacket.ObjectDataBlock CreateImprovedTerseBlock(bool avatar, uint localID, byte state, + Vector4 collisionPlane, Vector3 position, Vector3 velocity, Vector3 acceleration, Quaternion rotation, + Vector3 angularVelocity, byte[] textureEntry) + { + int pos = 0; + byte[] data = new byte[(avatar ? 60 : 44)]; + + // LocalID + Utils.UIntToBytes(localID, data, pos); + pos += 4; + + // Avatar/CollisionPlane + data[pos++] = state; + if (avatar) + { + data[pos++] = 1; + + if (collisionPlane == Vector4.Zero) + collisionPlane = Vector4.UnitW; + + collisionPlane.ToBytes(data, pos); + pos += 16; + } + else + { + ++pos; + } + + // Position + position.ToBytes(data, pos); + pos += 12; + + // Velocity + Utils.UInt16ToBytes(Utils.FloatToUInt16(velocity.X, -128.0f, 128.0f), data, pos); pos += 2; + Utils.UInt16ToBytes(Utils.FloatToUInt16(velocity.Y, -128.0f, 128.0f), data, pos); pos += 2; + Utils.UInt16ToBytes(Utils.FloatToUInt16(velocity.Z, -128.0f, 128.0f), data, pos); pos += 2; + + // Acceleration + Utils.UInt16ToBytes(Utils.FloatToUInt16(acceleration.X, -64.0f, 64.0f), data, pos); pos += 2; + Utils.UInt16ToBytes(Utils.FloatToUInt16(acceleration.Y, -64.0f, 64.0f), data, pos); pos += 2; + Utils.UInt16ToBytes(Utils.FloatToUInt16(acceleration.Z, -64.0f, 64.0f), data, pos); pos += 2; + + // Rotation + Utils.UInt16ToBytes(Utils.FloatToUInt16(rotation.X, -1.0f, 1.0f), data, pos); pos += 2; + Utils.UInt16ToBytes(Utils.FloatToUInt16(rotation.Y, -1.0f, 1.0f), data, pos); pos += 2; + Utils.UInt16ToBytes(Utils.FloatToUInt16(rotation.Z, -1.0f, 1.0f), data, pos); pos += 2; + Utils.UInt16ToBytes(Utils.FloatToUInt16(rotation.W, -1.0f, 1.0f), data, pos); pos += 2; + + // Angular Velocity + Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.X, -64.0f, 64.0f), data, pos); pos += 2; + Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Y, -64.0f, 64.0f), data, pos); pos += 2; + Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Z, -64.0f, 64.0f), data, pos); pos += 2; + + ImprovedTerseObjectUpdatePacket.ObjectDataBlock block = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock(); + block.Data = data; + + if (textureEntry != null && textureEntry.Length > 0) + { + byte[] teBytesFinal = new byte[textureEntry.Length + 4]; + + // Texture Length + Utils.IntToBytes(textureEntry.Length, textureEntry, 0); + // Texture + Buffer.BlockCopy(textureEntry, 0, teBytesFinal, 4, textureEntry.Length); + + block.TextureEntry = teBytesFinal; + } + else + { + block.TextureEntry = Utils.EmptyBytes; + } + + return block; } - /// - /// Set some default values in a ObjectUpdatePacket - /// - /// - protected void SetDefaultPrimPacketValues(ObjectUpdatePacket.ObjectDataBlock objdata) - { - objdata.PSBlock = new byte[0]; - objdata.ExtraParams = new byte[1]; - objdata.MediaURL = new byte[0]; - objdata.NameValue = new byte[0]; - objdata.Text = new byte[0]; - objdata.TextColor = new byte[4]; - objdata.JointAxisOrAnchor = new Vector3(0, 0, 0); - objdata.JointPivot = new Vector3(0, 0, 0); - objdata.Material = 3; - objdata.TextureAnim = new byte[0]; - objdata.Sound = UUID.Zero; - objdata.State = 0; - objdata.Data = new byte[0]; - - objdata.ObjectData = new byte[60]; - objdata.ObjectData[46] = 128; - objdata.ObjectData[47] = 63; + protected ObjectUpdatePacket.ObjectDataBlock CreateAvatarUpdateBlock(SendAvatarData data) + { + byte[] objectData = new byte[60]; + data.Position.ToBytes(objectData, 0); + //data.Velocity.ToBytes(objectData, 12); + //data.Acceleration.ToBytes(objectData, 24); + data.Rotation.ToBytes(objectData, 36); + //data.AngularVelocity.ToBytes(objectData, 48); + + ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); + + update.Data = Utils.EmptyBytes; + update.ExtraParams = new byte[1]; + update.FullID = data.AvatarID; + update.ID = data.AvatarLocalID; + update.Material = (byte)Material.Flesh; + update.MediaURL = Utils.EmptyBytes; + update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.FirstName + "\nLastName STRING RW SV " + + data.LastName + "\nTitle STRING RW SV " + data.GroupTitle); + update.ObjectData = objectData; + update.ParentID = data.ParentID; + update.PathCurve = 16; + update.PathScaleX = 100; + update.PathScaleY = 100; + update.PCode = (byte)PCode.Avatar; + update.ProfileCurve = 1; + update.PSBlock = Utils.EmptyBytes; + update.Scale = Vector3.One; + update.Text = Utils.EmptyBytes; + update.TextColor = new byte[4]; + update.TextureAnim = Utils.EmptyBytes; + update.TextureEntry = data.TextureEntry ?? Utils.EmptyBytes; + update.UpdateFlags = 61 + (9 << 8) + (130 << 16) + (16 << 24); // TODO: Replace these numbers with PrimFlags + + return update; } - /// - /// - /// - /// - public ObjectUpdatePacket.ObjectDataBlock CreateDefaultAvatarPacket(byte[] textureEntry) + protected ObjectUpdatePacket.ObjectDataBlock CreatePrimUpdateBlock(SendPrimitiveData data) { - ObjectUpdatePacket.ObjectDataBlock objdata = PacketPool.GetDataBlock(); - // new OpenMetaverse.Packets.ObjectUpdatePacket.ObjectDataBlock(data1, ref i); + byte[] objectData = new byte[60]; + data.pos.ToBytes(objectData, 0); + data.vel.ToBytes(objectData, 12); + data.acc.ToBytes(objectData, 24); + data.rotation.ToBytes(objectData, 36); + data.rvel.ToBytes(objectData, 48); - SetDefaultAvatarPacketValues(ref objdata); - objdata.UpdateFlags = 61 + (9 << 8) + (130 << 16) + (16 << 24); - objdata.PathCurve = 16; - objdata.ProfileCurve = 1; - objdata.PathScaleX = 100; - objdata.PathScaleY = 100; - objdata.ParentID = 0; - objdata.OwnerID = UUID.Zero; - objdata.Scale = new Vector3(1, 1, 1); - objdata.PCode = (byte)PCode.Avatar; - if (textureEntry != null) + ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); + update.ClickAction = (byte)data.clickAction; + update.CRC = 0; + update.ExtraParams = data.primShape.ExtraParams ?? Utils.EmptyBytes; + update.FullID = data.objectID; + update.ID = data.localID; + //update.JointAxisOrAnchor = Vector3.Zero; // These are deprecated + //update.JointPivot = Vector3.Zero; + //update.JointType = 0; + update.Material = data.material; + update.MediaURL = Utils.EmptyBytes; // FIXME: Support this in OpenSim + if (data.attachment) { - objdata.TextureEntry = textureEntry; + update.NameValue = Util.StringToBytes256("AttachItemID STRING RW SV " + data.AssetId); + update.State = (byte)((data.AttachPoint % 16) * 16 + (data.AttachPoint / 16)); + } + else + { + update.NameValue = Utils.EmptyBytes; + update.State = data.primShape.State; + } + update.ObjectData = objectData; + update.ParentID = data.parentID; + update.PathBegin = data.primShape.PathBegin; + update.PathCurve = data.primShape.PathCurve; + update.PathEnd = data.primShape.PathEnd; + update.PathRadiusOffset = data.primShape.PathRadiusOffset; + update.PathRevolutions = data.primShape.PathRevolutions; + update.PathScaleX = data.primShape.PathScaleX; + update.PathScaleY = data.primShape.PathScaleY; + update.PathShearX = data.primShape.PathShearX; + update.PathShearY = data.primShape.PathShearY; + update.PathSkew = data.primShape.PathSkew; + update.PathTaperX = data.primShape.PathTaperX; + update.PathTaperY = data.primShape.PathTaperY; + update.PathTwist = data.primShape.PathTwist; + update.PathTwistBegin = data.primShape.PathTwistBegin; + update.PCode = data.primShape.PCode; + update.ProfileBegin = data.primShape.ProfileBegin; + update.ProfileCurve = data.primShape.ProfileCurve; + update.ProfileEnd = data.primShape.ProfileEnd; + update.ProfileHollow = data.primShape.ProfileHollow; + update.PSBlock = data.particleSystem ?? Utils.EmptyBytes; + update.TextColor = data.color ?? Color4.Black.GetBytes(true); + update.TextureAnim = data.textureanim ?? Utils.EmptyBytes; + update.TextureEntry = data.primShape.TextureEntry ?? Utils.EmptyBytes; + update.Scale = data.primShape.Scale; + update.Text = Util.StringToBytes256(data.text); + update.UpdateFlags = (uint)data.flags; + + if (data.SoundId != UUID.Zero) + { + update.Sound = data.SoundId; + update.OwnerID = data.ownerID; + update.Gain = (float)data.SoundVolume; + update.Radius = (float)data.SoundRadius; + update.Flags = data.SoundFlags; + } + + switch ((PCode)data.primShape.PCode) + { + case PCode.Grass: + case PCode.Tree: + case PCode.NewTree: + update.Data = new byte[] { data.primShape.State }; + break; + default: + // TODO: Support ScratchPad + //if (prim.ScratchPad != null) + //{ + // update.Data = new byte[prim.ScratchPad.Length]; + // Buffer.BlockCopy(prim.ScratchPad, 0, update.Data, 0, update.Data.Length); + //} + //else + //{ + // update.Data = Utils.EmptyBytes; + //} + update.Data = Utils.EmptyBytes; + break; } - Vector3 pos = new Vector3(objdata.ObjectData, 16); - pos.X = 100f; - objdata.ID = 8880000; - objdata.NameValue = Utils.StringToBytes("FirstName STRING RW SV Test \nLastName STRING RW SV User "); - //Vector3 pos2 = new Vector3(100f, 100f, 23f); - //objdata.FullID=user.AgentId; - byte[] pb = pos.GetBytes(); - Array.Copy(pb, 0, objdata.ObjectData, 16, pb.Length); - - return objdata; - } - /// - /// - /// - /// - protected void SetDefaultAvatarPacketValues(ref ObjectUpdatePacket.ObjectDataBlock objdata) - { - objdata.PSBlock = new byte[0]; - objdata.ExtraParams = new byte[1]; - objdata.MediaURL = new byte[0]; - objdata.NameValue = new byte[0]; - objdata.Text = new byte[0]; - objdata.TextColor = new byte[4]; - objdata.JointAxisOrAnchor = new Vector3(0, 0, 0); - objdata.JointPivot = new Vector3(0, 0, 0); - objdata.Material = 4; - objdata.TextureAnim = new byte[0]; - objdata.Sound = UUID.Zero; - Primitive.TextureEntry ntex = new Primitive.TextureEntry(new UUID("00000000-0000-0000-5005-000000000005")); - objdata.TextureEntry = ntex.GetBytes(); - - objdata.State = 0; - objdata.Data = new byte[0]; - - objdata.ObjectData = new byte[76]; - objdata.ObjectData[15] = 128; - objdata.ObjectData[16] = 63; - objdata.ObjectData[56] = 128; - objdata.ObjectData[61] = 102; - objdata.ObjectData[62] = 40; - objdata.ObjectData[63] = 61; - objdata.ObjectData[64] = 189; + return update; } public void SendNameReply(UUID profileId, string firstname, string lastname) @@ -4682,8 +4405,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP packet.UUIDNameBlock = new UUIDNameReplyPacket.UUIDNameBlockBlock[1]; packet.UUIDNameBlock[0] = new UUIDNameReplyPacket.UUIDNameBlockBlock(); packet.UUIDNameBlock[0].ID = profileId; - packet.UUIDNameBlock[0].FirstName = Utils.StringToBytes(firstname); - packet.UUIDNameBlock[0].LastName = Utils.StringToBytes(lastname); + packet.UUIDNameBlock[0].FirstName = Util.StringToBytes256(firstname); + packet.UUIDNameBlock[0].LastName = Util.StringToBytes256(lastname); OutPacket(packet, ThrottleOutPacketType.Task); } @@ -4879,8 +4602,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP scriptQuestion.Data.TaskID = taskID; scriptQuestion.Data.ItemID = itemID; scriptQuestion.Data.Questions = question; - scriptQuestion.Data.ObjectName = Utils.StringToBytes(taskName); - scriptQuestion.Data.ObjectOwner = Utils.StringToBytes(ownerName); + scriptQuestion.Data.ObjectName = Util.StringToBytes256(taskName); + scriptQuestion.Data.ObjectOwner = Util.StringToBytes256(ownerName); OutPacket(scriptQuestion, ThrottleOutPacketType.Task); } @@ -5274,7 +4997,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (m_moneyBalance + debit >= 0) { m_moneyBalance += debit; - SendMoneyBalance(UUID.Zero, true, Utils.StringToBytes("Poof Poof!"), m_moneyBalance); + SendMoneyBalance(UUID.Zero, true, Util.StringToBytes256("Poof Poof!"), m_moneyBalance); return true; } return false; @@ -9218,7 +8941,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP new GroupTitlesReplyPacket.GroupDataBlock(); groupTitlesReply.GroupData[i].Title = - Utils.StringToBytes(d.Name); + Util.StringToBytes256(d.Name); groupTitlesReply.GroupData[i].RoleID = d.UUID; groupTitlesReply.GroupData[i].Selected = @@ -9255,10 +8978,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP groupProfileRequest.GroupData.GroupID); groupProfileReply.GroupData.GroupID = d.GroupID; - groupProfileReply.GroupData.Name = Utils.StringToBytes(d.Name); - groupProfileReply.GroupData.Charter = Utils.StringToBytes(d.Charter); + groupProfileReply.GroupData.Name = Util.StringToBytes256(d.Name); + groupProfileReply.GroupData.Charter = Util.StringToBytes1024(d.Charter); groupProfileReply.GroupData.ShowInList = d.ShowInList; - groupProfileReply.GroupData.MemberTitle = Utils.StringToBytes(d.MemberTitle); + groupProfileReply.GroupData.MemberTitle = Util.StringToBytes256(d.MemberTitle); groupProfileReply.GroupData.PowersMask = d.PowersMask; groupProfileReply.GroupData.InsigniaID = d.InsigniaID; groupProfileReply.GroupData.FounderID = d.FounderID; @@ -9330,11 +9053,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP groupMembersReply.MemberData[i].Contribution = m.Contribution; groupMembersReply.MemberData[i].OnlineStatus = - Utils.StringToBytes(m.OnlineStatus); + Util.StringToBytes256(m.OnlineStatus); groupMembersReply.MemberData[i].AgentPowers = m.AgentPowers; groupMembersReply.MemberData[i].Title = - Utils.StringToBytes(m.Title); + Util.StringToBytes256(m.Title); groupMembersReply.MemberData[i].IsOwner = m.IsOwner; } @@ -9395,11 +9118,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP groupRolesReply.RoleData[i].RoleID = d.RoleID; groupRolesReply.RoleData[i].Name = - Utils.StringToBytes(d.Name); + Util.StringToBytes256(d.Name); groupRolesReply.RoleData[i].Title = - Utils.StringToBytes(d.Title); + Util.StringToBytes256(d.Title); groupRolesReply.RoleData[i].Description = - Utils.StringToBytes(d.Description); + Util.StringToBytes1024(d.Description); groupRolesReply.RoleData[i].Powers = d.Powers; groupRolesReply.RoleData[i].Members = @@ -9626,9 +9349,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP groupNoticesListReply.Data[i].Timestamp = g.Timestamp; groupNoticesListReply.Data[i].FromName = - Utils.StringToBytes(g.FromName); + Util.StringToBytes256(g.FromName); groupNoticesListReply.Data[i].Subject = - Utils.StringToBytes(g.Subject); + Util.StringToBytes256(g.Subject); groupNoticesListReply.Data[i].HasAttachment = g.HasAttachment; groupNoticesListReply.Data[i].AssetType = @@ -10227,12 +9950,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP byte mediaLoop) { ParcelMediaUpdatePacket updatePacket = new ParcelMediaUpdatePacket(); - updatePacket.DataBlock.MediaURL = Utils.StringToBytes(mediaUrl); + updatePacket.DataBlock.MediaURL = Util.StringToBytes256(mediaUrl); updatePacket.DataBlock.MediaID = mediaTextureID; updatePacket.DataBlock.MediaAutoScale = autoScale; - updatePacket.DataBlockExtended.MediaType = Utils.StringToBytes(mediaType); - updatePacket.DataBlockExtended.MediaDesc = Utils.StringToBytes(mediaDesc); + updatePacket.DataBlockExtended.MediaType = Util.StringToBytes256(mediaType); + updatePacket.DataBlockExtended.MediaDesc = Util.StringToBytes256(mediaDesc); updatePacket.DataBlockExtended.MediaWidth = mediaWidth; updatePacket.DataBlockExtended.MediaHeight = mediaHeight; updatePacket.DataBlockExtended.MediaLoop = mediaLoop; diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 4f3478b..66e1468 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -733,10 +733,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP // on to en-US to avoid number parsing issues Culture.SetCurrentCulture(); - IncomingPacket incomingPacket = null; - while (base.IsRunning) { + IncomingPacket incomingPacket = null; + try { if (packetInbox.Dequeue(100, ref incomingPacket)) diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 30fe976..70b11c3 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -357,13 +357,6 @@ namespace OpenSim.Region.Framework.Scenes get { return m_defaultScriptEngine; } } - // Reference to all of the agents in the scene (root and child) - protected Dictionary m_scenePresences - { - get { return m_sceneGraph.ScenePresences; } - set { m_sceneGraph.ScenePresences = value; } - } - public EntityManager Entities { get { return m_sceneGraph.Entities; } @@ -1183,14 +1176,13 @@ namespace OpenSim.Region.Framework.Scenes /// Stats on the Simulator's performance private void SendSimStatsPackets(SimStats stats) { - List StatSendAgents = GetScenePresences(); - foreach (ScenePresence agent in StatSendAgents) - { - if (!agent.IsChildAgent) + ForEachScenePresence( + delegate(ScenePresence agent) { - agent.ControllingClient.SendSimStats(stats); + if (!agent.IsChildAgent) + agent.ControllingClient.SendSimStats(stats); } - } + ); } /// @@ -3501,10 +3493,8 @@ namespace OpenSim.Region.Framework.Scenes { ScenePresence presence; - lock (m_scenePresences) - { - m_scenePresences.TryGetValue(agentID, out presence); - } + lock (m_sceneGraph.ScenePresences) + m_sceneGraph.ScenePresences.TryGetValue(agentID, out presence); if (presence != null) { @@ -3714,12 +3704,9 @@ namespace OpenSim.Region.Framework.Scenes public void RequestTeleportLocation(IClientAPI remoteClient, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags) { - ScenePresence sp = null; - lock (m_scenePresences) - { - if (m_scenePresences.ContainsKey(remoteClient.AgentId)) - sp = m_scenePresences[remoteClient.AgentId]; - } + ScenePresence sp; + lock (m_sceneGraph.ScenePresences) + m_sceneGraph.ScenePresences.TryGetValue(remoteClient.AgentId, out sp); if (sp != null) { @@ -4168,7 +4155,7 @@ namespace OpenSim.Region.Framework.Scenes public void ForEachScenePresence(Action action) { // We don't want to try to send messages if there are no avatars. - if (m_scenePresences != null) + if (m_sceneGraph != null && m_sceneGraph.ScenePresences != null) { try { diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 79f6366..a078b3d 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -3791,15 +3791,15 @@ if (m_shape != null) { if (ParentGroup.RootPart == this) lPos = AbsolutePosition; } - + // Causes this thread to dig into the Client Thread Data. // Remember your locking here! remoteClient.SendPrimTerseUpdate(new SendPrimitiveTerseData(m_regionHandle, (ushort)(m_parentGroup.GetTimeDilation() * (float)ushort.MaxValue), LocalId, lPos, - RotationOffset, Velocity, + RotationOffset, Velocity, Acceleration, RotationalVelocity, state, FromItemID, - OwnerID, (int)AttachmentPoint, ParentGroup.GetUpdatePriority(remoteClient))); + OwnerID, (int)AttachmentPoint, null, ParentGroup.GetUpdatePriority(remoteClient))); } public void AddScriptLPS(int count) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index f05c3d8..bdd80c6 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -1160,15 +1160,21 @@ namespace OpenSim.Region.Framework.Scenes /// public void HandleAgentUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData) { - lock (m_agentUpdates) + const int AGENT_UPDATE_TIMEOUT_MS = 1000 * 3; + + if (System.Threading.Monitor.TryEnter(m_agentUpdates, AGENT_UPDATE_TIMEOUT_MS)) { - if (m_updatesAllowed) + try { - RealHandleAgentUpdate(remoteClient, agentData); - return; + if (m_updatesAllowed) + { + RealHandleAgentUpdate(remoteClient, agentData); + return; + } + + m_agentUpdates.Add(agentData); } - - m_agentUpdates.Add(agentData); + finally { System.Threading.Monitor.Exit(m_agentUpdates); } } } @@ -2471,7 +2477,7 @@ namespace OpenSim.Region.Framework.Scenes pos.Z -= m_appearance.HipOffset; remoteClient.SendAvatarTerseUpdate(new SendAvatarTerseData(m_regionHandle, (ushort)(m_scene.TimeDilation * ushort.MaxValue), LocalId, - pos, m_velocity, m_rotation, m_uuid, GetUpdatePriority(remoteClient))); + pos, m_velocity, Vector3.Zero, m_rotation, Vector4.Zero, m_uuid, null, GetUpdatePriority(remoteClient))); m_scene.StatsReporter.AddAgentTime(Environment.TickCount - m_perfMonMS); m_scene.StatsReporter.AddAgentUpdates(1); @@ -3504,7 +3510,6 @@ namespace OpenSim.Region.Framework.Scenes public void Close() { - lock (m_attachments) { // Delete attachments from scene @@ -3535,7 +3540,6 @@ namespace OpenSim.Region.Framework.Scenes m_sceneViewer.Close(); RemoveFromPhysicalScene(); - GC.Collect(); } public ScenePresence() -- cgit v1.1 From 2dd8a6beaca5a53039d2068db1cebfd7fd095943 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Mon, 19 Oct 2009 14:48:17 -0700 Subject: More instrumentation in physics. --- OpenSim/Region/Physics/OdePlugin/OdePlugin.cs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs index 7187fbe..f7f1f69 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs @@ -2986,6 +2986,8 @@ namespace OpenSim.Region.Physics.OdePlugin foreach (OdeCharacter actor in _characters) { if (actor != null) + if (actor.bad) + m_log.WarnFormat("[PHYSICS]: BAD Actor {0} in _characters list was not removed?", actor.m_uuid); actor.UpdatePositionAndVelocity(); } } -- cgit v1.1 From 590d91e57251cc35b3ce15bb60784249a1c3b15c Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Mon, 19 Oct 2009 15:03:55 -0700 Subject: Forgot {} on last commit. --- OpenSim/Region/Physics/OdePlugin/OdePlugin.cs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs index f7f1f69..aba3667 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs @@ -2986,9 +2986,11 @@ namespace OpenSim.Region.Physics.OdePlugin foreach (OdeCharacter actor in _characters) { if (actor != null) + { if (actor.bad) m_log.WarnFormat("[PHYSICS]: BAD Actor {0} in _characters list was not removed?", actor.m_uuid); actor.UpdatePositionAndVelocity(); + } } } -- cgit v1.1 From 142008121e2e9c5ca5fca5de07b8a14e37279800 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Mon, 19 Oct 2009 15:19:09 -0700 Subject: * Change Util.FireAndForget to use ThreadPool.UnsafeQueueUserWorkItem(). This avoids .NET remoting and a managed->unmanaged->managed jump. Overall, a night and day performance difference * Initialize the LLClientView prim full update queue to the number of prims in the scene for a big performance boost * Reordered some comparisons on hot code paths for a minor speed boost * Removed an unnecessary call to the expensive DateTime.Now function (if you *have* to get the current time as opposed to Environment.TickCount, always use DateTime.UtcNow) * Don't fire the queue empty callback for the Resend category * Run the outgoing packet handler thread loop for each client synchronously. It seems like more time was being spent doing the execution asynchronously, and it made deadlocks very difficult to track down * Rewrote some expensive math in LandObject.cs * Optimized EntityManager to only lock on operations that need locking, and use TryGetValue() where possible * Only update the attachment database when an object is attached or detached * Other small misc. performance improvements --- .../Region/ClientStack/LindenUDP/LLClientView.cs | 88 +++++++++++----------- .../Region/ClientStack/LindenUDP/LLImageManager.cs | 2 - .../Region/ClientStack/LindenUDP/LLUDPClient.cs | 9 ++- .../Region/ClientStack/LindenUDP/LLUDPServer.cs | 19 +++-- .../CoreModules/World/Land/LandManagementModule.cs | 5 +- .../Region/CoreModules/World/Land/LandObject.cs | 6 +- OpenSim/Region/Framework/Scenes/EntityManager.cs | 69 ++++++++--------- OpenSim/Region/Framework/Scenes/Scene.Inventory.cs | 21 ++---- OpenSim/Region/Framework/Scenes/Scene.cs | 4 + OpenSim/Region/Framework/Scenes/SceneGraph.cs | 12 ++- .../Region/Framework/Scenes/SceneObjectGroup.cs | 2 +- 11 files changed, 117 insertions(+), 120 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 1c463ea..b027882 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -321,12 +321,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP private readonly IGroupsModule m_GroupsModule; private int m_cachedTextureSerial; - private PriorityQueue m_avatarTerseUpdates = - new PriorityQueue(); - private PriorityQueue m_primTerseUpdates = - new PriorityQueue(); - private PriorityQueue m_primFullUpdates = - new PriorityQueue(); + private PriorityQueue m_avatarTerseUpdates; + private PriorityQueue m_primTerseUpdates; + private PriorityQueue m_primFullUpdates; private int m_moneyBalance; private int m_animationSequenceNumber = 1; private bool m_SendLogoutPacketWhenClosing = true; @@ -335,7 +332,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP protected Dictionary m_packetHandlers = new Dictionary(); protected Dictionary m_genericPacketHandlers = new Dictionary(); //PauPaw:Local Generic Message handlers - protected IScene m_scene; + protected Scene m_scene; protected LLImageManager m_imageManager; protected string m_firstName; protected string m_lastName; @@ -408,16 +405,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// /// Constructor /// - public LLClientView(EndPoint remoteEP, IScene scene, LLUDPServer udpServer, LLUDPClient udpClient, AuthenticateResponse sessionInfo, + public LLClientView(EndPoint remoteEP, Scene scene, LLUDPServer udpServer, LLUDPClient udpClient, AuthenticateResponse sessionInfo, UUID agentId, UUID sessionId, uint circuitCode) { RegisterInterface(this); RegisterInterface(this); RegisterInterface(this); - + InitDefaultAnimations(); m_scene = scene; + + m_avatarTerseUpdates = new PriorityQueue(); + m_primTerseUpdates = new PriorityQueue(); + m_primFullUpdates = new PriorityQueue(m_scene.Entities.Count); + m_assetService = m_scene.RequestModuleInterface(); m_hyperAssets = m_scene.RequestModuleInterface(); m_GroupsModule = scene.RequestModuleInterface(); @@ -3288,10 +3290,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } Quaternion rotation = data.Rotation; - - if (rotation.X == rotation.Y && - rotation.Y == rotation.Z && - rotation.Z == rotation.W && rotation.W == 0.0f) + if (rotation.W == 0.0f && rotation.X == 0.0f && rotation.Y == 0.0f && rotation.Z == 0.0f) rotation = Quaternion.Identity; ImprovedTerseObjectUpdatePacket.ObjectDataBlock terseBlock = CreateImprovedTerseBlock(data); @@ -3377,15 +3376,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP } Quaternion rotation = data.rotation; + if (rotation.W == 0.0f && rotation.X == 0.0f && rotation.Y == 0.0f && rotation.Z == 0.0f) + rotation = Quaternion.Identity; if (data.AttachPoint > 30 && data.ownerID != AgentId) // Someone else's HUD return; - if (data.primShape.PCode == 9 && data.primShape.State != 0 && data.parentID == 0) + if (data.primShape.State != 0 && data.parentID == 0 && data.primShape.PCode == 9) return; - if (rotation.X == rotation.Y && rotation.Y == rotation.Z && rotation.Z == rotation.W && rotation.W == 0.0f) - rotation = Quaternion.Identity; - ObjectUpdatePacket.ObjectDataBlock objectData = CreatePrimUpdateBlock(data); lock (m_primFullUpdates.SyncRoot) @@ -3397,7 +3395,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP ObjectUpdatePacket outPacket = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate); outPacket.Header.Zerocoded = true; - //outPacket.RegionData = new ObjectUpdatePacket.RegionDataBlock(); outPacket.RegionData.RegionHandle = Scene.RegionInfo.RegionHandle; outPacket.RegionData.TimeDilation = (ushort)(Scene.TimeDilation * ushort.MaxValue); @@ -3424,13 +3421,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP } Quaternion rotation = data.Rotation; + if (rotation.W == 0.0f && rotation.X == 0.0f && rotation.Y == 0.0f && rotation.Z == 0.0f) + rotation = Quaternion.Identity; if (data.AttachPoint > 30 && data.OwnerID != AgentId) // Someone else's HUD return; - if (rotation.X == rotation.Y && rotation.Y == rotation.Z && rotation.Z == rotation.W && rotation.W == 0) - rotation = Quaternion.Identity; - ImprovedTerseObjectUpdatePacket.ObjectDataBlock objectData = CreateImprovedTerseBlock(data); lock (m_primTerseUpdates.SyncRoot) @@ -10238,10 +10234,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP { internal delegate bool UpdatePriorityHandler(ref TPriority priority, uint local_id); - private MinHeap[] heaps = new MinHeap[1]; - private Dictionary lookup_table = new Dictionary(); - private Comparison comparison; - private object sync_root = new object(); + private MinHeap[] m_heaps = new MinHeap[1]; + private Dictionary m_lookupTable; + private Comparison m_comparison; + private object m_syncRoot = new object(); internal PriorityQueue() : this(MinHeap.DEFAULT_CAPACITY, Comparer.Default) { } @@ -10255,19 +10251,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP this(capacity, new Comparison(comparer.Compare)) { } internal PriorityQueue(int capacity, Comparison comparison) { - for (int i = 0; i < heaps.Length; ++i) - heaps[i] = new MinHeap(capacity); - this.comparison = comparison; + m_lookupTable = new Dictionary(capacity); + + for (int i = 0; i < m_heaps.Length; ++i) + m_heaps[i] = new MinHeap(capacity); + this.m_comparison = comparison; } - internal object SyncRoot { get { return this.sync_root; } } + internal object SyncRoot { get { return this.m_syncRoot; } } internal int Count { get { int count = 0; - for (int i = 0; i < heaps.Length; ++i) - count = heaps[i].Count; + for (int i = 0; i < m_heaps.Length; ++i) + count = m_heaps[i].Count; return count; } } @@ -10276,36 +10274,36 @@ namespace OpenSim.Region.ClientStack.LindenUDP { LookupItem item; - if (lookup_table.TryGetValue(local_id, out item)) + if (m_lookupTable.TryGetValue(local_id, out item)) { - item.Heap[item.Handle] = new MinHeapItem(priority, value, local_id, this.comparison); + item.Heap[item.Handle] = new MinHeapItem(priority, value, local_id, this.m_comparison); return false; } else { - item.Heap = heaps[0]; - item.Heap.Add(new MinHeapItem(priority, value, local_id, this.comparison), ref item.Handle); - lookup_table.Add(local_id, item); + item.Heap = m_heaps[0]; + item.Heap.Add(new MinHeapItem(priority, value, local_id, this.m_comparison), ref item.Handle); + m_lookupTable.Add(local_id, item); return true; } } internal TValue Peek() { - for (int i = 0; i < heaps.Length; ++i) - if (heaps[i].Count > 0) - return heaps[i].Min().Value; + for (int i = 0; i < m_heaps.Length; ++i) + if (m_heaps[i].Count > 0) + return m_heaps[i].Min().Value; throw new InvalidOperationException(string.Format("The {0} is empty", this.GetType().ToString())); } internal TValue Dequeue() { - for (int i = 0; i < heaps.Length; ++i) + for (int i = 0; i < m_heaps.Length; ++i) { - if (heaps[i].Count > 0) + if (m_heaps[i].Count > 0) { - MinHeapItem item = heaps[i].RemoveMin(); - lookup_table.Remove(item.LocalID); + MinHeapItem item = m_heaps[i].RemoveMin(); + m_lookupTable.Remove(item.LocalID); return item.Value; } } @@ -10317,7 +10315,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP MinHeapItem item; TPriority priority; - foreach (LookupItem lookup in new List(this.lookup_table.Values)) + foreach (LookupItem lookup in new List(this.m_lookupTable.Values)) { if (lookup.Heap.TryGetValue(lookup.Handle, out item)) { @@ -10332,7 +10330,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP { m_log.Warn("[LLCLIENTVIEW]: UpdatePriorityHandler returned false, dropping update"); lookup.Heap.Remove(lookup.Handle); - this.lookup_table.Remove(item.LocalID); + this.m_lookupTable.Remove(item.LocalID); } } } diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs b/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs index d25bf95..938cf50 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs @@ -51,7 +51,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private bool m_shuttingdown; - private long m_lastloopprocessed; private AssetBase m_missingImage; private LLClientView m_client; //Client we're assigned to private IAssetService m_assetCache; //Asset Cache @@ -169,7 +168,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP public bool ProcessImageQueue(int packetsToSend) { - m_lastloopprocessed = DateTime.Now.Ticks; int packetsSent = 0; while (packetsSent < packetsToSend) diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs index 9476eed..4b6a358 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs @@ -506,8 +506,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// for private void BeginFireQueueEmpty(int throttleIndex) { - if (!m_onQueueEmptyRunning[throttleIndex]) - Util.FireAndForget(FireQueueEmpty, throttleIndex); + // Unknown is -1 and Resend is 0. Make sure we are only firing the + // callback for categories other than those + if (throttleIndex > 0) + { + if (!m_onQueueEmptyRunning[throttleIndex]) + Util.FireAndForget(FireQueueEmpty, throttleIndex); + } } /// diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 66e1468..74175d0 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -107,7 +107,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Manages authentication for agent circuits private AgentCircuitManager m_circuitManager; /// Reference to the scene this UDP server is attached to - private IScene m_scene; + private Scene m_scene; /// The X/Y coordinates of the scene this UDP server is attached to private Location m_location; /// The measured resolution of Environment.TickCount @@ -184,15 +184,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP public void AddScene(IScene scene) { - if (m_scene == null) + if (m_scene != null) { - m_scene = scene; - m_location = new Location(m_scene.RegionInfo.RegionHandle); + m_log.Error("[LLUDPSERVER]: AddScene() called on an LLUDPServer that already has a scene"); + return; } - else + + if (!(scene is Scene)) { - m_log.Error("[LLUDPSERVER]: AddScene() called on an LLUDPServer that already has a scene"); + m_log.Error("[LLUDPSERVER]: AddScene() called with an unrecognized scene type " + scene.GetType()); + return; } + + m_scene = (Scene)scene; + m_location = new Location(m_scene.RegionInfo.RegionHandle); } public bool HandlesRegion(Location x) @@ -794,7 +799,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP elapsed500MS = 0; } - m_scene.ClientManager.ForEach( + m_scene.ClientManager.ForEachSync( delegate(IClientAPI client) { if (client is LLClientView) diff --git a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs index 332d3ce..53c64cb 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs @@ -147,9 +147,10 @@ namespace OpenSim.Region.CoreModules.World.Land client.OnParcelDwellRequest += ClientOnParcelDwellRequest; client.OnParcelDeedToGroup += ClientOnParcelDeedToGroup; - if (m_scene.Entities.ContainsKey(client.AgentId)) + EntityBase presenceEntity; + if (m_scene.Entities.TryGetValue(client.AgentId, out presenceEntity) && presenceEntity is ScenePresence) { - SendLandUpdate((ScenePresence)m_scene.Entities[client.AgentId], true); + SendLandUpdate((ScenePresence)presenceEntity, true); SendParcelOverlay(client); } } diff --git a/OpenSim/Region/CoreModules/World/Land/LandObject.cs b/OpenSim/Region/CoreModules/World/Land/LandObject.cs index b9b7da5..bfe85f1 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandObject.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandObject.cs @@ -139,10 +139,8 @@ namespace OpenSim.Region.CoreModules.World.Land } else { - //Normal Calculations - return Convert.ToInt32( - Math.Round((Convert.ToDecimal(LandData.Area) / Convert.ToDecimal(65536)) * m_scene.objectCapacity * - Convert.ToDecimal(m_scene.RegionInfo.RegionSettings.ObjectBonus))); ; + // Normal Calculations + return (int)Math.Round(((float)LandData.Area / 65536.0f) * (float)m_scene.objectCapacity * (float)m_scene.RegionInfo.RegionSettings.ObjectBonus); } } public int GetSimulatorMaxPrimCount(ILandObject thisObject) diff --git a/OpenSim/Region/Framework/Scenes/EntityManager.cs b/OpenSim/Region/Framework/Scenes/EntityManager.cs index 0ceef39..099fcce 100644 --- a/OpenSim/Region/Framework/Scenes/EntityManager.cs +++ b/OpenSim/Region/Framework/Scenes/EntityManager.cs @@ -93,40 +93,31 @@ namespace OpenSim.Region.Framework.Scenes { get { - lock (m_lock) - { - return m_eb_uuid.Count; - } + return m_eb_uuid.Count; } } public bool ContainsKey(UUID id) { - lock (m_lock) + try { - try - { - return m_eb_uuid.ContainsKey(id); - } - catch - { - return false; - } + return m_eb_uuid.ContainsKey(id); + } + catch + { + return false; } } public bool ContainsKey(uint localID) { - lock (m_lock) + try { - try - { - return m_eb_localID.ContainsKey(localID); - } - catch - { - return false; - } + return m_eb_localID.ContainsKey(localID); + } + catch + { + return false; } } @@ -136,7 +127,11 @@ namespace OpenSim.Region.Framework.Scenes { try { - bool a = m_eb_uuid.Remove(m_eb_localID[localID].UUID); + bool a = false; + EntityBase entity; + if (m_eb_localID.TryGetValue(localID, out entity)) + a = m_eb_uuid.Remove(entity.UUID); + bool b = m_eb_localID.Remove(localID); return a && b; } @@ -154,7 +149,11 @@ namespace OpenSim.Region.Framework.Scenes { try { - bool a = m_eb_localID.Remove(m_eb_uuid[id].LocalId); + bool a = false; + EntityBase entity; + if (m_eb_uuid.TryGetValue(id, out entity)) + a = m_eb_localID.Remove(entity.LocalId); + bool b = m_eb_uuid.Remove(id); return a && b; } @@ -206,14 +205,11 @@ namespace OpenSim.Region.Framework.Scenes { lock (m_lock) { - try - { - return m_eb_uuid[id]; - } - catch - { + EntityBase entity; + if (m_eb_uuid.TryGetValue(id, out entity)) + return entity; + else return null; - } } } set @@ -228,14 +224,11 @@ namespace OpenSim.Region.Framework.Scenes { lock (m_lock) { - try - { - return m_eb_localID[localID]; - } - catch - { + EntityBase entity; + if (m_eb_localID.TryGetValue(localID, out entity)) + return entity; + else return null; - } } } set diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index c44c4c7..c2b9e73 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -2351,12 +2351,6 @@ namespace OpenSim.Region.Framework.Scenes item = InventoryService.GetItem(item); presence.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID /*att.UUID*/); - IAvatarFactory ava = RequestModuleInterface(); - if (ava != null) - { - ava.UpdateDatabase(remoteClient.AgentId, presence.Appearance); - } - } return att.UUID; } @@ -2402,12 +2396,6 @@ namespace OpenSim.Region.Framework.Scenes InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId); item = InventoryService.GetItem(item); presence.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID /*att.UUID*/); - - if (m_AvatarFactory != null) - { - m_log.InfoFormat("[SCENE INVENTORY]: Saving avatar attachment. AgentID:{0} ItemID:{1} AttachmentPoint:{2}", remoteClient.AgentId, itemID, AttachmentPt); - m_AvatarFactory.UpdateDatabase(remoteClient.AgentId, presence.Appearance); - } } } @@ -2447,12 +2435,13 @@ namespace OpenSim.Region.Framework.Scenes if (TryGetAvatar(remoteClient.AgentId, out presence)) { presence.Appearance.DetachAttachment(itemID); - IAvatarFactory ava = RequestModuleInterface(); - if (ava != null) + + // Save avatar attachment information + if (m_AvatarFactory != null) { - ava.UpdateDatabase(remoteClient.AgentId, presence.Appearance); + m_log.Info("[SCENE]: Saving avatar attachment. AgentID: " + remoteClient.AgentId + ", ItemID: " + itemID); + m_AvatarFactory.UpdateDatabase(remoteClient.AgentId, presence.Appearance); } - } m_sceneGraph.DetachSingleAttachmentToInv(itemID, remoteClient); diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 70b11c3..4f3cc98 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -228,6 +228,10 @@ namespace OpenSim.Region.Framework.Scenes protected IXMLRPC m_xmlrpcModule; protected IWorldComm m_worldCommModule; protected IAvatarFactory m_AvatarFactory; + public IAvatarFactory AvatarFactory + { + get { return m_AvatarFactory; } + } protected IConfigSource m_config; protected IRegionSerialiserModule m_serialiser; protected IInterregionCommsOut m_interregionCommsOut; diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index 8ee26c3..e51f6ef 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -467,7 +467,6 @@ namespace OpenSim.Region.Framework.Scenes protected internal void AttachObject(IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, Quaternion rot, bool silent) { // If we can't take it, we can't attach it! - // SceneObjectPart part = m_parentScene.GetSceneObjectPart(objectLocalID); if (part == null) return; @@ -477,9 +476,16 @@ namespace OpenSim.Region.Framework.Scenes return; // Calls attach with a Zero position - // AttachObject(remoteClient, objectLocalID, AttachmentPt, rot, Vector3.Zero, false); m_parentScene.SendAttachEvent(objectLocalID, part.ParentGroup.GetFromItemID(), remoteClient.AgentId); + + // Save avatar attachment information + ScenePresence presence; + if (m_parentScene.AvatarFactory != null && m_parentScene.TryGetAvatar(remoteClient.AgentId, out presence)) + { + m_log.Info("[SCENE]: Saving avatar attachment. AgentID: " + remoteClient.AgentId + ", AttachmentPoint: " + AttachmentPt); + m_parentScene.AvatarFactory.UpdateDatabase(remoteClient.AgentId, presence.Appearance); + } } public SceneObjectGroup RezSingleAttachment( @@ -574,7 +580,7 @@ namespace OpenSim.Region.Framework.Scenes } - group.SetAttachmentPoint(Convert.ToByte(AttachmentPt)); + group.SetAttachmentPoint((byte)AttachmentPt); group.AbsolutePosition = attachPos; // Saves and gets itemID diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 2153b9b..810dfd1 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -899,7 +899,7 @@ namespace OpenSim.Region.Framework.Scenes SetAttachmentPoint(Convert.ToByte(attachmentpoint)); avatar.AddAttachment(this); - m_log.DebugFormat("[SOG]: Added att {0} to avie {1}", UUID, avatar.UUID); + m_log.Debug("[SOG]: Added attachment " + UUID + " to avatar " + avatar.UUID); if (!silent) { -- cgit v1.1 From fdce1be3db287bed901332b90ba57165e201d3fc Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Mon, 19 Oct 2009 16:52:27 -0700 Subject: * Removed OpenSim.Data.NHibernate * Replaced calls to ThreadPool.QueueUserWorkItem() with ThreadPool.UnsafeQueueUserWorkItem() since OpenSim does not use Code Access Security sandboxing --- OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs | 6 +++--- OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs | 4 ++-- OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index b027882..a966b42 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -791,7 +791,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// heightmap public virtual void SendLayerData(float[] map) { - ThreadPool.QueueUserWorkItem(DoSendLayerData, map); + ThreadPool.UnsafeQueueUserWorkItem(DoSendLayerData, map); } /// @@ -912,7 +912,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// 16x16 array of wind speeds public virtual void SendWindData(Vector2[] windSpeeds) { - ThreadPool.QueueUserWorkItem(new WaitCallback(DoSendWindData), (object)windSpeeds); + ThreadPool.UnsafeQueueUserWorkItem(new WaitCallback(DoSendWindData), (object)windSpeeds); } /// @@ -921,7 +921,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// 16x16 array of cloud densities public virtual void SendCloudData(float[] cloudDensity) { - ThreadPool.QueueUserWorkItem(new WaitCallback(DoSendCloudData), (object)cloudDensity); + ThreadPool.UnsafeQueueUserWorkItem(new WaitCallback(DoSendCloudData), (object)cloudDensity); } /// diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs index 5ca4178..d45c35c 100644 --- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs @@ -313,11 +313,11 @@ namespace Flotsam.RegionModules.AssetCache } - ThreadPool.QueueUserWorkItem( + ThreadPool.UnsafeQueueUserWorkItem( delegate { WriteFileCache(filename, asset); - } + }, null ); } } diff --git a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs index 4fb4c51..1260584 100644 --- a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs +++ b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs @@ -1095,7 +1095,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap // The reason is so we don't cause the thread to freeze waiting // for the 1 second it costs to start a thread manually. if (!threadrunning) - ThreadPool.QueueUserWorkItem(new WaitCallback(this.StartThread)); + ThreadPool.UnsafeQueueUserWorkItem(this.StartThread, null); lock (m_rootAgents) { -- cgit v1.1 From 0a6ea33ac8faa015ad8014b429be0046ba3b3e0a Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Mon, 19 Oct 2009 18:50:31 -0700 Subject: * Optimized sending of terrain data * Send terrain data in a spiral pattern instead of a typewriter pattern (placeholder until terrain data becomes part of the interest list management) * Added a debug line when resent packets are being sent --- .../Region/ClientStack/LindenUDP/LLClientView.cs | 312 +++++++++++---------- .../Region/ClientStack/LindenUDP/LLUDPServer.cs | 23 +- 2 files changed, 180 insertions(+), 155 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index a966b42..88faccf 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -45,7 +45,7 @@ using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Scenes.Hypergrid; using OpenSim.Services.Interfaces; -using Timer=System.Timers.Timer; +using Timer = System.Timers.Timer; using AssetLandmark = OpenSim.Framework.AssetLandmark; using Nini.Config; @@ -342,7 +342,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP protected UUID m_activeGroupID; protected string m_activeGroupName = String.Empty; protected ulong m_activeGroupPowers; - protected Dictionary m_groupPowers = new Dictionary(); + protected Dictionary m_groupPowers = new Dictionary(); protected int m_terrainCheckerCount; protected uint m_agentFOVCounter; @@ -621,7 +621,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } // Sound - public void SoundTrigger(UUID soundId, UUID owerid, UUID Objectid,UUID ParentId,float Gain, Vector3 Position,UInt64 Handle) + public void SoundTrigger(UUID soundId, UUID owerid, UUID Objectid, UUID ParentId, float Gain, Vector3 Position, UInt64 Handle) { } @@ -658,7 +658,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP handshake.RegionInfo.CacheID = UUID.Random(); //I guess this is for the client to remember an old setting? handshake.RegionInfo2 = new RegionHandshakePacket.RegionInfo2Block(); handshake.RegionInfo2.RegionID = regionInfo.RegionID; - + handshake.RegionInfo3 = new RegionHandshakePacket.RegionInfo3Block(); handshake.RegionInfo3.CPUClassID = 9; handshake.RegionInfo3.CPURatio = 1; @@ -800,32 +800,55 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// private void DoSendLayerData(object o) { - float[] map = (float[])o; + float[] map = LLHeightFieldMoronize((float[])o); try { - for (int y = 0; y < 16; y++) - { - // For some terrains, sending more than one terrain patch at once results in a libsecondlife exception - // see http://opensimulator.org/mantis/view.php?id=1662 - //for (int x = 0; x < 16; x += 4) - //{ - // SendLayerPacket(map, y, x); - // Thread.Sleep(150); - //} - for (int x = 0; x < 16; x++) - { - SendLayerData(x, y, LLHeightFieldMoronize(map)); - Thread.Sleep(35); - } - } + //for (int y = 0; y < 16; y++) + //{ + // for (int x = 0; x < 16; x++) + // { + // SendLayerData(x, y, map); + // } + //} + + // Send LayerData in a spiral pattern. Fun! + SendLayerTopRight(map, 0, 0, 15, 15); } catch (Exception e) { - m_log.Warn("[CLIENT]: ClientView.API.cs: SendLayerData() - Failed with exception " + e); + m_log.Error("[CLIENT]: SendLayerData() Failed with exception: " + e.Message, e); } } + private void SendLayerTopRight(float[] map, int x1, int y1, int x2, int y2) + { + // Row + for (int i = x1; i <= x2; i++) + SendLayerData(i, y1, map); + + // Column + for (int j = y1 + 1; j <= y2; j++) + SendLayerData(x2, j, map); + + if (x2 - x1 > 0) + SendLayerBottomLeft(map, x1, y1 + 1, x2 - 1, y2); + } + + void SendLayerBottomLeft(float[] map, int x1, int y1, int x2, int y2) + { + // Row in reverse + for (int i = x2; i >= x1; i--) + SendLayerData(i, y2, map); + + // Column in reverse + for (int j = y2 - 1; j >= y1; j--) + SendLayerData(x1, j, map); + + if (x2 - x1 > 0) + SendLayerTopRight(map, x1 + 1, y1, x2, y2 - 1); + } + /// /// Sends a set of four patches (x, x+1, ..., x+3) to the client /// @@ -854,22 +877,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP { try { - int[] patches = new int[1]; - int patchx, patchy; - patchx = px; - patchy = py; + int[] patches = new int[] { py * 16 + px }; + float[] heightmap = (map.Length == 65536) ? + map : + LLHeightFieldMoronize(map); - patches[0] = patchx + 0 + patchy * 16; - - LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(((map.Length==65536)? map : LLHeightFieldMoronize(map)), patches); - layerpack.Header.Zerocoded = true; + LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches); + layerpack.Header.Reliable = true; OutPacket(layerpack, ThrottleOutPacketType.Land); - } catch (Exception e) { - m_log.Warn("[client]: ClientView.API.cs: SendLayerData() - Failed with exception " + e.ToString()); + m_log.Error("[CLIENT]: SendLayerData() Failed with exception: " + e.Message, e); } } @@ -898,7 +918,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP Array.Copy(map, i * (int)Constants.RegionSize, returnmap, i * 256, 256); } - //Array.Copy(map,0,returnmap,0,(map.Length < 65536)? map.Length : 65536); return returnmap; @@ -1010,14 +1029,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP agentData.child = false; agentData.firstname = m_firstName; agentData.lastname = m_lastName; - + ICapabilitiesModule capsModule = m_scene.RequestModuleInterface(); - + if (capsModule == null) // can happen when shutting down. return agentData; agentData.CapsPath = capsModule.GetCapsPath(m_agentId); - agentData.ChildrenCapSeeds = new Dictionary(capsModule.GetChildrenSeeds(m_agentId)); + agentData.ChildrenCapSeeds = new Dictionary(capsModule.GetChildrenSeeds(m_agentId)); return agentData; } @@ -1213,7 +1232,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP pc.PingID.PingID = seq; pc.PingID.OldestUnacked = (oldestPacket != null) ? oldestPacket.SequenceNumber : 0; - + OutPacket(pc, ThrottleOutPacketType.Unknown); } @@ -1519,7 +1538,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP inventoryReply.Header.Zerocoded = true; OutPacket(inventoryReply, ThrottleOutPacketType.Asset); } - + protected void SendBulkUpdateInventoryFolder(InventoryFolderBase folderBase) { // We will use the same transaction id for all the separate packets to be sent out in this update. @@ -1543,7 +1562,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP bulkUpdate.FolderData = folderDataBlocks.ToArray(); List foo = new List(); bulkUpdate.ItemData = foo.ToArray(); - + //m_log.Debug("SendBulkUpdateInventory :" + bulkUpdate); OutPacket(bulkUpdate, ThrottleOutPacketType.Asset); } @@ -1666,7 +1685,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP return itemBlock; } - + public void SendBulkUpdateInventory(InventoryNodeBase node) { if (node is InventoryItemBase) @@ -1676,7 +1695,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP else m_log.ErrorFormat("[CLIENT]: Client for {0} sent unknown inventory node named {1}", Name, node.Name); } - + protected void SendBulkUpdateInventoryItem(InventoryItemBase item) { const uint FULL_MASK_PERMISSIONS = (uint)PermissionMask.All; @@ -3100,9 +3119,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP awb.ItemID = wearables[i].ItemID; aw.WearableData[i] = awb; -// m_log.DebugFormat( -// "[APPEARANCE]: Sending wearable item/asset {0} {1} (index {2}) for {3}", -// awb.ItemID, awb.AssetID, i, Name); + // m_log.DebugFormat( + // "[APPEARANCE]: Sending wearable item/asset {0} {1} (index {2}) for {3}", + // awb.ItemID, awb.AssetID, i, Name); } OutPacket(aw, ThrottleOutPacketType.Task); @@ -3270,7 +3289,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP objupdate.RegionData.RegionHandle = data.RegionHandle; objupdate.RegionData.TimeDilation = ushort.MaxValue; - + objupdate.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1]; objupdate.ObjectData[0] = CreateAvatarUpdateBlock(data); @@ -3343,7 +3362,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP { CoarseLocationUpdatePacket.LocationBlock lb = new CoarseLocationUpdatePacket.LocationBlock(); - + lb.X = (byte)CoarseLocations[i].X; lb.Y = (byte)CoarseLocations[i].Y; @@ -3620,7 +3639,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP newPack.Header.Zerocoded = true; OutPacket(newPack, ThrottleOutPacketType.Asset); } - + public void SendInitiateDownload(string simFileName, string clientFileName) { InitiateDownloadPacket newPack = new InitiateDownloadPacket(); @@ -3629,7 +3648,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP newPack.FileData.ViewerFilename = Utils.StringToBytes(clientFileName); OutPacket(newPack, ThrottleOutPacketType.Asset); } - + public void SendImageFirstPart( ushort numParts, UUID ImageUUID, uint ImageSize, byte[] ImageData, byte imageCodec) { @@ -3817,7 +3836,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP public void SendBannedUserList(UUID invoice, EstateBan[] bl, uint estateID) { - ListBannedUsers = new List(); + List BannedUsers = new List(); for (int i = 0; i < bl.Length; i++) { @@ -3881,7 +3900,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP rinfoblk.UseEstateSun = args.useEstateSun; rinfoblk.WaterHeight = args.waterHeight; rinfoblk.SimName = Utils.StringToBytes(args.simName); - + rinfopack.RegionInfo2 = new RegionInfoPacket.RegionInfo2Block(); rinfopack.RegionInfo2.HardMaxAgents = uint.MaxValue; rinfopack.RegionInfo2.HardMaxObjects = uint.MaxValue; @@ -4128,7 +4147,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP public void SendLandObjectOwners(LandData land, List groups, Dictionary ownersAndCount) { - + int notifyCount = ownersAndCount.Count; ParcelObjectOwnersReplyPacket pack = (ParcelObjectOwnersReplyPacket)PacketPool.Instance.GetPacket(PacketType.ParcelObjectOwnersReply); @@ -4208,7 +4227,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (collisionPlane == Vector4.Zero) collisionPlane = Vector4.UnitW; - + collisionPlane.ToBytes(data, pos); pos += 16; } @@ -4297,7 +4316,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP update.TextureAnim = Utils.EmptyBytes; update.TextureEntry = data.TextureEntry ?? Utils.EmptyBytes; update.UpdateFlags = 61 + (9 << 8) + (130 << 16) + (16 << 24); // TODO: Replace these numbers with PrimFlags - + return update; } @@ -4448,7 +4467,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP private bool HandleMoneyTransferRequest(IClientAPI sender, Packet Pack) { - MoneyTransferRequestPacket money = (MoneyTransferRequestPacket) Pack; + MoneyTransferRequestPacket money = (MoneyTransferRequestPacket)Pack; // validate the agent owns the agentID and sessionID if (money.MoneyData.SourceID == sender.AgentId && money.AgentData.AgentID == sender.AgentId && money.AgentData.SessionID == sender.SessionId) @@ -4469,7 +4488,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP private bool HandleParcelBuyRequest(IClientAPI sender, Packet Pack) { - ParcelBuyPacket parcel = (ParcelBuyPacket) Pack; + ParcelBuyPacket parcel = (ParcelBuyPacket)Pack; if (parcel.AgentData.AgentID == AgentId && parcel.AgentData.SessionID == SessionId) { ParcelBuy handlerParcelBuy = OnParcelBuy; @@ -4489,7 +4508,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP private bool HandleUUIDGroupNameRequest(IClientAPI sender, Packet Pack) { UUIDGroupNameRequestPacket upack = (UUIDGroupNameRequestPacket)Pack; - + for (int i = 0; i < upack.UUIDNameBlock.Length; i++) { @@ -4505,7 +4524,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP public bool HandleGenericMessage(IClientAPI sender, Packet pack) { - GenericMessagePacket gmpack = (GenericMessagePacket) pack; + GenericMessagePacket gmpack = (GenericMessagePacket)pack; if (m_genericPacketHandlers.Count == 0) return false; if (gmpack.AgentData.SessionID != SessionId) return false; @@ -4642,7 +4661,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP { if (((LogoutRequestPacket)packet).AgentData.SessionID != SessionId) return false; } - + return Logout(client); } @@ -4700,7 +4719,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP cachedresp.Header.Zerocoded = true; OutPacket(cachedresp, ThrottleOutPacketType.Task); - + return true; } @@ -4750,7 +4769,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP UpdatePrimSingleRotation handlerUpdatePrimSingleRotation = OnUpdatePrimSingleRotation; if (handlerUpdatePrimSingleRotation != null) { - // m_log.Info("new tab rotation is " + rot1.X + " , " + rot1.Y + " , " + rot1.Z + " , " + rot1.W); + // m_log.Info("new tab rotation is " + rot1.X + " , " + rot1.Y + " , " + rot1.Z + " , " + rot1.W); handlerUpdatePrimSingleRotation(localId, rot1, this); } break; @@ -4761,8 +4780,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP UpdatePrimSingleRotationPosition handlerUpdatePrimSingleRotationPosition = OnUpdatePrimSingleRotationPosition; if (handlerUpdatePrimSingleRotationPosition != null) { - // m_log.Debug("new mouse rotation position is " + rotPos.X + " , " + rotPos.Y + " , " + rotPos.Z); - // m_log.Info("new mouse rotation is " + rot2.X + " , " + rot2.Y + " , " + rot2.Z + " , " + rot2.W); + // m_log.Debug("new mouse rotation position is " + rotPos.X + " , " + rotPos.Y + " , " + rotPos.Z); + // m_log.Info("new mouse rotation is " + rot2.X + " , " + rot2.Y + " , " + rot2.Z + " , " + rot2.W); handlerUpdatePrimSingleRotationPosition(localId, rot2, rotPos, this); } break; @@ -4773,7 +4792,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP UpdateVector handlerUpdatePrimScale = OnUpdatePrimScale; if (handlerUpdatePrimScale != null) { -// m_log.Debug("new scale is " + scale4.X + " , " + scale4.Y + " , " + scale4.Z); + // m_log.Debug("new scale is " + scale4.X + " , " + scale4.Y + " , " + scale4.Z); handlerUpdatePrimScale(localId, scale4, this); } break; @@ -4812,7 +4831,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP UpdatePrimRotation handlerUpdatePrimRotation = OnUpdatePrimGroupRotation; if (handlerUpdatePrimRotation != null) { - // Console.WriteLine("new rotation is " + rot3.X + " , " + rot3.Y + " , " + rot3.Z + " , " + rot3.W); + // Console.WriteLine("new rotation is " + rot3.X + " , " + rot3.Y + " , " + rot3.Z + " , " + rot3.W); handlerUpdatePrimRotation(localId, rot3, this); } break; @@ -4823,8 +4842,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP handlerUpdatePrimGroupRotation = OnUpdatePrimGroupMouseRotation; if (handlerUpdatePrimGroupRotation != null) { - // m_log.Debug("new rotation position is " + pos.X + " , " + pos.Y + " , " + pos.Z); - // m_log.Debug("new group mouse rotation is " + rot4.X + " , " + rot4.Y + " , " + rot4.Z + " , " + rot4.W); + // m_log.Debug("new rotation position is " + pos.X + " , " + pos.Y + " , " + pos.Z); + // m_log.Debug("new group mouse rotation is " + rot4.X + " , " + rot4.Y + " , " + rot4.Z + " , " + rot4.W); handlerUpdatePrimGroupRotation(localId, pos3, rot4, this); } break; @@ -4835,7 +4854,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP UpdateVector handlerUpdatePrimGroupScale = OnUpdatePrimGroupScale; if (handlerUpdatePrimGroupScale != null) { -// m_log.Debug("new scale is " + scale7.X + " , " + scale7.Y + " , " + scale7.Z); + // m_log.Debug("new scale is " + scale7.X + " , " + scale7.Y + " , " + scale7.Z); handlerUpdatePrimGroupScale(localId, scale7, this); } break; @@ -5067,7 +5086,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Main packet processing conditional switch (Pack.Type) { - #region Scene/Avatar + #region Scene/Avatar case PacketType.AvatarPropertiesRequest: AvatarPropertiesRequestPacket avatarProperties = (AvatarPropertiesRequestPacket)Pack; @@ -5318,7 +5337,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP break; case PacketType.DeRezObject: - DeRezObjectPacket DeRezPacket = (DeRezObjectPacket) Pack; + DeRezObjectPacket DeRezPacket = (DeRezObjectPacket)Pack; #region Packet Session and User Check if (m_checkPackets) @@ -5339,13 +5358,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP { deRezIDs.Add(data.ObjectLocalID); } - // It just so happens that the values on the DeRezAction enumerator match the Destination - // values given by a Second Life client - handlerDeRezObject(this, deRezIDs, - DeRezPacket.AgentBlock.GroupID, - (DeRezAction)DeRezPacket.AgentBlock.Destination, - DeRezPacket.AgentBlock.DestinationID); - + // It just so happens that the values on the DeRezAction enumerator match the Destination + // values given by a Second Life client + handlerDeRezObject(this, deRezIDs, + DeRezPacket.AgentBlock.GroupID, + (DeRezAction)DeRezPacket.AgentBlock.Destination, + DeRezPacket.AgentBlock.DestinationID); + } break; @@ -5449,7 +5468,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } break; - + case PacketType.AgentIsNowWearing: if (OnAvatarNowWearing != null) { @@ -5653,7 +5672,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (lastarg != null) { - update = + update = ( (x.BodyRotation != lastarg.BodyRotation) || (x.CameraAtAxis != lastarg.CameraAtAxis) || @@ -5846,7 +5865,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } break; - + case PacketType.UserInfoRequest: UserInfoRequest handlerUserInfoRequest = OnUserInfoRequest; if (handlerUserInfoRequest != null) @@ -5858,7 +5877,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP SendUserInfoReply(false, true, ""); } break; - + case PacketType.UpdateUserInfo: UpdateUserInfoPacket updateUserInfo = (UpdateUserInfoPacket)Pack; @@ -5885,7 +5904,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP visible, this); } break; - + case PacketType.SetStartLocationRequest: SetStartLocationRequestPacket avSetStartLocationRequestPacket = (SetStartLocationRequestPacket)Pack; @@ -5943,9 +5962,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP } break; - #endregion + #endregion - #region Objects/m_sceneObjects + #region Objects/m_sceneObjects case PacketType.ObjectLink: ObjectLinkPacket link = (ObjectLinkPacket)Pack; @@ -5976,7 +5995,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP handlerLinkObjects(this, parentprimid, childrenprims); } break; - + case PacketType.ObjectDelink: ObjectDelinkPacket delink = (ObjectDelinkPacket)Pack; @@ -6005,7 +6024,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } break; - + case PacketType.ObjectAdd: if (OnAddPrim != null) { @@ -6035,7 +6054,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP handlerAddPrim(AgentId, ActiveGroupId, addPacket.ObjectData.RayEnd, addPacket.ObjectData.Rotation, shape, addPacket.ObjectData.BypassRaycast, addPacket.ObjectData.RayStart, addPacket.ObjectData.RayTargetID, addPacket.ObjectData.RayEndIsIntersection); } break; - + case PacketType.ObjectShape: ObjectShapePacket shapePacket = (ObjectShapePacket)Pack; @@ -6080,7 +6099,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } } break; - + case PacketType.ObjectExtraParams: ObjectExtraParamsPacket extraPar = (ObjectExtraParamsPacket)Pack; @@ -6096,7 +6115,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP ObjectExtraParams handlerUpdateExtraParams = OnUpdateExtraParams; if (handlerUpdateExtraParams != null) { - for (int i = 0 ; i < extraPar.ObjectData.Length ; i++) + for (int i = 0; i < extraPar.ObjectData.Length; i++) { handlerUpdateExtraParams(m_agentId, extraPar.ObjectData[i].ObjectLocalID, extraPar.ObjectData[i].ParamType, @@ -6497,7 +6516,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP break; case PacketType.ObjectName: ObjectNamePacket objName = (ObjectNamePacket)Pack; - + #region Packet Session and User Check if (m_checkPackets) { @@ -6506,7 +6525,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP break; } #endregion - + GenericCall7 handlerObjectName = null; for (int i = 0; i < objName.ObjectData.Length; i++) { @@ -6739,14 +6758,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP } break; - #endregion + #endregion - #region Inventory/Asset/Other related packets + #region Inventory/Asset/Other related packets case PacketType.RequestImage: RequestImagePacket imageRequest = (RequestImagePacket)Pack; //m_log.Debug("image request: " + Pack.ToString()); - + #region Packet Session and User Check if (m_checkPackets) { @@ -6770,7 +6789,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP //handlerTextureRequest = OnRequestTexture; //if (handlerTextureRequest != null) - //OnRequestTexture(this, args); + //OnRequestTexture(this, args); // in the end, we null this, so we have to check if it's null if (m_imageManager != null) @@ -6816,7 +6835,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (ti.OwnerID != AgentId) break; - if ((ti.CurrentPermissions & ((uint)PermissionMask.Modify| (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) != ((uint)PermissionMask.Modify| (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) + if ((ti.CurrentPermissions & ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) != ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) break; if (ti.AssetID != requestID) @@ -6874,7 +6893,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP case PacketType.AssetUploadRequest: AssetUploadRequestPacket request = (AssetUploadRequestPacket)Pack; - + // m_log.Debug("upload request " + request.ToString()); // m_log.Debug("upload request was for assetid: " + request.AssetBlock.TransactionID.Combine(this.SecureSessionId).ToString()); UUID temp = UUID.Combine(request.AssetBlock.TransactionID, SecureSessionId); @@ -6891,7 +6910,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP break; case PacketType.RequestXfer: RequestXferPacket xferReq = (RequestXferPacket)Pack; - + RequestXfer handlerRequestXfer = OnRequestXfer; if (handlerRequestXfer != null) @@ -6910,7 +6929,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP break; case PacketType.ConfirmXferPacket: ConfirmXferPacketPacket confirmXfer = (ConfirmXferPacketPacket)Pack; - + ConfirmXfer handlerConfirmXfer = OnConfirmXfer; if (handlerConfirmXfer != null) { @@ -7005,7 +7024,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP break; case PacketType.CreateInventoryItem: CreateInventoryItemPacket createItem = (CreateInventoryItemPacket)Pack; - + #region Packet Session and User Check if (m_checkPackets) { @@ -7098,7 +7117,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP break; case PacketType.UpdateInventoryItem: UpdateInventoryItemPacket inventoryItemUpdate = (UpdateInventoryItemPacket)Pack; - + #region Packet Session and User Check if (m_checkPackets) { @@ -7590,7 +7609,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } break; - #endregion + #endregion case PacketType.UUIDNameRequest: UUIDNameRequestPacket incoming = (UUIDNameRequestPacket)Pack; @@ -7605,7 +7624,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } break; - #region Parcel related packets + #region Parcel related packets case PacketType.RegionHandleRequest: RegionHandleRequestPacket rhrPack = (RegionHandleRequestPacket)Pack; @@ -7986,9 +8005,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP } break; - #endregion + #endregion - #region Estate Packets + #region Estate Packets case PacketType.EstateOwnerMessage: EstateOwnerMessagePacket messagePacket = (EstateOwnerMessagePacket)Pack; @@ -8022,21 +8041,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP convertParamStringToBool(messagePacket.ParamList[7].Parameter), convertParamStringToBool(messagePacket.ParamList[8].Parameter)); } break; -// case "texturebase": -// if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false)) -// { -// foreach (EstateOwnerMessagePacket.ParamListBlock block in messagePacket.ParamList) -// { -// string s = Utils.BytesToString(block.Parameter); -// string[] splitField = s.Split(' '); -// if (splitField.Length == 2) -// { -// UUID tempUUID = new UUID(splitField[1]); -// OnSetEstateTerrainBaseTexture(this, Convert.ToInt16(splitField[0]), tempUUID); -// } -// } -// } -// break; + // case "texturebase": + // if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false)) + // { + // foreach (EstateOwnerMessagePacket.ParamListBlock block in messagePacket.ParamList) + // { + // string s = Utils.BytesToString(block.Parameter); + // string[] splitField = s.Split(' '); + // if (splitField.Length == 2) + // { + // UUID tempUUID = new UUID(splitField[1]); + // OnSetEstateTerrainBaseTexture(this, Convert.ToInt16(splitField[0]), tempUUID); + // } + // } + // } + // break; case "texturedetail": if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false)) { @@ -8278,7 +8297,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_log.Error("EstateOwnerMessage: Unknown method requested\n" + messagePacket); break; } - + //int parcelID, uint reportType, uint requestflags, string filter //lsrp.RequestData.ParcelLocalID; @@ -8318,9 +8337,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP } break; - #endregion + #endregion - #region GodPackets + #region GodPackets case PacketType.RequestGodlikePowers: RequestGodlikePowersPacket rglpPack = (RequestGodlikePowersPacket)Pack; @@ -8366,9 +8385,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP //OutPacket(kupack, ThrottleOutPacketType.Task); break; - #endregion + #endregion - #region Economy/Transaction Packets + #region Economy/Transaction Packets case PacketType.MoneyBalanceRequest: MoneyBalanceRequestPacket moneybalancerequestpacket = (MoneyBalanceRequestPacket)Pack; @@ -8392,7 +8411,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP break; case PacketType.EconomyDataRequest: - + EconomyDataRequest handlerEconomoyDataRequest = OnEconomyDataRequest; if (handlerEconomoyDataRequest != null) { @@ -8468,9 +8487,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP } break; - #endregion + #endregion - #region Script Packets + #region Script Packets case PacketType.GetScriptRunning: GetScriptRunningPacket scriptRunning = (GetScriptRunningPacket)Pack; @@ -8520,9 +8539,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP } break; - #endregion + #endregion - #region Gesture Managment + #region Gesture Managment case PacketType.ActivateGestures: ActivateGesturesPacket activateGesturePacket = (ActivateGesturesPacket)Pack; @@ -8589,7 +8608,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } break; - #endregion + #endregion case PacketType.AgentFOV: AgentFOVPacket fovPacket = (AgentFOVPacket)Pack; @@ -8605,7 +8624,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } break; - #region unimplemented handlers + #region unimplemented handlers case PacketType.ViewerStats: // TODO: handle this packet @@ -8628,8 +8647,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP MapItemRequest handlerMapItemRequest = OnMapItemRequest; if (handlerMapItemRequest != null) { - handlerMapItemRequest(this,mirpk.AgentData.Flags, mirpk.AgentData.EstateID, - mirpk.AgentData.Godlike,mirpk.RequestData.ItemType, + handlerMapItemRequest(this, mirpk.AgentData.Flags, mirpk.AgentData.EstateID, + mirpk.AgentData.Godlike, mirpk.RequestData.ItemType, mirpk.RequestData.RegionHandle); } @@ -9037,7 +9056,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP groupMembersRequestPacket.GroupData.RequestID; groupMembersReply.GroupData.MemberCount = memberCount; - for (int i = 0 ; i < blockCount ; i++) + for (int i = 0; i < blockCount; i++) { GroupMembersData m = members[0]; members.RemoveAt(0); @@ -9174,7 +9193,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP groupRoleMembersReply.MemberData = new GroupRoleMembersReplyPacket.MemberDataBlock[pairs]; - for (int i = 0 ; i < pairs ; i++) + for (int i = 0; i < pairs; i++) { GroupRoleMembersData d = mappings[0]; mappings.RemoveAt(0); @@ -9301,7 +9320,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP ParcelDeedToGroup handlerParcelDeedToGroup = OnParcelDeedToGroup; if (handlerParcelDeedToGroup != null) { - handlerParcelDeedToGroup(parcelDeedToGroup.Data.LocalID, parcelDeedToGroup.Data.GroupID,this); + handlerParcelDeedToGroup(parcelDeedToGroup.Data.LocalID, parcelDeedToGroup.Data.GroupID, this); } } @@ -9759,7 +9778,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP PickDelete handlerPickDelete = OnPickDelete; if (handlerPickDelete != null) - handlerPickDelete(this, pickDelete.Data.PickID); + handlerPickDelete(this, pickDelete.Data.PickID); break; case PacketType.PickGodDelete: PickGodDeletePacket pickGodDelete = @@ -9779,7 +9798,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP handlerPickGodDelete(this, pickGodDelete.AgentData.AgentID, pickGodDelete.Data.PickID, - pickGodDelete.Data.QueryID); + pickGodDelete.Data.QueryID); break; case PacketType.PickInfoUpdate: PickInfoUpdatePacket pickInfoUpdate = @@ -9870,7 +9889,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_log.Warn("[CLIENT]: unhandled packet " + Pack); break; - #endregion + #endregion } PacketPool.Instance.ReturnPacket(Pack); @@ -9907,7 +9926,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP //shape.Textures = ntex; return shape; } - + public ClientInfo GetClientInfo() { ClientInfo info = m_udpClient.GetClientInfo(); @@ -9935,7 +9954,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP { ParcelMediaCommandMessagePacket commandMessagePacket = new ParcelMediaCommandMessagePacket(); commandMessagePacket.CommandBlock.Flags = flags; - commandMessagePacket.CommandBlock.Command =(uint) command; + commandMessagePacket.CommandBlock.Command = (uint)command; commandMessagePacket.CommandBlock.Time = time; OutPacket(commandMessagePacket, ThrottleOutPacketType.Unknown); @@ -9963,7 +9982,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP #region Camera - public void SendSetFollowCamProperties (UUID objectID, SortedDictionary parameters) + public void SendSetFollowCamProperties(UUID objectID, SortedDictionary parameters) { SetFollowCamPropertiesPacket packet = (SetFollowCamPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.SetFollowCamProperties); packet.ObjectData.ObjectID = objectID; @@ -9981,7 +10000,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(packet, ThrottleOutPacketType.Task); } - public void SendClearFollowCamProperties (UUID objectID) + public void SendClearFollowCamProperties(UUID objectID) { ClearFollowCamPropertiesPacket packet = (ClearFollowCamPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ClearFollowCamProperties); packet.ObjectData.ObjectID = objectID; @@ -10083,8 +10102,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP { return m_udpClient.GetStats(); } - - public string XReport(string uptime, string version) + + public string XReport(string uptime, string version) { return String.Empty; } @@ -10158,7 +10177,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } //m_log.DebugFormat("[ASSET CACHE]: Asset transfer request for asset which is {0} already known to be missing. Dropping", requestID); - + // FIXME: We never tell the client about assets which do not exist when requested by this transfer mechanism, which can't be right. return; } @@ -10381,7 +10400,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP #endregion #region LookupItem - private struct LookupItem { + private struct LookupItem + { internal MinHeap Heap; internal IHandle Handle; } diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 74175d0..a6ead5e 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -372,23 +372,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP public void ResendUnacked(LLUDPClient udpClient) { - if (udpClient.IsConnected && udpClient.NeedAcks.Count > 0) + if (!udpClient.IsConnected) + return; + + // Disconnect an agent if no packets are received for some time + //FIXME: Make 60 an .ini setting + if (Environment.TickCount - udpClient.TickLastPacketReceived > 1000 * 60) { - // Disconnect an agent if no packets are received for some time - //FIXME: Make 60 an .ini setting - if (Environment.TickCount - udpClient.TickLastPacketReceived > 1000 * 60) - { - m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + udpClient.AgentID); + m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + udpClient.AgentID); - RemoveClient(udpClient); - return; - } + RemoveClient(udpClient); + return; + } + if (udpClient.NeedAcks.Count > 0) + { // Get a list of all of the packets that have been sitting unacked longer than udpClient.RTO List expiredPackets = udpClient.NeedAcks.GetExpiredPackets(udpClient.RTO); if (expiredPackets != null) { + m_log.Debug("[LLUDPSERVER]: Resending " + expiredPackets.Count + " packets to " + udpClient.AgentID); + // Resend packets for (int i = 0; i < expiredPackets.Count; i++) { -- cgit v1.1 From 182693628ca1b81c90f3f0296418437eda406bb5 Mon Sep 17 00:00:00 2001 From: Snowcrash Date: Mon, 19 Oct 2009 13:03:14 +0200 Subject: Fix for index error in llList2String --- .../Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index e10e612..224b3cc 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -4660,7 +4660,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { index = src.Length + index; } - if (index >= src.Length) + if (index >= src.Length || index < 0) { return 0; } @@ -4685,7 +4685,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { index = src.Length + index; } - if (index >= src.Length) + if (index >= src.Length || index < 0) { return 0.0; } @@ -4712,7 +4712,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { index = src.Length + index; } - if (index >= src.Length) + if (index >= src.Length || index < 0) { return String.Empty; } @@ -4726,7 +4726,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { index = src.Length + index; } - if (index >= src.Length) + if (index >= src.Length || index < 0) { return ""; } @@ -4740,7 +4740,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { index = src.Length + index; } - if (index >= src.Length) + if (index >= src.Length || index < 0) { return new LSL_Vector(0, 0, 0); } @@ -4761,7 +4761,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { index = src.Length + index; } - if (index >= src.Length) + if (index >= src.Length || index < 0) { return new LSL_Rotation(0, 0, 0, 1); } -- cgit v1.1 From 26863c04a5f0fc1ed18d15b278d723468427911c Mon Sep 17 00:00:00 2001 From: Melanie Date: Tue, 20 Oct 2009 14:02:11 +0100 Subject: Change "config save" to "config save ", which is mandatory. File name is enforced to NOT be OpenSim.ini --- OpenSim/Region/Application/OpenSim.cs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index ca6a2a3..143dd2a 100644 --- a/OpenSim/Region/Application/OpenSim.cs +++ b/OpenSim/Region/Application/OpenSim.cs @@ -628,8 +628,20 @@ namespace OpenSim break; case "save": - m_log.Info("Saving configuration file: " + Application.iniFilePath); - m_config.Save(Application.iniFilePath); + if (cmdparams.Length < 2) + { + m_log.Error("SYNTAX: " + n + " SAVE FILE"); + return; + } + + if (Application.iniFilePath == cmdparams[1]) + { + m_log.Error("FILE can not be "+Application.iniFilePath); + return; + } + + m_log.Info("Saving configuration file: " + cmdparams[1]); + m_config.Save(cmdparams[1]); break; } } -- cgit v1.1 From 9a5e7222cef7e81fee0c992c4557ac56e9665808 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Tue, 20 Oct 2009 10:33:23 -0700 Subject: * Removing cruft left over from the conversion to the new texture sending and UDP code * Changing the cache modules to only initialize the caches if they are actually enabled. Should save a bit of resources from unused cache systems --- .../Region/ClientStack/ClientStackUserSettings.cs | 48 ---- OpenSim/Region/ClientStack/ThrottleSettings.cs | 57 ---- .../Agent/TextureDownload/TextureDownloadModule.cs | 302 --------------------- .../Agent/TextureDownload/TextureNotFoundSender.cs | 87 ------ .../TextureDownload/UserTextureDownloadService.cs | 265 ------------------ .../TextureSender/Tests/TextureSenderTests.cs | 180 ------------ .../Agent/TextureSender/TextureSender.cs | 212 --------------- .../Region/CoreModules/Asset/CenomeAssetCache.cs | 10 +- OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs | 7 +- .../Region/CoreModules/Asset/FlotsamAssetCache.cs | 51 ++-- .../CoreModules/Asset/GlynnTuckerAssetCache.cs | 43 ++- .../Region/Framework/Interfaces/ITextureSender.cs | 58 ---- 12 files changed, 45 insertions(+), 1275 deletions(-) delete mode 100644 OpenSim/Region/ClientStack/ClientStackUserSettings.cs delete mode 100644 OpenSim/Region/ClientStack/ThrottleSettings.cs delete mode 100644 OpenSim/Region/CoreModules/Agent/TextureDownload/TextureDownloadModule.cs delete mode 100644 OpenSim/Region/CoreModules/Agent/TextureDownload/TextureNotFoundSender.cs delete mode 100644 OpenSim/Region/CoreModules/Agent/TextureDownload/UserTextureDownloadService.cs delete mode 100644 OpenSim/Region/CoreModules/Agent/TextureSender/Tests/TextureSenderTests.cs delete mode 100644 OpenSim/Region/CoreModules/Agent/TextureSender/TextureSender.cs delete mode 100644 OpenSim/Region/Framework/Interfaces/ITextureSender.cs (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/ClientStackUserSettings.cs b/OpenSim/Region/ClientStack/ClientStackUserSettings.cs deleted file mode 100644 index 231b3aa..0000000 --- a/OpenSim/Region/ClientStack/ClientStackUserSettings.cs +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -namespace OpenSim.Region.ClientStack -{ - /// - /// Allow users to tweak parameters for the client stack. - /// - /// At the moment this is very incomplete - other tweakable settings could be added. This is also somewhat LL client - /// oriented right now. - /// - public class ClientStackUserSettings - { - /// - /// The settings for the throttle that governs how many packets in total are sent to the client. - /// - public ThrottleSettings TotalThrottleSettings; - - /// - /// A multiplier applied to all client throttle settings. Default value is x2 (temporarily) - /// - public float ClientThrottleMultipler = 2; - } -} diff --git a/OpenSim/Region/ClientStack/ThrottleSettings.cs b/OpenSim/Region/ClientStack/ThrottleSettings.cs deleted file mode 100644 index fe4718c..0000000 --- a/OpenSim/Region/ClientStack/ThrottleSettings.cs +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -namespace OpenSim.Region.ClientStack -{ - /// - /// Represent throttle settings for a client stack. These settings are in bytes per second - /// - public class ThrottleSettings - { - /// - /// Minimum bytes per second that the throttle can be set to. - /// - public int Min; - - /// - /// Maximum bytes per second that the throttle can be set to. - /// - public int Max; - - /// - /// Current bytes per second that the throttle should be set to. - /// - public int Current; - - public ThrottleSettings(int min, int max, int current) - { - Min = min; - Max = max; - Current = current; - } - } -} diff --git a/OpenSim/Region/CoreModules/Agent/TextureDownload/TextureDownloadModule.cs b/OpenSim/Region/CoreModules/Agent/TextureDownload/TextureDownloadModule.cs deleted file mode 100644 index 71ff28c..0000000 --- a/OpenSim/Region/CoreModules/Agent/TextureDownload/TextureDownloadModule.cs +++ /dev/null @@ -1,302 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Reflection; -using System.Threading; -using log4net; -using Nini.Config; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Framework.Communications.Cache; -using OpenSim.Region.Framework.Interfaces; -using OpenSim.Region.Framework.Scenes; -using BlockingQueue = OpenSim.Framework.BlockingQueue; -using OpenSim.Services.Interfaces; - -namespace OpenSim.Region.CoreModules.Agent.TextureDownload -{ - public class TextureDownloadModule : IRegionModule - { - private static readonly ILog m_log - = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - /// - /// There is one queue for all textures waiting to be sent, regardless of the requesting user. - /// - private readonly BlockingQueue m_queueSenders - = new BlockingQueue(); - - /// - /// Each user has their own texture download service. - /// - private readonly Dictionary m_userTextureServices = - new Dictionary(); - - private Scene m_scene; - private List m_scenes = new List(); - - public TextureDownloadModule() - { - } - - #region IRegionModule Members - - public void Initialise(Scene scene, IConfigSource config) - { - - if (m_scene == null) - { - //m_log.Debug("Creating Texture download module"); - m_scene = scene; - //m_thread = new Thread(new ThreadStart(ProcessTextureSenders)); - //m_thread.Name = "ProcessTextureSenderThread"; - //m_thread.IsBackground = true; - //m_thread.Start(); - //ThreadTracker.Add(m_thread); - } - - if (!m_scenes.Contains(scene)) - { - m_scenes.Add(scene); - m_scene = scene; - m_scene.EventManager.OnNewClient += NewClient; - m_scene.EventManager.OnRemovePresence += EventManager_OnRemovePresence; - } - } - - public void PostInitialise() - { - } - - public void Close() - { - } - - public string Name - { - get { return "TextureDownloadModule"; } - } - - public bool IsSharedModule - { - get { return false; } - } - - #endregion - - /// - /// Cleanup the texture service related objects for the removed presence. - /// - /// - private void EventManager_OnRemovePresence(UUID agentId) - { - UserTextureDownloadService textureService; - - lock (m_userTextureServices) - { - if (m_userTextureServices.TryGetValue(agentId, out textureService)) - { - textureService.Close(); - //m_log.DebugFormat("[TEXTURE MODULE]: Removing UserTextureServices from {0}", m_scene.RegionInfo.RegionName); - m_userTextureServices.Remove(agentId); - } - } - } - - public void NewClient(IClientAPI client) - { - UserTextureDownloadService textureService; - - lock (m_userTextureServices) - { - if (m_userTextureServices.TryGetValue(client.AgentId, out textureService)) - { - textureService.Close(); - //m_log.DebugFormat("[TEXTURE MODULE]: Removing outdated UserTextureServices from {0}", m_scene.RegionInfo.RegionName); - m_userTextureServices.Remove(client.AgentId); - } - m_userTextureServices.Add(client.AgentId, new UserTextureDownloadService(client, m_scene, m_queueSenders)); - } - - client.OnRequestTexture += TextureRequest; - } - - /// I'm commenting this out, and replacing it with the implementation below, which - /// may return a null value. This is necessary for avoiding race conditions - /// recreating UserTextureServices for clients that have just been closed. - /// That behavior of always returning a UserTextureServices was causing the - /// A-B-A problem (mantis #2855). - /// - ///// - ///// Does this user have a registered texture download service? - ///// - ///// - ///// - ///// Always returns true, since a service is created if one does not already exist - //private bool TryGetUserTextureService( - // IClientAPI client, out UserTextureDownloadService textureService) - //{ - // lock (m_userTextureServices) - // { - // if (m_userTextureServices.TryGetValue(client.AgentId, out textureService)) - // { - // //m_log.DebugFormat("[TEXTURE MODULE]: Found existing UserTextureServices in ", m_scene.RegionInfo.RegionName); - // return true; - // } - - // m_log.DebugFormat("[TEXTURE MODULE]: Creating new UserTextureServices in ", m_scene.RegionInfo.RegionName); - // textureService = new UserTextureDownloadService(client, m_scene, m_queueSenders); - // m_userTextureServices.Add(client.AgentId, textureService); - - // return true; - // } - //} - - /// - /// Does this user have a registered texture download service? - /// - /// - /// - /// A UserTextureDownloadService or null in the output parameter, and true or false accordingly. - private bool TryGetUserTextureService(IClientAPI client, out UserTextureDownloadService textureService) - { - lock (m_userTextureServices) - { - if (m_userTextureServices.TryGetValue(client.AgentId, out textureService)) - { - //m_log.DebugFormat("[TEXTURE MODULE]: Found existing UserTextureServices in ", m_scene.RegionInfo.RegionName); - return true; - } - - textureService = null; - return false; - } - } - - /// - /// Start the process of requesting a given texture. - /// - /// - /// - public void TextureRequest(Object sender, TextureRequestArgs e) - { - IClientAPI client = (IClientAPI)sender; - - if (e.Priority == 1016001f) // Preview - { - if (client.Scene is Scene) - { - Scene scene = (Scene)client.Scene; - - CachedUserInfo profile = scene.CommsManager.UserProfileCacheService.GetUserDetails(client.AgentId); - if (profile == null) // Deny unknown user - return; - - IInventoryService invService = scene.InventoryService; - if (invService.GetRootFolder(client.AgentId) == null) // Deny no inventory - return; - - // Diva 2009-08-13: this test doesn't make any sense to many devs - //if (profile.UserProfile.GodLevel < 200 && profile.RootFolder.FindAsset(e.RequestedAssetID) == null) // Deny if not owned - //{ - // m_log.WarnFormat("[TEXTURE]: user {0} doesn't have permissions to texture {1}"); - // return; - //} - - m_log.Debug("Texture preview"); - } - } - - UserTextureDownloadService textureService; - - if (TryGetUserTextureService(client, out textureService)) - { - textureService.HandleTextureRequest(e); - } - } - - /// - /// Entry point for the thread dedicated to processing the texture queue. - /// - public void ProcessTextureSenders() - { - ITextureSender sender = null; - - try - { - while (true) - { - sender = m_queueSenders.Dequeue(); - - if (sender.Cancel) - { - TextureSent(sender); - - sender.Cancel = false; - } - else - { - bool finished = sender.SendTexturePacket(); - if (finished) - { - TextureSent(sender); - } - else - { - m_queueSenders.Enqueue(sender); - } - } - - // Make sure that any sender we currently have can get garbage collected - sender = null; - - //m_log.InfoFormat("[TEXTURE] Texture sender queue size: {0}", m_queueSenders.Count()); - } - } - catch (Exception e) - { - // TODO: Let users in the sim and those entering it and possibly an external watchdog know what has happened - m_log.ErrorFormat( - "[TEXTURE]: Texture send thread terminating with exception. PLEASE REBOOT YOUR SIM - TEXTURES WILL NOT BE AVAILABLE UNTIL YOU DO. Exception is {0}", - e); - } - } - - /// - /// Called when the texture has finished sending. - /// - /// - private void TextureSent(ITextureSender sender) - { - sender.Sending = false; - //m_log.DebugFormat("[TEXTURE]: Removing download stat for {0}", sender.assetID); - m_scene.StatsReporter.AddPendingDownloads(-1); - } - } -} diff --git a/OpenSim/Region/CoreModules/Agent/TextureDownload/TextureNotFoundSender.cs b/OpenSim/Region/CoreModules/Agent/TextureDownload/TextureNotFoundSender.cs deleted file mode 100644 index ba735a7..0000000 --- a/OpenSim/Region/CoreModules/Agent/TextureDownload/TextureNotFoundSender.cs +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Region.Framework.Interfaces; - -namespace OpenSim.Region.CoreModules.Agent.TextureDownload -{ - /// - /// Sends a 'texture not found' packet back to the client - /// - public class TextureNotFoundSender : ITextureSender - { - // private static readonly log4net.ILog m_log - // = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); - - // private IClientAPI m_client; - // private UUID m_textureId; - - public TextureNotFoundSender(IClientAPI client, UUID textureID) - { - //m_client = client; - //m_textureId = textureID; - } - - #region ITextureSender Members - - public bool Sending - { - get { return false; } - set { } - } - - public bool Cancel - { - get { return false; } - set { } - } - - // See ITextureSender - public void UpdateRequest(int discardLevel, uint packetNumber) - { - // No need to implement since priority changes don't affect this operation - } - - // See ITextureSender - public bool SendTexturePacket() - { - // m_log.DebugFormat( - // "[TEXTURE NOT FOUND SENDER]: Informing the client that texture {0} cannot be found", - // m_textureId); - - // XXX Temporarily disabling as this appears to be causing client crashes on at least - // 1.19.0(5) of the Linden Second Life client. - // m_client.SendImageNotFound(m_textureId); - - return true; - } - - #endregion - } -} diff --git a/OpenSim/Region/CoreModules/Agent/TextureDownload/UserTextureDownloadService.cs b/OpenSim/Region/CoreModules/Agent/TextureDownload/UserTextureDownloadService.cs deleted file mode 100644 index 19f0f90..0000000 --- a/OpenSim/Region/CoreModules/Agent/TextureDownload/UserTextureDownloadService.cs +++ /dev/null @@ -1,265 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Reflection; -using log4net; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Framework.Communications.Limit; -using OpenSim.Framework.Statistics; -using OpenSim.Region.Framework.Interfaces; -using OpenSim.Region.Framework.Scenes; - -namespace OpenSim.Region.CoreModules.Agent.TextureDownload -{ - /// - /// This module sets up texture senders in response to client texture requests, and places them on a - /// processing queue once those senders have the appropriate data (i.e. a texture retrieved from the - /// asset cache). - /// - public class UserTextureDownloadService - { -// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - /// - /// True if the service has been closed, probably because a user with texture requests still queued - /// logged out. - /// - private bool closed; - - /// - /// We will allow the client to request the same texture n times before dropping further requests - /// - /// This number includes repeated requests for the same texture at different resolutions (which we don't - /// currently handle properly as far as I know). However, this situation should be handled in a more - /// sophisticated way. - /// -// private static readonly int MAX_ALLOWED_TEXTURE_REQUESTS = 5; - - /// - /// XXX Also going to limit requests for found textures. - /// -// private readonly IRequestLimitStrategy foundTextureLimitStrategy -// = new RepeatLimitStrategy(MAX_ALLOWED_TEXTURE_REQUESTS); - -// private readonly IClientAPI m_client; - private readonly Scene m_scene; - - /// - /// Texture Senders are placed in this queue once they have received their texture from the asset - /// cache. Another module actually invokes the send. - /// -// private readonly OpenSim.Framework.BlockingQueue m_sharedSendersQueue; - - /// - /// Holds texture senders before they have received the appropriate texture from the asset cache. - /// - private readonly Dictionary m_textureSenders = new Dictionary(); - - /// - /// We're going to limit requests for the same missing texture. - /// XXX This is really a temporary solution to deal with the situation where a client continually requests - /// the same missing textures - /// -// private readonly IRequestLimitStrategy missingTextureLimitStrategy -// = new RepeatLimitStrategy(MAX_ALLOWED_TEXTURE_REQUESTS); - - public UserTextureDownloadService( - IClientAPI client, Scene scene, OpenSim.Framework.BlockingQueue sharedQueue) - { -// m_client = client; - m_scene = scene; -// m_sharedSendersQueue = sharedQueue; - } - - /// - /// Handle a texture request. This involves creating a texture sender and placing it on the - /// previously passed in shared queue. - /// - /// - public void HandleTextureRequest(TextureRequestArgs e) - { - - //TextureSender.TextureSender textureSender; - - //TODO: should be working out the data size/ number of packets to be sent for each discard level - //if ((e.DiscardLevel >= 0) || (e.Priority != 0)) - //{ - //lock (m_textureSenders) - //{ - //if (m_textureSenders.TryGetValue(e.RequestedAssetID, out textureSender)) - //{ - // If we've received new non UUID information for this request and it hasn't dispatched - // yet, then update the request accordingly. - // textureSender.UpdateRequest(e.DiscardLevel, e.PacketNumber); - //} - //else - //{ - // m_log.DebugFormat("[TEXTURE]: Received a request for texture {0}", e.RequestedAssetID); - - //if (!foundTextureLimitStrategy.AllowRequest(e.RequestedAssetID)) - //{ - // m_log.DebugFormat( - // "[TEXTURE]: Refusing request for {0} from client {1}", - // e.RequestedAssetID, m_client.AgentId); - - //return; - //} - //else if (!missingTextureLimitStrategy.AllowRequest(e.RequestedAssetID)) - //{ - // if (missingTextureLimitStrategy.IsFirstRefusal(e.RequestedAssetID)) - // { - // if (StatsManager.SimExtraStats != null) - // StatsManager.SimExtraStats.AddBlockedMissingTextureRequest(); - - // Commenting out this message for now as it causes too much noise with other - // debug messages. - // m_log.DebugFormat( - // "[TEXTURE]: Dropping requests for notified missing texture {0} for client {1} since we have received more than {2} requests", - // e.RequestedAssetID, m_client.AgentId, MAX_ALLOWED_TEXTURE_REQUESTS); - // } - - // return; - //} - - m_scene.StatsReporter.AddPendingDownloads(1); - - //TextureSender.TextureSender requestHandler = new TextureSender.TextureSender(m_client, e.DiscardLevel, e.PacketNumber); - //m_textureSenders.Add(e.RequestedAssetID, null); - - m_scene.AssetService.Get(e.RequestedAssetID.ToString(), this, TextureReceived); - - - } - - protected void TextureReceived(string id, Object sender, AssetBase asset) - { - if (asset != null) - TextureCallback(asset.FullID, asset); - } - - /// - /// The callback for the asset cache when a texture has been retrieved. This method queues the - /// texture sender for processing. - /// - /// - /// - public void TextureCallback(UUID textureID, AssetBase texture) - { - //m_log.DebugFormat("[USER TEXTURE DOWNLOAD SERVICE]: Calling TextureCallback with {0}, texture == null is {1}", textureID, (texture == null ? true : false)); - - // There may still be texture requests pending for a logged out client - if (closed) - return; - - /* - lock (m_textureSenders) - { - TextureSender.TextureSender textureSender; - if (m_textureSenders.TryGetValue(textureID, out textureSender)) - { - // XXX It may be perfectly valid for a texture to have no data... but if we pass - // this on to the TextureSender it will blow up, so just discard for now. - // Needs investigation. - if (texture == null || texture.Data == null) - { - if (!missingTextureLimitStrategy.IsMonitoringRequests(textureID)) - { - missingTextureLimitStrategy.MonitorRequests(textureID); - - // m_log.DebugFormat( - // "[TEXTURE]: Queueing first TextureNotFoundSender for {0}, client {1}", - // textureID, m_client.AgentId); - } - - ITextureSender textureNotFoundSender = new TextureNotFoundSender(m_client, textureID); - EnqueueTextureSender(textureNotFoundSender); - } - else - { - if (!textureSender.ImageLoaded) - { - textureSender.TextureReceived(texture); - EnqueueTextureSender(textureSender); - - foundTextureLimitStrategy.MonitorRequests(textureID); - } - } - - //m_log.InfoFormat("[TEXTURE] Removing texture sender with uuid {0}", textureID); - m_textureSenders.Remove(textureID); - //m_log.InfoFormat("[TEXTURE] Current texture senders in dictionary: {0}", m_textureSenders.Count); - } - else - { - m_log.WarnFormat( - "[TEXTURE]: Got a texture uuid {0} with no sender object to handle it, this shouldn't happen", - textureID); - } - } - */ - } - - /// - /// Place a ready texture sender on the processing queue. - /// - /// -// private void EnqueueTextureSender(ITextureSender textureSender) -// { -// textureSender.Cancel = false; -// textureSender.Sending = true; -// -// if (!m_sharedSendersQueue.Contains(textureSender)) -// { -// m_sharedSendersQueue.Enqueue(textureSender); -// } -// } - - /// - /// Close this module. - /// - internal void Close() - { - closed = true; - - lock (m_textureSenders) - { - foreach (TextureSender.TextureSender textureSender in m_textureSenders.Values) - { - textureSender.Cancel = true; - } - - m_textureSenders.Clear(); - } - - // XXX: It might be possible to also remove pending texture requests from the asset cache queues, - // though this might also be more trouble than it's worth. - } - } -} diff --git a/OpenSim/Region/CoreModules/Agent/TextureSender/Tests/TextureSenderTests.cs b/OpenSim/Region/CoreModules/Agent/TextureSender/Tests/TextureSenderTests.cs deleted file mode 100644 index efa275c..0000000 --- a/OpenSim/Region/CoreModules/Agent/TextureSender/Tests/TextureSenderTests.cs +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using NUnit.Framework; -using NUnit.Framework.SyntaxHelpers; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Tests.Common; -using OpenSim.Tests.Common.Mock; - -namespace OpenSim.Region.CoreModules.Agent.TextureSender -{ - [TestFixture] - public class UserTextureSenderTests - { - public UUID uuid1; - public UUID uuid2; - public UUID uuid3; - public UUID uuid4; - public int npackets, testsize; - public TestClient client; - public TextureSender ts; - public static Random random = new Random(); - - [TestFixtureSetUp] - public void Init() - { - AgentCircuitData agent = new AgentCircuitData(); - agent.AgentID = UUID.Random(); - agent.firstname = "testfirstname"; - agent.lastname = "testlastname"; - agent.SessionID = UUID.Zero; - agent.SecureSessionID = UUID.Zero; - agent.circuitcode = 123; - agent.BaseFolder = UUID.Zero; - agent.InventoryFolder = UUID.Zero; - agent.startpos = Vector3.Zero; - agent.CapsPath = "http://wibble.com"; - client = new TestClient(agent, null); - ts = new TextureSender(client, 0, 0); - testsize = random.Next(5000,15000); - npackets = CalculateNumPackets(testsize); - uuid1 = UUID.Random(); - uuid2 = UUID.Random(); - uuid3 = UUID.Random(); - uuid4 = UUID.Random(); - } - - /// - /// Test sending package - /// - [Test] - public void T010_SendPkg() - { - TestHelper.InMethod(); - // Normal sending - AssetBase abase = new AssetBase(uuid1, "asset one"); - byte[] abdata = new byte[testsize]; - random.NextBytes(abdata); - abase.Data = abdata; - bool isdone = false; - ts.TextureReceived(abase); - for (int i = 0; i < npackets; i++) { - isdone = ts.SendTexturePacket(); - } - - Assert.That(isdone,Is.False); - isdone = ts.SendTexturePacket(); - Assert.That(isdone,Is.True); - } - - [Test] - public void T011_UpdateReq() - { - TestHelper.InMethod(); - // Test packet number start - AssetBase abase = new AssetBase(uuid2, "asset two"); - byte[] abdata = new byte[testsize]; - random.NextBytes(abdata); - abase.Data = abdata; - - bool isdone = false; - ts.TextureReceived(abase); - ts.UpdateRequest(0,3); - - for (int i = 0; i < npackets-3; i++) { - isdone = ts.SendTexturePacket(); - } - - Assert.That(isdone,Is.False); - isdone = ts.SendTexturePacket(); - Assert.That(isdone,Is.True); - - // Test discard level - abase = new AssetBase(uuid3, "asset three"); - abdata = new byte[testsize]; - random.NextBytes(abdata); - abase.Data = abdata; - isdone = false; - ts.TextureReceived(abase); - ts.UpdateRequest(-1,0); - - Assert.That(ts.SendTexturePacket(),Is.True); - - abase = new AssetBase(uuid4, "asset four"); - abdata = new byte[testsize]; - random.NextBytes(abdata); - abase.Data = abdata; - isdone = false; - ts.TextureReceived(abase); - ts.UpdateRequest(0,5); - - for (int i = 0; i < npackets-5; i++) { - isdone = ts.SendTexturePacket(); - } - Assert.That(isdone,Is.False); - isdone = ts.SendTexturePacket(); - Assert.That(isdone,Is.True); - } - - [Test] - public void T999_FinishStatus() - { - TestHelper.InMethod(); - // Of the 4 assets "sent", only 2 sent the first part. - Assert.That(client.sentdatapkt.Count,Is.EqualTo(2)); - - // Sum of all packets sent: - int totalpkts = (npackets) + (npackets - 2) + (npackets - 4); - Assert.That(client.sentpktpkt.Count,Is.EqualTo(totalpkts)); - } - - /// - /// Calculate the number of packets that will be required to send the texture loaded into this sender - /// This is actually the number of 1000 byte packets not including an initial 600 byte packet... - /// Borrowed from TextureSender.cs - /// - /// - /// - private int CalculateNumPackets(int length) - { - int numPackets = 0; - - if (length > 600) - { - //over 600 bytes so split up file - int restData = (length - 600); - int restPackets = ((restData + 999) / 1000); - numPackets = restPackets; - } - - return numPackets; - } - } -} diff --git a/OpenSim/Region/CoreModules/Agent/TextureSender/TextureSender.cs b/OpenSim/Region/CoreModules/Agent/TextureSender/TextureSender.cs deleted file mode 100644 index 62c5a32..0000000 --- a/OpenSim/Region/CoreModules/Agent/TextureSender/TextureSender.cs +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Reflection; -using log4net; -using OpenSim.Framework; -using OpenSim.Region.Framework.Interfaces; - -namespace OpenSim.Region.CoreModules.Agent.TextureSender -{ - /// - /// A TextureSender handles the process of receiving a texture requested by the client from the - /// AssetCache, and then sending that texture back to the client. - /// - public class TextureSender : ITextureSender - { - private static readonly ILog m_log - = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - /// - /// Records the number of times texture send has been called. - /// - public int counter = 0; - - public bool ImageLoaded = false; - - /// - /// Holds the texture asset to send. - /// - private AssetBase m_asset; - - //public UUID assetID { get { return m_asset.FullID; } } - - // private bool m_cancel = false; - - // See ITextureSender - - // private bool m_sending = false; - - /// - /// This is actually the number of extra packets required to send the texture data! We always assume - /// at least one is required. - /// - private int NumPackets = 0; - - /// - /// Holds the packet number to send next. In this case, each packet is 1000 bytes long and starts - /// at the 600th byte (0th indexed). - /// - private int PacketCounter = 0; - - private int RequestedDiscardLevel = -1; - private IClientAPI RequestUser; - private uint StartPacketNumber = 0; - - public TextureSender(IClientAPI client, int discardLevel, uint packetNumber) - { - RequestUser = client; - RequestedDiscardLevel = discardLevel; - StartPacketNumber = packetNumber; - } - - #region ITextureSender Members - - public bool Cancel - { - get { return false; } - set - { - // m_cancel = value; - } - } - - public bool Sending - { - get { return false; } - set - { - // m_sending = value; - } - } - - // See ITextureSender - public void UpdateRequest(int discardLevel, uint packetNumber) - { - RequestedDiscardLevel = discardLevel; - StartPacketNumber = packetNumber; - PacketCounter = (int)StartPacketNumber; - } - - // See ITextureSender - public bool SendTexturePacket() - { - //m_log.DebugFormat("[TEXTURE SENDER]: Sending packet for {0}", m_asset.FullID); - - SendPacket(); - counter++; - if ((NumPackets == 0) || (RequestedDiscardLevel == -1) || (PacketCounter > NumPackets) || - ((RequestedDiscardLevel > 0) && (counter > 50 + (NumPackets / (RequestedDiscardLevel + 1))))) - { - return true; - } - return false; - } - - #endregion - - /// - /// Load up the texture data to send. - /// - /// - public void TextureReceived(AssetBase asset) - { - m_asset = asset; - NumPackets = CalculateNumPackets(asset.Data.Length); - PacketCounter = (int)StartPacketNumber; - ImageLoaded = true; - } - - /// - /// Sends a texture packet to the client. - /// - private void SendPacket() - { - if (PacketCounter <= NumPackets) - { - if (PacketCounter == 0) - { - if (NumPackets == 0) - { - RequestUser.SendImageFirstPart(1, m_asset.FullID, (uint)m_asset.Data.Length, m_asset.Data, 2); - PacketCounter++; - } - else - { - byte[] ImageData1 = new byte[600]; - Array.Copy(m_asset.Data, 0, ImageData1, 0, 600); - - RequestUser.SendImageFirstPart( - (ushort)(NumPackets), m_asset.FullID, (uint)m_asset.Data.Length, ImageData1, 2); - PacketCounter++; - } - } - else - { - int size = m_asset.Data.Length - 600 - (1000 * (PacketCounter - 1)); - if (size > 1000) size = 1000; - byte[] imageData = new byte[size]; - try - { - Array.Copy(m_asset.Data, 600 + (1000 * (PacketCounter - 1)), imageData, 0, size); - } - catch (ArgumentOutOfRangeException) - { - m_log.Error("[TEXTURE SENDER]: Unable to separate texture into multiple packets: Array bounds failure on asset:" + - m_asset.ID); - return; - } - - RequestUser.SendImageNextPart((ushort)PacketCounter, m_asset.FullID, imageData); - PacketCounter++; - } - } - } - - /// - /// Calculate the number of packets that will be required to send the texture loaded into this sender - /// This is actually the number of 1000 byte packets not including an initial 600 byte packet... - /// - /// - /// - private int CalculateNumPackets(int length) - { - int numPackets = 0; - - if (length > 600) - { - //over 600 bytes so split up file - int restData = (length - 600); - int restPackets = ((restData + 999) / 1000); - numPackets = restPackets; - } - - return numPackets; - } - } -} diff --git a/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs b/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs index 66ca7c2..1add0ab 100644 --- a/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs @@ -155,14 +155,6 @@ namespace OpenSim.Region.CoreModules.Asset private int m_hitCount; /// - /// Initialize asset cache module with default parameters. - /// - public void Initialize() - { - Initialize(DefaultMaxSize, DefaultMaxCount, DefaultExpirationTime); - } - - /// /// Initialize asset cache module, with custom parameters. /// /// @@ -174,7 +166,7 @@ namespace OpenSim.Region.CoreModules.Asset /// /// Asset's expiration time. /// - public void Initialize(long maximalSize, int maximalCount, TimeSpan expirationTime) + protected void Initialize(long maximalSize, int maximalCount, TimeSpan expirationTime) { if (maximalSize <= 0 || maximalCount <= 0) { diff --git a/OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs b/OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs index 0a7e736..7da5e7a 100644 --- a/OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs @@ -44,10 +44,8 @@ namespace OpenSim.Region.CoreModules.Asset LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType); - private bool m_Enabled = false; - private Cache m_Cache = new Cache(CacheMedium.Memory, - CacheStrategy.Aggressive, - CacheFlags.AllowUpdate); + private bool m_Enabled; + private Cache m_Cache; public string Name { @@ -77,6 +75,7 @@ namespace OpenSim.Region.CoreModules.Asset return; } + m_Cache = new Cache(CacheMedium.Memory, CacheStrategy.Aggressive, CacheFlags.AllowUpdate); m_Enabled = true; m_log.Info("[ASSET CACHE]: Core asset cache enabled"); diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs index d45c35c..cbdca16 100644 --- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs @@ -61,24 +61,23 @@ namespace Flotsam.RegionModules.AssetCache LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType); - private bool m_Enabled = false; + private bool m_Enabled; private const string m_ModuleName = "FlotsamAssetCache"; private const string m_DefaultCacheDirectory = m_ModuleName; private string m_CacheDirectory = m_DefaultCacheDirectory; - - private List m_InvalidChars = new List(); + private readonly List m_InvalidChars = new List(); private int m_LogLevel = 1; private ulong m_HitRateDisplay = 1; // How often to display hit statistics, given in requests - private static ulong m_Requests = 0; - private static ulong m_RequestsForInprogress = 0; - private static ulong m_DiskHits = 0; - private static ulong m_MemoryHits = 0; - private static double m_HitRateMemory = 0.0; - private static double m_HitRateFile = 0.0; + private static ulong m_Requests; + private static ulong m_RequestsForInprogress; + private static ulong m_DiskHits; + private static ulong m_MemoryHits; + private static double m_HitRateMemory; + private static double m_HitRateFile; #if WAIT_ON_INPROGRESS_REQUESTS private Dictionary m_CurrentlyWriting = new Dictionary(); @@ -87,7 +86,7 @@ namespace Flotsam.RegionModules.AssetCache private List m_CurrentlyWriting = new List(); #endif - private ExpiringCache m_MemoryCache = new ExpiringCache(); + private ExpiringCache m_MemoryCache; private bool m_MemoryCacheEnabled = true; // Expiration is expressed in hours. @@ -101,12 +100,12 @@ namespace Flotsam.RegionModules.AssetCache private static int m_CacheDirectoryTierLen = 3; private static int m_CacheWarnAt = 30000; - private System.Timers.Timer m_CachCleanTimer = new System.Timers.Timer(); + private System.Timers.Timer m_CacheCleanTimer; - private IAssetService m_AssetService = null; + private IAssetService m_AssetService; private List m_Scenes = new List(); - private bool m_DeepScanBeforePurge = false; + private bool m_DeepScanBeforePurge; public FlotsamAssetCache() { @@ -128,14 +127,15 @@ namespace Flotsam.RegionModules.AssetCache { IConfig moduleConfig = source.Configs["Modules"]; - if (moduleConfig != null) { - string name = moduleConfig.GetString("AssetCaching", ""); + string name = moduleConfig.GetString("AssetCaching", String.Empty); if (name == Name) { + m_MemoryCache = new ExpiringCache(); m_Enabled = true; + m_log.InfoFormat("[FLOTSAM ASSET CACHE]: {0} enabled", this.Name); IConfig assetConfig = source.Configs["AssetCache"]; @@ -163,21 +163,11 @@ namespace Flotsam.RegionModules.AssetCache m_FileExpirationCleanupTimer = TimeSpan.FromHours(assetConfig.GetDouble("FileCleanupTimer", m_DefaultFileExpiration)); if ((m_FileExpiration > TimeSpan.Zero) && (m_FileExpirationCleanupTimer > TimeSpan.Zero)) { - m_CachCleanTimer.Interval = m_FileExpirationCleanupTimer.TotalMilliseconds; - m_CachCleanTimer.AutoReset = true; - m_CachCleanTimer.Elapsed += CleanupExpiredFiles; - m_CachCleanTimer.Enabled = true; - lock (m_CachCleanTimer) - { - m_CachCleanTimer.Start(); - } - } - else - { - lock (m_CachCleanTimer) - { - m_CachCleanTimer.Enabled = false; - } + m_CacheCleanTimer = new System.Timers.Timer(m_FileExpirationCleanupTimer.TotalMilliseconds); + m_CacheCleanTimer.AutoReset = true; + m_CacheCleanTimer.Elapsed += CleanupExpiredFiles; + lock (m_CacheCleanTimer) + m_CacheCleanTimer.Start(); } m_CacheDirectoryTiers = assetConfig.GetInt("CacheDirectoryTiers", 1); @@ -208,7 +198,6 @@ namespace Flotsam.RegionModules.AssetCache MainConsole.Instance.Commands.AddCommand(this.Name, true, "fcache clear", "fcache clear [file] [memory]", "Remove all assets in the file and/or memory cache", HandleConsoleCommand); MainConsole.Instance.Commands.AddCommand(this.Name, true, "fcache assets", "fcache assets", "Attempt a deep scan and cache of all assets in all scenes", HandleConsoleCommand); MainConsole.Instance.Commands.AddCommand(this.Name, true, "fcache expire", "fcache expire ", "Purge cached assets older then the specified date/time", HandleConsoleCommand); - } } } diff --git a/OpenSim/Region/CoreModules/Asset/GlynnTuckerAssetCache.cs b/OpenSim/Region/CoreModules/Asset/GlynnTuckerAssetCache.cs index 4869f5d..1365e69 100644 --- a/OpenSim/Region/CoreModules/Asset/GlynnTuckerAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/GlynnTuckerAssetCache.cs @@ -45,11 +45,13 @@ namespace OpenSim.Region.CoreModules.Asset LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType); - private bool m_Enabled = false; - private ICache m_Cache = new GlynnTucker.Cache.SimpleMemoryCache(); + private bool m_Enabled; + private ICache m_Cache; + private ulong m_Hits; + private ulong m_Requests; // Instrumentation - private uint m_DebugRate = 0; + private uint m_DebugRate; public Type ReplaceableInterface { @@ -72,6 +74,7 @@ namespace OpenSim.Region.CoreModules.Asset if (name == Name) { + m_Cache = new GlynnTucker.Cache.SimpleMemoryCache(); m_Enabled = true; m_log.Info("[ASSET CACHE]: GlynnTucker asset cache enabled"); @@ -80,7 +83,6 @@ namespace OpenSim.Region.CoreModules.Asset IConfig cacheConfig = source.Configs["AssetCache"]; if (cacheConfig != null) m_DebugRate = (uint)cacheConfig.GetInt("DebugRate", 0); - } } } @@ -117,24 +119,6 @@ namespace OpenSim.Region.CoreModules.Asset m_Cache.AddOrUpdate(asset.ID, asset); } - private ulong m_Hits = 0; - private ulong m_Requests = 0; - private void Debug(Object asset) - { - // Temporary instrumentation to measure the hit/miss rate - if (m_DebugRate > 0) - { - m_Requests++; - if (asset != null) - m_Hits++; - - if ((m_Requests % m_DebugRate) == 0) - m_log.DebugFormat("[ASSET CACHE]: Hit Rate {0} / {1} == {2}%", m_Hits, m_Requests, ((float)m_Hits / m_Requests) * 100); - - } - // End instrumentation - } - public AssetBase Get(string id) { Object asset = null; @@ -156,5 +140,20 @@ namespace OpenSim.Region.CoreModules.Asset { m_Cache.Clear(); } + + private void Debug(Object asset) + { + // Temporary instrumentation to measure the hit/miss rate + if (m_DebugRate > 0) + { + ++m_Requests; + if (asset != null) + ++m_Hits; + + if ((m_Requests % m_DebugRate) == 0) + m_log.DebugFormat("[ASSET CACHE]: Hit Rate {0} / {1} == {2}%", m_Hits, m_Requests, ((float)m_Hits / (float)m_Requests) * 100.0f); + } + // End instrumentation + } } } diff --git a/OpenSim/Region/Framework/Interfaces/ITextureSender.cs b/OpenSim/Region/Framework/Interfaces/ITextureSender.cs deleted file mode 100644 index c469ae8..0000000 --- a/OpenSim/Region/Framework/Interfaces/ITextureSender.cs +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -namespace OpenSim.Region.Framework.Interfaces -{ - /// - /// Interface for an object which can send texture information to a client - /// - public interface ITextureSender - { - /// - /// Are we in the process of sending the texture? - /// - bool Sending { get; set; } - - /// - /// Has the texture send been cancelled? - /// - bool Cancel { get; set; } - - /// - /// Update the non data properties of a texture request - /// - /// - /// - void UpdateRequest(int discardLevel, uint packetNumber); - - /// - /// Send a texture packet to the client. - /// - /// True if the last packet has been sent, false otherwise. - bool SendTexturePacket(); - } -} -- cgit v1.1 From 8151190a45b98645efb06ea28b1758ffbc75cf7e Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Tue, 20 Oct 2009 10:56:15 -0700 Subject: * Removing ODEPrim and ODECharacter GetHashCode() overrides since they were based on something that could change * Tweaked a few other GetHashCode() overrides to bring them in line with MSDN recommendations --- OpenSim/Region/Physics/OdePlugin/ODECharacter.cs | 5 ----- OpenSim/Region/Physics/OdePlugin/ODEPrim.cs | 5 ----- OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs | 2 +- 3 files changed, 1 insertion(+), 11 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs index ef0e56e..71ace16 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs @@ -231,11 +231,6 @@ namespace OpenSim.Region.Physics.OdePlugin set { m_localID = value; } } - public override int GetHashCode() - { - return (int)m_localID; - } - public override bool Grabbed { set { return; } diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs index 63bfc90..4581d22 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs @@ -259,11 +259,6 @@ namespace OpenSim.Region.Physics.OdePlugin m_localID = value; } } - public override int GetHashCode() - { - return (int)m_localID; - } - public override bool Grabbed { set { return; } diff --git a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs index 2842f6b..3f38bb6 100644 --- a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs +++ b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs @@ -1975,7 +1975,7 @@ namespace OpenSim.Region.ScriptEngine.Shared public override int GetHashCode() { - return Convert.ToInt32(value); + return value.GetHashCode(); } -- cgit v1.1 From edd393ff308db2bf6802654dc37de6aa6a10f78a Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Tue, 20 Oct 2009 11:58:23 -0700 Subject: Reverting the deletion of files related to texture sending until we figure out exactly what is and isn't needed --- .../Region/ClientStack/LindenUDP/LLUDPClient.cs | 2 + .../Agent/TextureDownload/TextureDownloadModule.cs | 302 +++++++++++++++++++++ .../Agent/TextureDownload/TextureNotFoundSender.cs | 87 ++++++ .../TextureDownload/UserTextureDownloadService.cs | 265 ++++++++++++++++++ .../Agent/TextureSender/TextureSender.cs | 212 +++++++++++++++ .../Region/Framework/Interfaces/ITextureSender.cs | 58 ++++ 6 files changed, 926 insertions(+) create mode 100644 OpenSim/Region/CoreModules/Agent/TextureDownload/TextureDownloadModule.cs create mode 100644 OpenSim/Region/CoreModules/Agent/TextureDownload/TextureNotFoundSender.cs create mode 100644 OpenSim/Region/CoreModules/Agent/TextureDownload/UserTextureDownloadService.cs create mode 100644 OpenSim/Region/CoreModules/Agent/TextureSender/TextureSender.cs create mode 100644 OpenSim/Region/Framework/Interfaces/ITextureSender.cs (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs index 4b6a358..4a3a04e 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs @@ -163,7 +163,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP CircuitCode = circuitCode; m_udpServer = server; m_defaultThrottleRates = rates; + // Create a token bucket throttle for this client that has the scene token bucket as a parent m_throttle = new TokenBucket(parentThrottle, rates.TotalLimit, rates.Total); + // Create an array of token buckets for this clients different throttle categories m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) diff --git a/OpenSim/Region/CoreModules/Agent/TextureDownload/TextureDownloadModule.cs b/OpenSim/Region/CoreModules/Agent/TextureDownload/TextureDownloadModule.cs new file mode 100644 index 0000000..71ff28c --- /dev/null +++ b/OpenSim/Region/CoreModules/Agent/TextureDownload/TextureDownloadModule.cs @@ -0,0 +1,302 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Threading; +using log4net; +using Nini.Config; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Framework.Communications.Cache; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using BlockingQueue = OpenSim.Framework.BlockingQueue; +using OpenSim.Services.Interfaces; + +namespace OpenSim.Region.CoreModules.Agent.TextureDownload +{ + public class TextureDownloadModule : IRegionModule + { + private static readonly ILog m_log + = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + /// + /// There is one queue for all textures waiting to be sent, regardless of the requesting user. + /// + private readonly BlockingQueue m_queueSenders + = new BlockingQueue(); + + /// + /// Each user has their own texture download service. + /// + private readonly Dictionary m_userTextureServices = + new Dictionary(); + + private Scene m_scene; + private List m_scenes = new List(); + + public TextureDownloadModule() + { + } + + #region IRegionModule Members + + public void Initialise(Scene scene, IConfigSource config) + { + + if (m_scene == null) + { + //m_log.Debug("Creating Texture download module"); + m_scene = scene; + //m_thread = new Thread(new ThreadStart(ProcessTextureSenders)); + //m_thread.Name = "ProcessTextureSenderThread"; + //m_thread.IsBackground = true; + //m_thread.Start(); + //ThreadTracker.Add(m_thread); + } + + if (!m_scenes.Contains(scene)) + { + m_scenes.Add(scene); + m_scene = scene; + m_scene.EventManager.OnNewClient += NewClient; + m_scene.EventManager.OnRemovePresence += EventManager_OnRemovePresence; + } + } + + public void PostInitialise() + { + } + + public void Close() + { + } + + public string Name + { + get { return "TextureDownloadModule"; } + } + + public bool IsSharedModule + { + get { return false; } + } + + #endregion + + /// + /// Cleanup the texture service related objects for the removed presence. + /// + /// + private void EventManager_OnRemovePresence(UUID agentId) + { + UserTextureDownloadService textureService; + + lock (m_userTextureServices) + { + if (m_userTextureServices.TryGetValue(agentId, out textureService)) + { + textureService.Close(); + //m_log.DebugFormat("[TEXTURE MODULE]: Removing UserTextureServices from {0}", m_scene.RegionInfo.RegionName); + m_userTextureServices.Remove(agentId); + } + } + } + + public void NewClient(IClientAPI client) + { + UserTextureDownloadService textureService; + + lock (m_userTextureServices) + { + if (m_userTextureServices.TryGetValue(client.AgentId, out textureService)) + { + textureService.Close(); + //m_log.DebugFormat("[TEXTURE MODULE]: Removing outdated UserTextureServices from {0}", m_scene.RegionInfo.RegionName); + m_userTextureServices.Remove(client.AgentId); + } + m_userTextureServices.Add(client.AgentId, new UserTextureDownloadService(client, m_scene, m_queueSenders)); + } + + client.OnRequestTexture += TextureRequest; + } + + /// I'm commenting this out, and replacing it with the implementation below, which + /// may return a null value. This is necessary for avoiding race conditions + /// recreating UserTextureServices for clients that have just been closed. + /// That behavior of always returning a UserTextureServices was causing the + /// A-B-A problem (mantis #2855). + /// + ///// + ///// Does this user have a registered texture download service? + ///// + ///// + ///// + ///// Always returns true, since a service is created if one does not already exist + //private bool TryGetUserTextureService( + // IClientAPI client, out UserTextureDownloadService textureService) + //{ + // lock (m_userTextureServices) + // { + // if (m_userTextureServices.TryGetValue(client.AgentId, out textureService)) + // { + // //m_log.DebugFormat("[TEXTURE MODULE]: Found existing UserTextureServices in ", m_scene.RegionInfo.RegionName); + // return true; + // } + + // m_log.DebugFormat("[TEXTURE MODULE]: Creating new UserTextureServices in ", m_scene.RegionInfo.RegionName); + // textureService = new UserTextureDownloadService(client, m_scene, m_queueSenders); + // m_userTextureServices.Add(client.AgentId, textureService); + + // return true; + // } + //} + + /// + /// Does this user have a registered texture download service? + /// + /// + /// + /// A UserTextureDownloadService or null in the output parameter, and true or false accordingly. + private bool TryGetUserTextureService(IClientAPI client, out UserTextureDownloadService textureService) + { + lock (m_userTextureServices) + { + if (m_userTextureServices.TryGetValue(client.AgentId, out textureService)) + { + //m_log.DebugFormat("[TEXTURE MODULE]: Found existing UserTextureServices in ", m_scene.RegionInfo.RegionName); + return true; + } + + textureService = null; + return false; + } + } + + /// + /// Start the process of requesting a given texture. + /// + /// + /// + public void TextureRequest(Object sender, TextureRequestArgs e) + { + IClientAPI client = (IClientAPI)sender; + + if (e.Priority == 1016001f) // Preview + { + if (client.Scene is Scene) + { + Scene scene = (Scene)client.Scene; + + CachedUserInfo profile = scene.CommsManager.UserProfileCacheService.GetUserDetails(client.AgentId); + if (profile == null) // Deny unknown user + return; + + IInventoryService invService = scene.InventoryService; + if (invService.GetRootFolder(client.AgentId) == null) // Deny no inventory + return; + + // Diva 2009-08-13: this test doesn't make any sense to many devs + //if (profile.UserProfile.GodLevel < 200 && profile.RootFolder.FindAsset(e.RequestedAssetID) == null) // Deny if not owned + //{ + // m_log.WarnFormat("[TEXTURE]: user {0} doesn't have permissions to texture {1}"); + // return; + //} + + m_log.Debug("Texture preview"); + } + } + + UserTextureDownloadService textureService; + + if (TryGetUserTextureService(client, out textureService)) + { + textureService.HandleTextureRequest(e); + } + } + + /// + /// Entry point for the thread dedicated to processing the texture queue. + /// + public void ProcessTextureSenders() + { + ITextureSender sender = null; + + try + { + while (true) + { + sender = m_queueSenders.Dequeue(); + + if (sender.Cancel) + { + TextureSent(sender); + + sender.Cancel = false; + } + else + { + bool finished = sender.SendTexturePacket(); + if (finished) + { + TextureSent(sender); + } + else + { + m_queueSenders.Enqueue(sender); + } + } + + // Make sure that any sender we currently have can get garbage collected + sender = null; + + //m_log.InfoFormat("[TEXTURE] Texture sender queue size: {0}", m_queueSenders.Count()); + } + } + catch (Exception e) + { + // TODO: Let users in the sim and those entering it and possibly an external watchdog know what has happened + m_log.ErrorFormat( + "[TEXTURE]: Texture send thread terminating with exception. PLEASE REBOOT YOUR SIM - TEXTURES WILL NOT BE AVAILABLE UNTIL YOU DO. Exception is {0}", + e); + } + } + + /// + /// Called when the texture has finished sending. + /// + /// + private void TextureSent(ITextureSender sender) + { + sender.Sending = false; + //m_log.DebugFormat("[TEXTURE]: Removing download stat for {0}", sender.assetID); + m_scene.StatsReporter.AddPendingDownloads(-1); + } + } +} diff --git a/OpenSim/Region/CoreModules/Agent/TextureDownload/TextureNotFoundSender.cs b/OpenSim/Region/CoreModules/Agent/TextureDownload/TextureNotFoundSender.cs new file mode 100644 index 0000000..ba735a7 --- /dev/null +++ b/OpenSim/Region/CoreModules/Agent/TextureDownload/TextureNotFoundSender.cs @@ -0,0 +1,87 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; + +namespace OpenSim.Region.CoreModules.Agent.TextureDownload +{ + /// + /// Sends a 'texture not found' packet back to the client + /// + public class TextureNotFoundSender : ITextureSender + { + // private static readonly log4net.ILog m_log + // = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + + // private IClientAPI m_client; + // private UUID m_textureId; + + public TextureNotFoundSender(IClientAPI client, UUID textureID) + { + //m_client = client; + //m_textureId = textureID; + } + + #region ITextureSender Members + + public bool Sending + { + get { return false; } + set { } + } + + public bool Cancel + { + get { return false; } + set { } + } + + // See ITextureSender + public void UpdateRequest(int discardLevel, uint packetNumber) + { + // No need to implement since priority changes don't affect this operation + } + + // See ITextureSender + public bool SendTexturePacket() + { + // m_log.DebugFormat( + // "[TEXTURE NOT FOUND SENDER]: Informing the client that texture {0} cannot be found", + // m_textureId); + + // XXX Temporarily disabling as this appears to be causing client crashes on at least + // 1.19.0(5) of the Linden Second Life client. + // m_client.SendImageNotFound(m_textureId); + + return true; + } + + #endregion + } +} diff --git a/OpenSim/Region/CoreModules/Agent/TextureDownload/UserTextureDownloadService.cs b/OpenSim/Region/CoreModules/Agent/TextureDownload/UserTextureDownloadService.cs new file mode 100644 index 0000000..19f0f90 --- /dev/null +++ b/OpenSim/Region/CoreModules/Agent/TextureDownload/UserTextureDownloadService.cs @@ -0,0 +1,265 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Reflection; +using log4net; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Framework.Communications.Limit; +using OpenSim.Framework.Statistics; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; + +namespace OpenSim.Region.CoreModules.Agent.TextureDownload +{ + /// + /// This module sets up texture senders in response to client texture requests, and places them on a + /// processing queue once those senders have the appropriate data (i.e. a texture retrieved from the + /// asset cache). + /// + public class UserTextureDownloadService + { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + /// + /// True if the service has been closed, probably because a user with texture requests still queued + /// logged out. + /// + private bool closed; + + /// + /// We will allow the client to request the same texture n times before dropping further requests + /// + /// This number includes repeated requests for the same texture at different resolutions (which we don't + /// currently handle properly as far as I know). However, this situation should be handled in a more + /// sophisticated way. + /// +// private static readonly int MAX_ALLOWED_TEXTURE_REQUESTS = 5; + + /// + /// XXX Also going to limit requests for found textures. + /// +// private readonly IRequestLimitStrategy foundTextureLimitStrategy +// = new RepeatLimitStrategy(MAX_ALLOWED_TEXTURE_REQUESTS); + +// private readonly IClientAPI m_client; + private readonly Scene m_scene; + + /// + /// Texture Senders are placed in this queue once they have received their texture from the asset + /// cache. Another module actually invokes the send. + /// +// private readonly OpenSim.Framework.BlockingQueue m_sharedSendersQueue; + + /// + /// Holds texture senders before they have received the appropriate texture from the asset cache. + /// + private readonly Dictionary m_textureSenders = new Dictionary(); + + /// + /// We're going to limit requests for the same missing texture. + /// XXX This is really a temporary solution to deal with the situation where a client continually requests + /// the same missing textures + /// +// private readonly IRequestLimitStrategy missingTextureLimitStrategy +// = new RepeatLimitStrategy(MAX_ALLOWED_TEXTURE_REQUESTS); + + public UserTextureDownloadService( + IClientAPI client, Scene scene, OpenSim.Framework.BlockingQueue sharedQueue) + { +// m_client = client; + m_scene = scene; +// m_sharedSendersQueue = sharedQueue; + } + + /// + /// Handle a texture request. This involves creating a texture sender and placing it on the + /// previously passed in shared queue. + /// + /// + public void HandleTextureRequest(TextureRequestArgs e) + { + + //TextureSender.TextureSender textureSender; + + //TODO: should be working out the data size/ number of packets to be sent for each discard level + //if ((e.DiscardLevel >= 0) || (e.Priority != 0)) + //{ + //lock (m_textureSenders) + //{ + //if (m_textureSenders.TryGetValue(e.RequestedAssetID, out textureSender)) + //{ + // If we've received new non UUID information for this request and it hasn't dispatched + // yet, then update the request accordingly. + // textureSender.UpdateRequest(e.DiscardLevel, e.PacketNumber); + //} + //else + //{ + // m_log.DebugFormat("[TEXTURE]: Received a request for texture {0}", e.RequestedAssetID); + + //if (!foundTextureLimitStrategy.AllowRequest(e.RequestedAssetID)) + //{ + // m_log.DebugFormat( + // "[TEXTURE]: Refusing request for {0} from client {1}", + // e.RequestedAssetID, m_client.AgentId); + + //return; + //} + //else if (!missingTextureLimitStrategy.AllowRequest(e.RequestedAssetID)) + //{ + // if (missingTextureLimitStrategy.IsFirstRefusal(e.RequestedAssetID)) + // { + // if (StatsManager.SimExtraStats != null) + // StatsManager.SimExtraStats.AddBlockedMissingTextureRequest(); + + // Commenting out this message for now as it causes too much noise with other + // debug messages. + // m_log.DebugFormat( + // "[TEXTURE]: Dropping requests for notified missing texture {0} for client {1} since we have received more than {2} requests", + // e.RequestedAssetID, m_client.AgentId, MAX_ALLOWED_TEXTURE_REQUESTS); + // } + + // return; + //} + + m_scene.StatsReporter.AddPendingDownloads(1); + + //TextureSender.TextureSender requestHandler = new TextureSender.TextureSender(m_client, e.DiscardLevel, e.PacketNumber); + //m_textureSenders.Add(e.RequestedAssetID, null); + + m_scene.AssetService.Get(e.RequestedAssetID.ToString(), this, TextureReceived); + + + } + + protected void TextureReceived(string id, Object sender, AssetBase asset) + { + if (asset != null) + TextureCallback(asset.FullID, asset); + } + + /// + /// The callback for the asset cache when a texture has been retrieved. This method queues the + /// texture sender for processing. + /// + /// + /// + public void TextureCallback(UUID textureID, AssetBase texture) + { + //m_log.DebugFormat("[USER TEXTURE DOWNLOAD SERVICE]: Calling TextureCallback with {0}, texture == null is {1}", textureID, (texture == null ? true : false)); + + // There may still be texture requests pending for a logged out client + if (closed) + return; + + /* + lock (m_textureSenders) + { + TextureSender.TextureSender textureSender; + if (m_textureSenders.TryGetValue(textureID, out textureSender)) + { + // XXX It may be perfectly valid for a texture to have no data... but if we pass + // this on to the TextureSender it will blow up, so just discard for now. + // Needs investigation. + if (texture == null || texture.Data == null) + { + if (!missingTextureLimitStrategy.IsMonitoringRequests(textureID)) + { + missingTextureLimitStrategy.MonitorRequests(textureID); + + // m_log.DebugFormat( + // "[TEXTURE]: Queueing first TextureNotFoundSender for {0}, client {1}", + // textureID, m_client.AgentId); + } + + ITextureSender textureNotFoundSender = new TextureNotFoundSender(m_client, textureID); + EnqueueTextureSender(textureNotFoundSender); + } + else + { + if (!textureSender.ImageLoaded) + { + textureSender.TextureReceived(texture); + EnqueueTextureSender(textureSender); + + foundTextureLimitStrategy.MonitorRequests(textureID); + } + } + + //m_log.InfoFormat("[TEXTURE] Removing texture sender with uuid {0}", textureID); + m_textureSenders.Remove(textureID); + //m_log.InfoFormat("[TEXTURE] Current texture senders in dictionary: {0}", m_textureSenders.Count); + } + else + { + m_log.WarnFormat( + "[TEXTURE]: Got a texture uuid {0} with no sender object to handle it, this shouldn't happen", + textureID); + } + } + */ + } + + /// + /// Place a ready texture sender on the processing queue. + /// + /// +// private void EnqueueTextureSender(ITextureSender textureSender) +// { +// textureSender.Cancel = false; +// textureSender.Sending = true; +// +// if (!m_sharedSendersQueue.Contains(textureSender)) +// { +// m_sharedSendersQueue.Enqueue(textureSender); +// } +// } + + /// + /// Close this module. + /// + internal void Close() + { + closed = true; + + lock (m_textureSenders) + { + foreach (TextureSender.TextureSender textureSender in m_textureSenders.Values) + { + textureSender.Cancel = true; + } + + m_textureSenders.Clear(); + } + + // XXX: It might be possible to also remove pending texture requests from the asset cache queues, + // though this might also be more trouble than it's worth. + } + } +} diff --git a/OpenSim/Region/CoreModules/Agent/TextureSender/TextureSender.cs b/OpenSim/Region/CoreModules/Agent/TextureSender/TextureSender.cs new file mode 100644 index 0000000..62c5a32 --- /dev/null +++ b/OpenSim/Region/CoreModules/Agent/TextureSender/TextureSender.cs @@ -0,0 +1,212 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Reflection; +using log4net; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; + +namespace OpenSim.Region.CoreModules.Agent.TextureSender +{ + /// + /// A TextureSender handles the process of receiving a texture requested by the client from the + /// AssetCache, and then sending that texture back to the client. + /// + public class TextureSender : ITextureSender + { + private static readonly ILog m_log + = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + /// + /// Records the number of times texture send has been called. + /// + public int counter = 0; + + public bool ImageLoaded = false; + + /// + /// Holds the texture asset to send. + /// + private AssetBase m_asset; + + //public UUID assetID { get { return m_asset.FullID; } } + + // private bool m_cancel = false; + + // See ITextureSender + + // private bool m_sending = false; + + /// + /// This is actually the number of extra packets required to send the texture data! We always assume + /// at least one is required. + /// + private int NumPackets = 0; + + /// + /// Holds the packet number to send next. In this case, each packet is 1000 bytes long and starts + /// at the 600th byte (0th indexed). + /// + private int PacketCounter = 0; + + private int RequestedDiscardLevel = -1; + private IClientAPI RequestUser; + private uint StartPacketNumber = 0; + + public TextureSender(IClientAPI client, int discardLevel, uint packetNumber) + { + RequestUser = client; + RequestedDiscardLevel = discardLevel; + StartPacketNumber = packetNumber; + } + + #region ITextureSender Members + + public bool Cancel + { + get { return false; } + set + { + // m_cancel = value; + } + } + + public bool Sending + { + get { return false; } + set + { + // m_sending = value; + } + } + + // See ITextureSender + public void UpdateRequest(int discardLevel, uint packetNumber) + { + RequestedDiscardLevel = discardLevel; + StartPacketNumber = packetNumber; + PacketCounter = (int)StartPacketNumber; + } + + // See ITextureSender + public bool SendTexturePacket() + { + //m_log.DebugFormat("[TEXTURE SENDER]: Sending packet for {0}", m_asset.FullID); + + SendPacket(); + counter++; + if ((NumPackets == 0) || (RequestedDiscardLevel == -1) || (PacketCounter > NumPackets) || + ((RequestedDiscardLevel > 0) && (counter > 50 + (NumPackets / (RequestedDiscardLevel + 1))))) + { + return true; + } + return false; + } + + #endregion + + /// + /// Load up the texture data to send. + /// + /// + public void TextureReceived(AssetBase asset) + { + m_asset = asset; + NumPackets = CalculateNumPackets(asset.Data.Length); + PacketCounter = (int)StartPacketNumber; + ImageLoaded = true; + } + + /// + /// Sends a texture packet to the client. + /// + private void SendPacket() + { + if (PacketCounter <= NumPackets) + { + if (PacketCounter == 0) + { + if (NumPackets == 0) + { + RequestUser.SendImageFirstPart(1, m_asset.FullID, (uint)m_asset.Data.Length, m_asset.Data, 2); + PacketCounter++; + } + else + { + byte[] ImageData1 = new byte[600]; + Array.Copy(m_asset.Data, 0, ImageData1, 0, 600); + + RequestUser.SendImageFirstPart( + (ushort)(NumPackets), m_asset.FullID, (uint)m_asset.Data.Length, ImageData1, 2); + PacketCounter++; + } + } + else + { + int size = m_asset.Data.Length - 600 - (1000 * (PacketCounter - 1)); + if (size > 1000) size = 1000; + byte[] imageData = new byte[size]; + try + { + Array.Copy(m_asset.Data, 600 + (1000 * (PacketCounter - 1)), imageData, 0, size); + } + catch (ArgumentOutOfRangeException) + { + m_log.Error("[TEXTURE SENDER]: Unable to separate texture into multiple packets: Array bounds failure on asset:" + + m_asset.ID); + return; + } + + RequestUser.SendImageNextPart((ushort)PacketCounter, m_asset.FullID, imageData); + PacketCounter++; + } + } + } + + /// + /// Calculate the number of packets that will be required to send the texture loaded into this sender + /// This is actually the number of 1000 byte packets not including an initial 600 byte packet... + /// + /// + /// + private int CalculateNumPackets(int length) + { + int numPackets = 0; + + if (length > 600) + { + //over 600 bytes so split up file + int restData = (length - 600); + int restPackets = ((restData + 999) / 1000); + numPackets = restPackets; + } + + return numPackets; + } + } +} diff --git a/OpenSim/Region/Framework/Interfaces/ITextureSender.cs b/OpenSim/Region/Framework/Interfaces/ITextureSender.cs new file mode 100644 index 0000000..c469ae8 --- /dev/null +++ b/OpenSim/Region/Framework/Interfaces/ITextureSender.cs @@ -0,0 +1,58 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +namespace OpenSim.Region.Framework.Interfaces +{ + /// + /// Interface for an object which can send texture information to a client + /// + public interface ITextureSender + { + /// + /// Are we in the process of sending the texture? + /// + bool Sending { get; set; } + + /// + /// Has the texture send been cancelled? + /// + bool Cancel { get; set; } + + /// + /// Update the non data properties of a texture request + /// + /// + /// + void UpdateRequest(int discardLevel, uint packetNumber); + + /// + /// Send a texture packet to the client. + /// + /// True if the last packet has been sent, false otherwise. + bool SendTexturePacket(); + } +} -- cgit v1.1 From 99abe885c812e42229d1e1b4fa58cd0a34edf859 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Tue, 20 Oct 2009 12:30:34 -0700 Subject: Fixing position/rotation/collisionplane in ObjectUpdate packets for avatars --- OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 88faccf..dce9469 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -4285,12 +4285,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP protected ObjectUpdatePacket.ObjectDataBlock CreateAvatarUpdateBlock(SendAvatarData data) { - byte[] objectData = new byte[60]; - data.Position.ToBytes(objectData, 0); - //data.Velocity.ToBytes(objectData, 12); - //data.Acceleration.ToBytes(objectData, 24); - data.Rotation.ToBytes(objectData, 36); - //data.AngularVelocity.ToBytes(objectData, 48); + byte[] objectData = new byte[76]; + + Vector4.UnitW.ToBytes(objectData, 0); // TODO: Collision plane support + data.Position.ToBytes(objectData, 16); + //data.Velocity.ToBytes(objectData, 28); + //data.Acceleration.ToBytes(objectData, 40); + data.Rotation.ToBytes(objectData, 52); + //data.AngularVelocity.ToBytes(objectData, 64); ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); -- cgit v1.1 From d1ab11dc2a60ddab0cca214a1c165e386dbb5d43 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Tue, 20 Oct 2009 12:43:09 -0700 Subject: Added try/catches in the outgoing packet handler to match the one in the incoming packet handler --- .../Region/ClientStack/LindenUDP/LLUDPServer.cs | 104 ++++++++++++--------- 1 file changed, 59 insertions(+), 45 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index a6ead5e..3881bdb 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -776,61 +776,75 @@ namespace OpenSim.Region.ClientStack.LindenUDP while (base.IsRunning) { - bool resendUnacked = false; - bool sendAcks = false; - bool sendPings = false; - bool packetSent = false; - - elapsedMS += Environment.TickCount - now; - - // Check for pending outgoing resends every 100ms - if (elapsedMS >= 100) - { - resendUnacked = true; - elapsedMS -= 100; - ++elapsed100MS; - } - // Check for pending outgoing ACKs every 500ms - if (elapsed100MS >= 5) - { - sendAcks = true; - elapsed100MS = 0; - ++elapsed500MS; - } - // Send pings to clients every 5000ms - if (elapsed500MS >= 10) + try { - sendPings = true; - elapsed500MS = 0; - } + bool resendUnacked = false; + bool sendAcks = false; + bool sendPings = false; + bool packetSent = false; - m_scene.ClientManager.ForEachSync( - delegate(IClientAPI client) + elapsedMS += Environment.TickCount - now; + + // Check for pending outgoing resends every 100ms + if (elapsedMS >= 100) { - if (client is LLClientView) - { - LLUDPClient udpClient = ((LLClientView)client).UDPClient; + resendUnacked = true; + elapsedMS -= 100; + ++elapsed100MS; + } + // Check for pending outgoing ACKs every 500ms + if (elapsed100MS >= 5) + { + sendAcks = true; + elapsed100MS = 0; + ++elapsed500MS; + } + // Send pings to clients every 5000ms + if (elapsed500MS >= 10) + { + sendPings = true; + elapsed500MS = 0; + } - if (udpClient.IsConnected) + m_scene.ClientManager.ForEachSync( + delegate(IClientAPI client) + { + try { - if (udpClient.DequeueOutgoing()) - packetSent = true; - if (resendUnacked) - ResendUnacked(udpClient); - if (sendAcks) + if (client is LLClientView) { - SendAcks(udpClient); - udpClient.SendPacketStats(); + LLUDPClient udpClient = ((LLClientView)client).UDPClient; + + if (udpClient.IsConnected) + { + if (udpClient.DequeueOutgoing()) + packetSent = true; + if (resendUnacked) + ResendUnacked(udpClient); + if (sendAcks) + { + SendAcks(udpClient); + udpClient.SendPacketStats(); + } + if (sendPings) + SendPing(udpClient); + } } - if (sendPings) - SendPing(udpClient); + } + catch (Exception ex) + { + m_log.Error("[LLUDPSERVER]: OutgoingPacketHandler iteration for " + client.Name + " threw an exception: " + ex.Message, ex); } } - } - ); + ); - if (!packetSent) - Thread.Sleep(20); + if (!packetSent) + Thread.Sleep(20); + } + catch (Exception ex) + { + m_log.Error("[LLUDPSERVER]: OutgoingPacketHandler loop threw an exception: " + ex.Message, ex); + } } } -- cgit v1.1 From d38f33736c371cf8c09d78ee5c42b8cc943bb1d7 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Tue, 20 Oct 2009 14:41:20 -0700 Subject: * Removed the throttle speed optimizations to see if it brings stability back * Changed the outgoing packet handler to use a real function instead of a closure and to track time on a per-client basis instead of a global basis --- .../Region/ClientStack/LindenUDP/LLUDPClient.cs | 25 +++-- .../Region/ClientStack/LindenUDP/LLUDPServer.cs | 116 ++++++++++----------- 2 files changed, 69 insertions(+), 72 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs index 4a3a04e..ec74188 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs @@ -101,6 +101,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP public bool IsPaused = true; /// Environment.TickCount when the last packet was received for this client public int TickLastPacketReceived; + /// Environment.TickCount of the last time the outgoing packet handler executed for this client + public int TickLastOutgoingPacketHandler; /// Timer granularity. This is set to the measured resolution of Environment.TickCount public readonly float G; @@ -320,27 +322,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP bucket.MaxBurst = total; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend]; - bucket.DripRate = bucket.MaxBurst = resend; + bucket.DripRate = resend; + bucket.MaxBurst = resend; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land]; - bucket.DripRate = bucket.MaxBurst = land; + bucket.DripRate = land; + bucket.MaxBurst = land; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind]; - bucket.DripRate = bucket.MaxBurst = wind; + bucket.DripRate = wind; + bucket.MaxBurst = wind; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud]; - bucket.DripRate = bucket.MaxBurst = cloud; + bucket.DripRate = cloud; + bucket.MaxBurst = cloud; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset]; - bucket.DripRate = bucket.MaxBurst = asset; + bucket.DripRate = asset; + bucket.MaxBurst = asset; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task]; - bucket.DripRate = task + state + texture; - bucket.MaxBurst = task + state + texture; + bucket.DripRate = task + state; + bucket.MaxBurst = task + state; bucket = m_throttleCategories[(int)ThrottleOutPacketType.State]; - bucket.DripRate = state + texture; - bucket.MaxBurst = state + texture; + bucket.DripRate = state; + bucket.MaxBurst = state; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture]; bucket.DripRate = texture; diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 3881bdb..80ef95e 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -118,6 +118,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP private int m_recvBufferSize; /// Flag to process packets asynchronously or synchronously private bool m_asyncPacketHandling; + /// Track whether or not a packet was sent in the + /// OutgoingPacketHandler loop so we know when to sleep + private bool m_packetSentLastLoop; /// The measured resolution of Environment.TickCount public float TickCountResolution { get { return m_tickCountResolution; } } @@ -745,10 +748,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP while (base.IsRunning) { - IncomingPacket incomingPacket = null; - try { + IncomingPacket incomingPacket = null; + if (packetInbox.Dequeue(100, ref incomingPacket)) Util.FireAndForget(ProcessInPacket, incomingPacket); } @@ -769,83 +772,70 @@ namespace OpenSim.Region.ClientStack.LindenUDP // on to en-US to avoid number parsing issues Culture.SetCurrentCulture(); - int now = Environment.TickCount; - int elapsedMS = 0; - int elapsed100MS = 0; - int elapsed500MS = 0; - while (base.IsRunning) { try { - bool resendUnacked = false; - bool sendAcks = false; - bool sendPings = false; - bool packetSent = false; + m_packetSentLastLoop = false; - elapsedMS += Environment.TickCount - now; + m_scene.ClientManager.ForEachSync(ClientOutgoingPacketHandler); - // Check for pending outgoing resends every 100ms - if (elapsedMS >= 100) - { - resendUnacked = true; - elapsedMS -= 100; - ++elapsed100MS; - } - // Check for pending outgoing ACKs every 500ms - if (elapsed100MS >= 5) - { - sendAcks = true; - elapsed100MS = 0; - ++elapsed500MS; - } - // Send pings to clients every 5000ms - if (elapsed500MS >= 10) - { - sendPings = true; - elapsed500MS = 0; - } + // If no packets at all were sent, sleep to avoid chewing up CPU cycles + // when there is nothing to do + if (!m_packetSentLastLoop) + Thread.Sleep(20); + } + catch (Exception ex) + { + m_log.Error("[LLUDPSERVER]: OutgoingPacketHandler loop threw an exception: " + ex.Message, ex); + } + } + } - m_scene.ClientManager.ForEachSync( - delegate(IClientAPI client) + private void ClientOutgoingPacketHandler(IClientAPI client) + { + try + { + if (client is LLClientView) + { + LLUDPClient udpClient = ((LLClientView)client).UDPClient; + + int thisTick = Environment.TickCount & Int32.MaxValue; + int elapsedMS = thisTick - udpClient.TickLastOutgoingPacketHandler; + + if (udpClient.IsConnected) + { + // Check for pending outgoing resends every 100ms + if (elapsedMS >= 100) { - try + ResendUnacked(udpClient); + + // Check for pending outgoing ACKs every 500ms + if (elapsedMS >= 500) { - if (client is LLClientView) + SendAcks(udpClient); + + // Send pings to clients every 5000ms + if (elapsedMS >= 5000) { - LLUDPClient udpClient = ((LLClientView)client).UDPClient; - - if (udpClient.IsConnected) - { - if (udpClient.DequeueOutgoing()) - packetSent = true; - if (resendUnacked) - ResendUnacked(udpClient); - if (sendAcks) - { - SendAcks(udpClient); - udpClient.SendPacketStats(); - } - if (sendPings) - SendPing(udpClient); - } + SendPing(udpClient); } } - catch (Exception ex) - { - m_log.Error("[LLUDPSERVER]: OutgoingPacketHandler iteration for " + client.Name + " threw an exception: " + ex.Message, ex); - } } - ); - if (!packetSent) - Thread.Sleep(20); - } - catch (Exception ex) - { - m_log.Error("[LLUDPSERVER]: OutgoingPacketHandler loop threw an exception: " + ex.Message, ex); + // Dequeue any outgoing packets that are within the throttle limits + if (udpClient.DequeueOutgoing()) + m_packetSentLastLoop = true; + } + + udpClient.TickLastOutgoingPacketHandler = thisTick; } } + catch (Exception ex) + { + m_log.Error("[LLUDPSERVER]: OutgoingPacketHandler iteration for " + client.Name + + " threw an exception: " + ex.Message, ex); + } } private void ProcessInPacket(object state) -- cgit v1.1 From 1833c6956892f1c8324ecbe0179103bff2079151 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Tue, 20 Oct 2009 15:19:19 -0700 Subject: * Removed the unused m_agentUpdates collection and some extra work that was being done for AgentUpdate packets * Start LLUDPClients unpaused (this variable is not being used yet) --- .../Region/ClientStack/LindenUDP/LLUDPClient.cs | 2 +- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 126 ++++++--------------- 2 files changed, 34 insertions(+), 94 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs index ec74188..bf0fda3 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs @@ -98,7 +98,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// True when this connection is alive, otherwise false public bool IsConnected = true; /// True when this connection is paused, otherwise false - public bool IsPaused = true; + public bool IsPaused; /// Environment.TickCount when the last packet was received for this client public int TickLastPacketReceived; /// Environment.TickCount of the last time the outgoing packet handler executed for this client diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index bdd80c6..d7113bf 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -128,8 +128,6 @@ namespace OpenSim.Region.Framework.Scenes private bool m_setAlwaysRun; - private bool m_updatesAllowed = true; - private List m_agentUpdates = new List(); private string m_movementAnimation = "DEFAULT"; private long m_animPersistUntil = 0; private bool m_allowFalling = false; @@ -1090,34 +1088,6 @@ namespace OpenSim.Region.Framework.Scenes } - // These methods allow to queue up agent updates (like key presses) - // until all attachment scripts are running and the animations from - // AgentDataUpdate have been started. It is essential for combat - // devices, weapons and AOs that keypresses are not processed - // until scripts that are potentially interested in them are - // up and running and that animations a script knows to be running - // from before a crossing are running again - // - public void LockAgentUpdates() - { - m_updatesAllowed = false; - } - - public void UnlockAgentUpdates() - { - lock (m_agentUpdates) - { - if (m_updatesAllowed == false) - { - foreach (AgentUpdateArgs a in m_agentUpdates) - RealHandleAgentUpdate(ControllingClient, a); - m_agentUpdates.Clear(); - m_updatesAllowed = true; - } - } - } - - /// /// Callback for the Camera view block check. Gets called with the results of the camera view block test /// hitYN is true when there's something in the way. @@ -1155,49 +1125,30 @@ namespace OpenSim.Region.Framework.Scenes } } + Array m_dirControlFlags = Enum.GetValues(typeof(Dir_ControlFlags)); + /// /// This is the event handler for client movement. If a client is moving, this event is triggering. /// public void HandleAgentUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData) { - const int AGENT_UPDATE_TIMEOUT_MS = 1000 * 3; - - if (System.Threading.Monitor.TryEnter(m_agentUpdates, AGENT_UPDATE_TIMEOUT_MS)) - { - try - { - if (m_updatesAllowed) - { - RealHandleAgentUpdate(remoteClient, agentData); - return; - } - - m_agentUpdates.Add(agentData); - } - finally { System.Threading.Monitor.Exit(m_agentUpdates); } - } - } - - private void RealHandleAgentUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData) - { //if (m_isChildAgent) //{ // // m_log.Debug("DEBUG: HandleAgentUpdate: child agent"); // return; //} - - m_movementUpdateCount++; - if (m_movementUpdateCount >= int.MaxValue) - m_movementUpdateCount = 1; + m_perfMonMS = Environment.TickCount; + ++m_movementUpdateCount; + if (m_movementUpdateCount < 1) + m_movementUpdateCount = 1; // Must check for standing up even when PhysicsActor is null, // since sitting currently removes avatar from physical scene //m_log.Debug("agentPos:" + AbsolutePosition.ToString()); // This is irritating. Really. - if (!AbsolutePosition.IsFinite()) { RemoveFromPhysicalScene(); @@ -1218,19 +1169,17 @@ namespace OpenSim.Region.Framework.Scenes { m_LastFinitePos = m_pos; } - //m_physicsActor.AddForce(new PhysicsVector(999999999, 99999999, 999999999999999), true); + //m_physicsActor.AddForce(new PhysicsVector(999999999, 99999999, 999999999999999), true); //ILandObject land = LandChannel.GetLandObject(agent.startpos.X, agent.startpos.Y); //if (land != null) //{ - //if (land.landData.landingType == (byte)1 && land.landData.userLocation != Vector3.Zero) - //{ - // agent.startpos = land.landData.userLocation; - //} + //if (land.landData.landingType == (byte)1 && land.landData.userLocation != Vector3.Zero) + //{ + // agent.startpos = land.landData.userLocation; + //} //} - - m_perfMonMS = Environment.TickCount; uint flags = agentData.ControlFlags; Quaternion bodyRotation = agentData.BodyRotation; @@ -1253,7 +1202,7 @@ namespace OpenSim.Region.Framework.Scenes // The Agent's Draw distance setting m_DrawDistance = agentData.Far; - if ((flags & (uint) AgentManager.ControlFlags.AGENT_CONTROL_STAND_UP) != 0) + if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_STAND_UP) != 0) { StandUp(); } @@ -1261,14 +1210,13 @@ namespace OpenSim.Region.Framework.Scenes // Check if Client has camera in 'follow cam' or 'build' mode. Vector3 camdif = (Vector3.One * m_bodyRot - Vector3.One * CameraRotation); - m_followCamAuto = ((m_CameraUpAxis.Z > 0.959f && m_CameraUpAxis.Z < 0.98f) + m_followCamAuto = ((m_CameraUpAxis.Z > 0.959f && m_CameraUpAxis.Z < 0.98f) && (Math.Abs(camdif.X) < 0.4f && Math.Abs(camdif.Y) < 0.4f)) ? true : false; //m_log.DebugFormat("[FollowCam]: {0}", m_followCamAuto); // Raycast from the avatar's head to the camera to see if there's anything blocking the view if ((m_movementUpdateCount % NumMovementsBetweenRayCast) == 0 && m_scene.PhysicsScene.SupportsRayCast()) { - if (m_followCamAuto) { Vector3 headadjustment = new Vector3(0, 0, 0.3f); @@ -1276,24 +1224,18 @@ namespace OpenSim.Region.Framework.Scenes } } - m_mouseLook = (flags & (uint) AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0; - - - + m_mouseLook = (flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0; m_leftButtonDown = (flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_DOWN) != 0; - - lock (scriptedcontrols) { if (scriptedcontrols.Count > 0) { SendControlToScripts(flags); flags = RemoveIgnoredControls(flags, IgnoredControls); - } } - + if (PhysicsActor == null) { return; @@ -1302,7 +1244,7 @@ namespace OpenSim.Region.Framework.Scenes if (m_autopilotMoving) CheckAtSitTarget(); - if ((flags & (uint) AgentManager.ControlFlags.AGENT_CONTROL_SIT_ON_GROUND) != 0) + if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_SIT_ON_GROUND) != 0) { // TODO: This doesn't prevent the user from walking yet. // Setting parent ID would fix this, if we knew what value @@ -1335,13 +1277,13 @@ namespace OpenSim.Region.Framework.Scenes PhysicsActor.Flying = false; else PhysicsActor.Flying = ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0); - + if (PhysicsActor.Flying != oldflying) { update_movementflag = true; } } - + if (q != m_bodyRot) { m_bodyRot = q; @@ -1357,15 +1299,15 @@ namespace OpenSim.Region.Framework.Scenes // use camera up angle when in mouselook and not flying or when holding the left mouse button down and not flying // this prevents 'jumping' in inappropriate situations. - if ((m_mouseLook && !m_physicsActor.Flying) || (m_leftButtonDown && !m_physicsActor.Flying)) + if ((m_mouseLook && !m_physicsActor.Flying) || (m_leftButtonDown && !m_physicsActor.Flying)) dirVectors = GetWalkDirectionVectors(); else dirVectors = Dir_Vectors; - foreach (Dir_ControlFlags DCF in Enum.GetValues(typeof (Dir_ControlFlags))) + foreach (Dir_ControlFlags DCF in m_dirControlFlags) { - if ((flags & (uint) DCF) != 0) + if ((flags & (uint)DCF) != 0) { bResetMoveToPosition = true; DCFlagKeyPressed = true; @@ -1377,18 +1319,18 @@ namespace OpenSim.Region.Framework.Scenes { // Why did I get this? } - - if ((m_movementflag & (uint) DCF) == 0) + + if ((m_movementflag & (uint)DCF) == 0) { - m_movementflag += (byte) (uint) DCF; + m_movementflag += (byte)(uint)DCF; update_movementflag = true; } } else { - if ((m_movementflag & (uint) DCF) != 0) + if ((m_movementflag & (uint)DCF) != 0) { - m_movementflag -= (byte) (uint) DCF; + m_movementflag -= (byte)(uint)DCF; update_movementflag = true; } else @@ -1479,14 +1421,12 @@ namespace OpenSim.Region.Framework.Scenes } catch (Exception) { - //Avoid system crash, can be slower but... } - } } } - + // Cause the avatar to stop flying if it's colliding // with something with the down arrow pressed. @@ -1494,8 +1434,8 @@ namespace OpenSim.Region.Framework.Scenes if (m_physicsActor != null && m_physicsActor.Flying && !m_forceFly) { // Are the landing controls requirements filled? - bool controlland = (((flags & (uint) AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) || - ((flags & (uint) AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0)); + bool controlland = (((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) || + ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0)); // Are the collision requirements fulfilled? bool colliding = (m_physicsActor.IsColliding == true); @@ -1508,10 +1448,10 @@ namespace OpenSim.Region.Framework.Scenes if (update_movementflag || (update_rotation && DCFlagKeyPressed)) { -// m_log.DebugFormat("{0} {1}", update_movementflag, (update_rotation && DCFlagKeyPressed)); -// m_log.DebugFormat( -// "In {0} adding velocity to {1} of {2}", m_scene.RegionInfo.RegionName, Name, agent_control_v3); - + // m_log.DebugFormat("{0} {1}", update_movementflag, (update_rotation && DCFlagKeyPressed)); + // m_log.DebugFormat( + // "In {0} adding velocity to {1} of {2}", m_scene.RegionInfo.RegionName, Name, agent_control_v3); + AddNewMovement(agent_control_v3, q); if (update_movementflag) -- cgit v1.1 From 45dc4e0a5442d1d03f7387164070145386a9b4e1 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Tue, 20 Oct 2009 18:19:17 -0700 Subject: * Added a sanity check to GetScriptAssemblies() and GetScriptStates() for the case where no scripting engine is enabled * Added TokenBucket.cs to OpenSim, with some fixes for setting a more accurate MaxBurst value and getting a more accurate Content value (by Drip()ing each get) --- .../Region/ClientStack/LindenUDP/LLUDPClient.cs | 2 + .../Region/ClientStack/LindenUDP/LLUDPServer.cs | 2 + .../Region/ClientStack/LindenUDP/TokenBucket.cs | 213 +++++++++++++++++++++ .../LindenUDP/UnackedPacketCollection.cs | 2 + .../Framework/Scenes/SceneObjectPartInventory.cs | 26 ++- 5 files changed, 235 insertions(+), 10 deletions(-) create mode 100644 OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs index bf0fda3..134cfe5 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs @@ -33,6 +33,8 @@ using OpenSim.Framework; using OpenMetaverse; using OpenMetaverse.Packets; +using TokenBucket = OpenSim.Region.ClientStack.LindenUDP.TokenBucket; + namespace OpenSim.Region.ClientStack.LindenUDP { #region Delegates diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 80ef95e..952d147 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -39,6 +39,8 @@ using OpenSim.Framework.Statistics; using OpenSim.Region.Framework.Scenes; using OpenMetaverse; +using TokenBucket = OpenSim.Region.ClientStack.LindenUDP.TokenBucket; + namespace OpenSim.Region.ClientStack.LindenUDP { /// diff --git a/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs b/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs new file mode 100644 index 0000000..0a64095 --- /dev/null +++ b/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs @@ -0,0 +1,213 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; + +namespace OpenSim.Region.ClientStack.LindenUDP +{ + /// + /// A hierarchical token bucket for bandwidth throttling. See + /// http://en.wikipedia.org/wiki/Token_bucket for more information + /// + public class TokenBucket + { + /// Parent bucket to this bucket, or null if this is a root + /// bucket + TokenBucket parent; + /// Size of the bucket in bytes. If zero, the bucket has + /// infinite capacity + int maxBurst; + /// Rate that the bucket fills, in bytes per millisecond. If + /// zero, the bucket always remains full + int tokensPerMS; + /// Number of tokens currently in the bucket + int content; + /// Time of the last drip, in system ticks + int lastDrip; + + #region Properties + + /// + /// The parent bucket of this bucket, or null if this bucket has no + /// parent. The parent bucket will limit the aggregate bandwidth of all + /// of its children buckets + /// + public TokenBucket Parent + { + get { return parent; } + } + + /// + /// Maximum burst rate in bytes per second. This is the maximum number + /// of tokens that can accumulate in the bucket at any one time + /// + public int MaxBurst + { + get { return maxBurst; } + set { maxBurst = (value >= 0 ? value : 0); } + } + + /// + /// The speed limit of this bucket in bytes per second. This is the + /// number of tokens that are added to the bucket per second + /// + /// Tokens are added to the bucket any time + /// is called, at the granularity of + /// the system tick interval (typically around 15-22ms) + public int DripRate + { + get { return tokensPerMS * 1000; } + set + { + if (value == 0) + tokensPerMS = 0; + else + { + int bpms = (int)((float)value / 1000.0f); + + if (bpms <= 0) + tokensPerMS = 1; // 1 byte/ms is the minimum granularity + else + tokensPerMS = bpms; + } + } + } + + /// + /// The number of bytes that can be sent at this moment. This is the + /// current number of tokens in the bucket + /// If this bucket has a parent bucket that does not have + /// enough tokens for a request, will + /// return false regardless of the content of this bucket + /// + public int Content + { + get + { + Drip(); + return content; + } + } + + #endregion Properties + + /// + /// Default constructor + /// + /// Parent bucket if this is a child bucket, or + /// null if this is a root bucket + /// Maximum size of the bucket in bytes, or + /// zero if this bucket has no maximum capacity + /// Rate that the bucket fills, in bytes per + /// second. If zero, the bucket always remains full + public TokenBucket(TokenBucket parent, int maxBurst, int dripRate) + { + this.parent = parent; + MaxBurst = maxBurst; + DripRate = dripRate; + lastDrip = Environment.TickCount & Int32.MaxValue; + } + + /// + /// Remove a given number of tokens from the bucket + /// + /// Number of tokens to remove from the bucket + /// True if the requested number of tokens were removed from + /// the bucket, otherwise false + public bool RemoveTokens(int amount) + { + bool dummy; + return RemoveTokens(amount, out dummy); + } + + /// + /// Remove a given number of tokens from the bucket + /// + /// Number of tokens to remove from the bucket + /// True if tokens were added to the bucket + /// during this call, otherwise false + /// True if the requested number of tokens were removed from + /// the bucket, otherwise false + public bool RemoveTokens(int amount, out bool dripSucceeded) + { + if (maxBurst == 0) + { + dripSucceeded = true; + return true; + } + + dripSucceeded = Drip(); + + if (content - amount >= 0) + { + if (parent != null && !parent.RemoveTokens(amount)) + return false; + + content -= amount; + return true; + } + else + { + return false; + } + } + + /// + /// Add tokens to the bucket over time. The number of tokens added each + /// call depends on the length of time that has passed since the last + /// call to Drip + /// + /// True if tokens were added to the bucket, otherwise false + private bool Drip() + { + if (tokensPerMS == 0) + { + content = maxBurst; + return true; + } + else + { + int now = Environment.TickCount & Int32.MaxValue; + int deltaMS = now - lastDrip; + + if (deltaMS <= 0) + { + if (deltaMS < 0) + lastDrip = now; + return false; + } + + int dripAmount = deltaMS * tokensPerMS; + + content = Math.Min(content + dripAmount, maxBurst); + lastDrip = now; + + return true; + } + } + } +} diff --git a/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs b/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs index f3242c1..87c7df4 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs @@ -147,6 +147,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP int now = Environment.TickCount; foreach (OutgoingPacket packet in packets.Values) { + // TickCount of zero means a packet is in the resend queue + // but hasn't actually been sent over the wire yet if (packet.TickCount == 0) continue; diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs index 098e010..f4ca877 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs @@ -871,12 +871,15 @@ namespace OpenSim.Region.Framework.Scenes { foreach (IScriptModule e in engines) { - string n = e.GetAssemblyName(item.ItemID); - if (n != "") + if (e != null) { - if (!ret.Contains(n)) - ret.Add(n); - break; + string n = e.GetAssemblyName(item.ItemID); + if (n != String.Empty) + { + if (!ret.Contains(n)) + ret.Add(n); + break; + } } } } @@ -898,12 +901,15 @@ namespace OpenSim.Region.Framework.Scenes { foreach (IScriptModule e in engines) { - string n = e.GetXMLState(item.ItemID); - if (n != "") + if (e != null) { - if (!ret.ContainsKey(item.ItemID)) - ret[item.ItemID] = n; - break; + string n = e.GetXMLState(item.ItemID); + if (n != String.Empty) + { + if (!ret.ContainsKey(item.ItemID)) + ret[item.ItemID] = n; + break; + } } } } -- cgit v1.1 From cde47c2b3d7089be556252246eb03365c1f39b54 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Wed, 21 Oct 2009 00:18:35 -0700 Subject: Committing Jim's optimization to replace the 20ms sleep in outgoing packet handling with an interruptible wait handle --- .../Region/ClientStack/LindenUDP/LLClientView.cs | 6 ++ .../Region/ClientStack/LindenUDP/LLUDPClient.cs | 51 +++++++---- .../Region/ClientStack/LindenUDP/LLUDPServer.cs | 98 +++++++++++++++------- .../Region/ClientStack/LindenUDP/TokenBucket.cs | 16 ++-- 4 files changed, 121 insertions(+), 50 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index dce9469..38bbce0 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -3320,6 +3320,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP // If we received an update about our own avatar, process the avatar update priority queue immediately if (data.AgentID == m_agentId) ProcessAvatarTerseUpdates(); + else + m_udpServer.SignalOutgoingPacketHandler(); } private void ProcessAvatarTerseUpdates() @@ -3407,6 +3409,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP lock (m_primFullUpdates.SyncRoot) m_primFullUpdates.Enqueue(data.priority, objectData, data.localID); + + m_udpServer.SignalOutgoingPacketHandler(); } void ProcessPrimFullUpdates() @@ -3450,6 +3454,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP lock (m_primTerseUpdates.SyncRoot) m_primTerseUpdates.Enqueue(data.Priority, objectData, data.LocalID); + + m_udpServer.SignalOutgoingPacketHandler(); } void ProcessPrimTerseUpdates() diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs index 134cfe5..b9d2c15 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs @@ -105,9 +105,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP public int TickLastPacketReceived; /// Environment.TickCount of the last time the outgoing packet handler executed for this client public int TickLastOutgoingPacketHandler; + /// Keeps track of the number of elapsed milliseconds since the last time the outgoing packet handler executed for this client + public int ElapsedMSOutgoingPacketHandler; + /// Keeps track of the number of 100 millisecond periods elapsed in the outgoing packet handler executed for this client + public int Elapsed100MSOutgoingPacketHandler; + /// Keeps track of the number of 500 millisecond periods elapsed in the outgoing packet handler executed for this client + public int Elapsed500MSOutgoingPacketHandler; - /// Timer granularity. This is set to the measured resolution of Environment.TickCount - public readonly float G; /// Smoothed round-trip time. A smoothed average of the round-trip time for sending a /// reliable packet to the client and receiving an ACK public float SRTT; @@ -182,15 +186,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_throttleCategories[i] = new TokenBucket(m_throttle, rates.GetLimit(type), rates.GetRate(type)); } - // Set the granularity variable used for retransmission calculations to - // the measured resolution of Environment.TickCount - G = server.TickCountResolution; - // Default the retransmission timeout to three seconds RTO = 3000; // Initialize this to a sane value to prevent early disconnects - TickLastPacketReceived = Environment.TickCount; + TickLastPacketReceived = Environment.TickCount & Int32.MaxValue; + ElapsedMSOutgoingPacketHandler = 0; + Elapsed100MSOutgoingPacketHandler = 0; + Elapsed500MSOutgoingPacketHandler = 0; } /// @@ -391,6 +394,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP { // Not enough tokens in the bucket, queue this packet queue.Enqueue(packet); + m_udpServer.SignalOutgoingPacketHandler(); return true; } } @@ -407,13 +411,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// /// This function is only called from a synchronous loop in the /// UDPServer so we don't need to bother making this thread safe - /// True if any packets were sent, otherwise false - public bool DequeueOutgoing() + /// The minimum amount of time before the next packet + /// can be sent to this client + public int DequeueOutgoing() { OutgoingPacket packet; OpenSim.Framework.LocklessQueue queue; TokenBucket bucket; - bool packetSent = false; + int dataLength; + int minTimeout = Int32.MaxValue; //string queueDebugOutput = String.Empty; // Serious debug business @@ -428,12 +434,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP // leaving a dequeued packet still waiting to be sent out. Try to // send it again OutgoingPacket nextPacket = m_nextPackets[i]; - if (bucket.RemoveTokens(nextPacket.Buffer.DataLength)) + dataLength = nextPacket.Buffer.DataLength; + if (bucket.RemoveTokens(dataLength)) { // Send the packet m_udpServer.SendPacketFinal(nextPacket); m_nextPackets[i] = null; - packetSent = true; + minTimeout = 0; + } + else if (minTimeout != 0) + { + // Check the minimum amount of time we would have to wait before this packet can be sent out + minTimeout = Math.Min(minTimeout, ((dataLength - bucket.Content) / bucket.DripPerMS) + 1); } } else @@ -445,16 +457,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP { // A packet was pulled off the queue. See if we have // enough tokens in the bucket to send it out - if (bucket.RemoveTokens(packet.Buffer.DataLength)) + dataLength = packet.Buffer.DataLength; + if (bucket.RemoveTokens(dataLength)) { // Send the packet m_udpServer.SendPacketFinal(packet); - packetSent = true; + minTimeout = 0; } else { // Save the dequeued packet for the next iteration m_nextPackets[i] = packet; + + if (minTimeout != 0) + { + // Check the minimum amount of time we would have to wait before this packet can be sent out + minTimeout = Math.Min(minTimeout, ((dataLength - bucket.Content) / bucket.DripPerMS) + 1); + } } // If the queue is empty after this dequeue, fire the queue @@ -473,7 +492,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } //m_log.Info("[LLUDPCLIENT]: Queues: " + queueDebugOutput); // Serious debug business - return packetSent; + return minTimeout; } /// @@ -504,7 +523,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } // Always round retransmission timeout up to two seconds - RTO = Math.Max(2000, (int)(SRTT + Math.Max(G, K * RTTVAR))); + RTO = Math.Max(2000, (int)(SRTT + Math.Max(m_udpServer.TickCountResolution, K * RTTVAR))); //m_log.Debug("[LLUDPCLIENT]: Setting agent " + this.Agent.FullName + "'s RTO to " + RTO + "ms with an RTTVAR of " + // RTTVAR + " based on new RTT of " + r + "ms"); } diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 952d147..7d5c11e 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -96,6 +96,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + /// The measured resolution of Environment.TickCount + public readonly float TickCountResolution; + /// Handlers for incoming packets //PacketEventDictionary packetEvents = new PacketEventDictionary(); /// Incoming packets that are awaiting handling @@ -112,20 +115,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP private Scene m_scene; /// The X/Y coordinates of the scene this UDP server is attached to private Location m_location; - /// The measured resolution of Environment.TickCount - private float m_tickCountResolution; /// The size of the receive buffer for the UDP socket. This value /// is passed up to the operating system and used in the system networking /// stack. Use zero to leave this value as the default private int m_recvBufferSize; /// Flag to process packets asynchronously or synchronously private bool m_asyncPacketHandling; - /// Track whether or not a packet was sent in the + /// Track the minimum amount of time needed to send the next packet in the /// OutgoingPacketHandler loop so we know when to sleep - private bool m_packetSentLastLoop; + private int m_minTimeout = Int32.MaxValue; + /// EventWaitHandle to signify the outgoing packet handler thread that + /// there is more work to do + private EventWaitHandle m_outgoingWaitHandle; - /// The measured resolution of Environment.TickCount - public float TickCountResolution { get { return m_tickCountResolution; } } public Socket Server { get { return null; } } public LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager) @@ -134,16 +136,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP #region Environment.TickCount Measurement // Measure the resolution of Environment.TickCount - m_tickCountResolution = 0f; + TickCountResolution = 0f; for (int i = 0; i < 5; i++) { int start = Environment.TickCount; int now = start; while (now == start) now = Environment.TickCount; - m_tickCountResolution += (float)(now - start) * 0.2f; + TickCountResolution += (float)(now - start) * 0.2f; } m_log.Info("[LLUDPSERVER]: Average Environment.TickCount resolution: " + TickCountResolution + "ms"); + TickCountResolution = (float)Math.Ceiling(TickCountResolution); #endregion Environment.TickCount Measurement @@ -171,6 +174,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP base.Start(m_recvBufferSize, m_asyncPacketHandling); + m_outgoingWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset); + // Start the incoming packet processing thread Thread incomingThread = new Thread(IncomingPacketHandler); incomingThread.Name = "Incoming Packets (" + m_scene.RegionInfo.RegionName + ")"; @@ -185,6 +190,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP { m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + m_scene.RegionInfo.RegionName); base.Stop(); + + m_outgoingWaitHandle.Close(); } public void AddScene(IScene scene) @@ -768,6 +775,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP packetInbox.Clear(); } + public bool SignalOutgoingPacketHandler() + { + return m_outgoingWaitHandle.Set(); + } + private void OutgoingPacketHandler() { // Set this culture for the thread that outgoing packets are sent @@ -778,14 +790,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP { try { - m_packetSentLastLoop = false; + m_minTimeout = Int32.MaxValue; + // Handle outgoing packets, resends, acknowledgements, and pings for each + // client. m_minTimeout will be set to 0 if more packets are waiting in the + // queues with bandwidth to spare, or the number of milliseconds we need to + // wait before at least one packet can be sent to a client m_scene.ClientManager.ForEachSync(ClientOutgoingPacketHandler); - // If no packets at all were sent, sleep to avoid chewing up CPU cycles - // when there is nothing to do - if (!m_packetSentLastLoop) - Thread.Sleep(20); + // Can't wait for a negative amount of time, and put a 100ms ceiling on our + // maximum wait time + m_minTimeout = Utils.Clamp(m_minTimeout, 0, 100); + + if (m_minTimeout > 0) + { + // Don't bother waiting for a shorter interval than our TickCountResolution + // since the token buckets wouldn't update anyways + m_minTimeout = Math.Max(m_minTimeout, (int)TickCountResolution); + + // Wait for someone to signal that packets are ready to be sent, or for our + // sleep interval to expire + m_outgoingWaitHandle.WaitOne(m_minTimeout); + } } catch (Exception ex) { @@ -802,32 +828,48 @@ namespace OpenSim.Region.ClientStack.LindenUDP { LLUDPClient udpClient = ((LLClientView)client).UDPClient; + // Update ElapsedMSOutgoingPacketHandler int thisTick = Environment.TickCount & Int32.MaxValue; - int elapsedMS = thisTick - udpClient.TickLastOutgoingPacketHandler; + if (udpClient.TickLastOutgoingPacketHandler > thisTick) + udpClient.ElapsedMSOutgoingPacketHandler += ((Int32.MaxValue - udpClient.TickLastOutgoingPacketHandler) + thisTick); + else + udpClient.ElapsedMSOutgoingPacketHandler += (thisTick - udpClient.TickLastOutgoingPacketHandler); if (udpClient.IsConnected) { // Check for pending outgoing resends every 100ms - if (elapsedMS >= 100) + if (udpClient.ElapsedMSOutgoingPacketHandler >= 100) { ResendUnacked(udpClient); + udpClient.ElapsedMSOutgoingPacketHandler -= 100; + udpClient.Elapsed100MSOutgoingPacketHandler += 1; + } - // Check for pending outgoing ACKs every 500ms - if (elapsedMS >= 500) - { - SendAcks(udpClient); - - // Send pings to clients every 5000ms - if (elapsedMS >= 5000) - { - SendPing(udpClient); - } - } + // Check for pending outgoing ACKs every 500ms + if (udpClient.Elapsed100MSOutgoingPacketHandler >= 5) + { + SendAcks(udpClient); + udpClient.Elapsed100MSOutgoingPacketHandler -= 5; + udpClient.Elapsed500MSOutgoingPacketHandler += 1; + } + + // Send pings to clients every 5000ms + if (udpClient.Elapsed500MSOutgoingPacketHandler >= 10) + { + SendPing(udpClient); + udpClient.Elapsed500MSOutgoingPacketHandler -= 10; } // Dequeue any outgoing packets that are within the throttle limits - if (udpClient.DequeueOutgoing()) - m_packetSentLastLoop = true; + // and get the minimum time we would have to sleep before this client + // could send a packet out + int minTimeoutThisLoop = udpClient.DequeueOutgoing(); + + // Although this is not thread safe, it is cheaper than locking and the + // worst that will happen is we sleep for slightly longer than the + // minimum necessary interval + if (minTimeoutThisLoop < m_minTimeout) + m_minTimeout = minTimeoutThisLoop; } udpClient.TickLastOutgoingPacketHandler = thisTick; diff --git a/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs b/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs index 0a64095..bdbd284 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs @@ -98,6 +98,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP } /// + /// The speed limit of this bucket in bytes per millisecond + /// + public int DripPerMS + { + get { return tokensPerMS; } + } + + /// /// The number of bytes that can be sent at this moment. This is the /// current number of tokens in the bucket /// If this bucket has a parent bucket that does not have @@ -106,11 +114,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// public int Content { - get - { - Drip(); - return content; - } + get { return content; } } #endregion Properties @@ -182,7 +186,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// call to Drip /// /// True if tokens were added to the bucket, otherwise false - private bool Drip() + public bool Drip() { if (tokensPerMS == 0) { -- cgit v1.1 From c0c845aea462ea7b15580c72f5513e5e1ef02030 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Wed, 21 Oct 2009 01:07:40 -0700 Subject: Fixed the way OnQueueEmpty is called to prevent simultaneous calls for the same category --- OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs index b9d2c15..ca9925c 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs @@ -541,7 +541,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (throttleIndex > 0) { if (!m_onQueueEmptyRunning[throttleIndex]) + { + m_onQueueEmptyRunning[throttleIndex] = true; Util.FireAndForget(FireQueueEmpty, throttleIndex); + } } } @@ -559,14 +562,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (callback != null) { - if (!m_onQueueEmptyRunning[i]) - { - m_onQueueEmptyRunning[i] = true; - try { callback(type); } - catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + type + ") threw an exception: " + e.Message, e); } - m_onQueueEmptyRunning[i] = false; - } + try { callback(type); } + catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + type + ") threw an exception: " + e.Message, e); } } + + m_onQueueEmptyRunning[i] = false; } } } -- cgit v1.1 From 8dd15fd5a590e059038d6438a305264cad3918b7 Mon Sep 17 00:00:00 2001 From: Melanie Date: Wed, 21 Oct 2009 18:45:37 +0100 Subject: Patch by mcortez: Remove lock from scene presence updating in groups module --- .../OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs index b209199..b2544fa 100644 --- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs +++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs @@ -1244,18 +1244,16 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: Updating scene title for {0} with title: {1}", AgentID, Title); ScenePresence presence = null; - lock (m_sceneList) + + foreach (Scene scene in m_sceneList) { - foreach (Scene scene in m_sceneList) + presence = scene.GetScenePresence(AgentID); + if (presence != null) { - presence = scene.GetScenePresence(AgentID); - if (presence != null) - { - presence.Grouptitle = Title; + presence.Grouptitle = Title; - // FixMe: Ter suggests a "Schedule" method that I can't find. - presence.SendFullUpdateToAllClients(); - } + // FixMe: Ter suggests a "Schedule" method that I can't find. + presence.SendFullUpdateToAllClients(); } } } -- cgit v1.1 From 9178537e9414478f0a9bd84bb5e106b2f15640c3 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Wed, 21 Oct 2009 11:59:48 -0700 Subject: * Replaced the UnackedPacketCollection with a lockless implementation. The tiny amount of time spent in the locks turned into a lot of time when the rest of the LLUDP implementation went lockless * Changed the timer tracking numbers for each client to not have "memory". It will no longer queue up calls to functions like ResendUnacked * Reverted Jim's WaitHandle code. Although it was technically more correct, it exhibited the exact same behavior as the old code but spent more cycles. The 20ms has been replaced with the minimum amount of time before a token bucket could receive a drip, and an else { sleep(0); } was added to make sure the outgoing packet handler always yields at least a minimum amount --- .../Region/ClientStack/LindenUDP/LLClientView.cs | 11 +- .../Region/ClientStack/LindenUDP/LLUDPClient.cs | 33 ++--- .../Region/ClientStack/LindenUDP/LLUDPServer.cs | 143 +++++++------------- .../LindenUDP/UnackedPacketCollection.cs | 147 ++++++++++----------- 4 files changed, 126 insertions(+), 208 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 38bbce0..997f38c 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -1228,10 +1228,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP StartPingCheckPacket pc = (StartPingCheckPacket)PacketPool.Instance.GetPacket(PacketType.StartPingCheck); pc.Header.Reliable = false; - OutgoingPacket oldestPacket = m_udpClient.NeedAcks.GetOldest(); - pc.PingID.PingID = seq; - pc.PingID.OldestUnacked = (oldestPacket != null) ? oldestPacket.SequenceNumber : 0; + // We *could* get OldestUnacked, but it would hurt performance and not provide any benefit + pc.PingID.OldestUnacked = 0; OutPacket(pc, ThrottleOutPacketType.Unknown); } @@ -3320,8 +3319,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP // If we received an update about our own avatar, process the avatar update priority queue immediately if (data.AgentID == m_agentId) ProcessAvatarTerseUpdates(); - else - m_udpServer.SignalOutgoingPacketHandler(); } private void ProcessAvatarTerseUpdates() @@ -3409,8 +3406,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP lock (m_primFullUpdates.SyncRoot) m_primFullUpdates.Enqueue(data.priority, objectData, data.localID); - - m_udpServer.SignalOutgoingPacketHandler(); } void ProcessPrimFullUpdates() @@ -3454,8 +3449,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP lock (m_primTerseUpdates.SyncRoot) m_primTerseUpdates.Enqueue(data.Priority, objectData, data.LocalID); - - m_udpServer.SignalOutgoingPacketHandler(); } void ProcessPrimTerseUpdates() diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs index ca9925c..458e78d 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs @@ -202,7 +202,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP public void Shutdown() { IsConnected = false; - NeedAcks.Clear(); for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) { m_packetOutboxes[i].Clear(); @@ -394,7 +393,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP { // Not enough tokens in the bucket, queue this packet queue.Enqueue(packet); - m_udpServer.SignalOutgoingPacketHandler(); return true; } } @@ -411,15 +409,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// /// This function is only called from a synchronous loop in the /// UDPServer so we don't need to bother making this thread safe - /// The minimum amount of time before the next packet - /// can be sent to this client - public int DequeueOutgoing() + /// True if any packets were sent, otherwise false + public bool DequeueOutgoing() { OutgoingPacket packet; OpenSim.Framework.LocklessQueue queue; TokenBucket bucket; - int dataLength; - int minTimeout = Int32.MaxValue; + bool packetSent = false; //string queueDebugOutput = String.Empty; // Serious debug business @@ -434,18 +430,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP // leaving a dequeued packet still waiting to be sent out. Try to // send it again OutgoingPacket nextPacket = m_nextPackets[i]; - dataLength = nextPacket.Buffer.DataLength; - if (bucket.RemoveTokens(dataLength)) + if (bucket.RemoveTokens(nextPacket.Buffer.DataLength)) { // Send the packet m_udpServer.SendPacketFinal(nextPacket); m_nextPackets[i] = null; - minTimeout = 0; - } - else if (minTimeout != 0) - { - // Check the minimum amount of time we would have to wait before this packet can be sent out - minTimeout = Math.Min(minTimeout, ((dataLength - bucket.Content) / bucket.DripPerMS) + 1); + packetSent = true; } } else @@ -457,23 +447,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP { // A packet was pulled off the queue. See if we have // enough tokens in the bucket to send it out - dataLength = packet.Buffer.DataLength; - if (bucket.RemoveTokens(dataLength)) + if (bucket.RemoveTokens(packet.Buffer.DataLength)) { // Send the packet m_udpServer.SendPacketFinal(packet); - minTimeout = 0; + packetSent = true; } else { // Save the dequeued packet for the next iteration m_nextPackets[i] = packet; - - if (minTimeout != 0) - { - // Check the minimum amount of time we would have to wait before this packet can be sent out - minTimeout = Math.Min(minTimeout, ((dataLength - bucket.Content) / bucket.DripPerMS) + 1); - } } // If the queue is empty after this dequeue, fire the queue @@ -492,7 +475,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } //m_log.Info("[LLUDPCLIENT]: Queues: " + queueDebugOutput); // Serious debug business - return minTimeout; + return packetSent; } /// diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 7d5c11e..a8ce102 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -121,12 +121,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP private int m_recvBufferSize; /// Flag to process packets asynchronously or synchronously private bool m_asyncPacketHandling; - /// Track the minimum amount of time needed to send the next packet in the - /// OutgoingPacketHandler loop so we know when to sleep - private int m_minTimeout = Int32.MaxValue; - /// EventWaitHandle to signify the outgoing packet handler thread that - /// there is more work to do - private EventWaitHandle m_outgoingWaitHandle; + /// Tracks whether or not a packet was sent each round so we know + /// whether or not to sleep + private bool m_packetSent; public Socket Server { get { return null; } } @@ -174,8 +171,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP base.Start(m_recvBufferSize, m_asyncPacketHandling); - m_outgoingWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset); - // Start the incoming packet processing thread Thread incomingThread = new Thread(IncomingPacketHandler); incomingThread.Name = "Incoming Packets (" + m_scene.RegionInfo.RegionName + ")"; @@ -190,8 +185,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP { m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + m_scene.RegionInfo.RegionName); base.Stop(); - - m_outgoingWaitHandle.Close(); } public void AddScene(IScene scene) @@ -374,10 +367,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP StartPingCheckPacket pc = (StartPingCheckPacket)PacketPool.Instance.GetPacket(PacketType.StartPingCheck); pc.Header.Reliable = false; - OutgoingPacket oldestPacket = udpClient.NeedAcks.GetOldest(); - pc.PingID.PingID = (byte)udpClient.CurrentPingSequence++; - pc.PingID.OldestUnacked = (oldestPacket != null) ? oldestPacket.SequenceNumber : 0; + // We *could* get OldestUnacked, but it would hurt performance and not provide any benefit + pc.PingID.OldestUnacked = 0; SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false); } @@ -397,39 +389,36 @@ namespace OpenSim.Region.ClientStack.LindenUDP return; } - if (udpClient.NeedAcks.Count > 0) + // Get a list of all of the packets that have been sitting unacked longer than udpClient.RTO + List expiredPackets = udpClient.NeedAcks.GetExpiredPackets(udpClient.RTO); + + if (expiredPackets != null) { - // Get a list of all of the packets that have been sitting unacked longer than udpClient.RTO - List expiredPackets = udpClient.NeedAcks.GetExpiredPackets(udpClient.RTO); + m_log.Debug("[LLUDPSERVER]: Resending " + expiredPackets.Count + " packets to " + udpClient.AgentID + ", RTO=" + udpClient.RTO); - if (expiredPackets != null) + // Resend packets + for (int i = 0; i < expiredPackets.Count; i++) { - m_log.Debug("[LLUDPSERVER]: Resending " + expiredPackets.Count + " packets to " + udpClient.AgentID); + OutgoingPacket outgoingPacket = expiredPackets[i]; - // Resend packets - for (int i = 0; i < expiredPackets.Count; i++) - { - OutgoingPacket outgoingPacket = expiredPackets[i]; - - //m_log.DebugFormat("[LLUDPSERVER]: Resending packet #{0} (attempt {1}), {2}ms have passed", - // outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount); + //m_log.DebugFormat("[LLUDPSERVER]: Resending packet #{0} (attempt {1}), {2}ms have passed", + // outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount); - // Set the resent flag - outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT); - outgoingPacket.Category = ThrottleOutPacketType.Resend; + // Set the resent flag + outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT); + outgoingPacket.Category = ThrottleOutPacketType.Resend; - // The TickCount will be set to the current time when the packet - // is actually sent out again - outgoingPacket.TickCount = 0; + // The TickCount will be set to the current time when the packet + // is actually sent out again + outgoingPacket.TickCount = 0; - // Bump up the resend count on this packet - Interlocked.Increment(ref outgoingPacket.ResendCount); - //Interlocked.Increment(ref Stats.ResentPackets); + // Bump up the resend count on this packet + Interlocked.Increment(ref outgoingPacket.ResendCount); + //Interlocked.Increment(ref Stats.ResentPackets); - // Requeue or resend the packet - if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) - SendPacketFinal(outgoingPacket); - } + // Requeue or resend the packet + if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) + SendPacketFinal(outgoingPacket); } } } @@ -577,11 +566,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Handle appended ACKs if (packet.Header.AppendedAcks && packet.Header.AckList != null) { - lock (udpClient.NeedAcks.SyncRoot) - { - for (int i = 0; i < packet.Header.AckList.Length; i++) - AcknowledgePacket(udpClient, packet.Header.AckList[i], now, packet.Header.Resent); - } + for (int i = 0; i < packet.Header.AckList.Length; i++) + udpClient.NeedAcks.Remove(packet.Header.AckList[i], now, packet.Header.Resent); } // Handle PacketAck packets @@ -589,11 +575,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP { PacketAckPacket ackPacket = (PacketAckPacket)packet; - lock (udpClient.NeedAcks.SyncRoot) - { - for (int i = 0; i < ackPacket.Packets.Length; i++) - AcknowledgePacket(udpClient, ackPacket.Packets[i].ID, now, packet.Header.Resent); - } + for (int i = 0; i < ackPacket.Packets.Length; i++) + udpClient.NeedAcks.Remove(ackPacket.Packets[i].ID, now, packet.Header.Resent); // We don't need to do anything else with PacketAck packets return; @@ -734,21 +717,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP client.Close(); } - private void AcknowledgePacket(LLUDPClient client, uint ack, int currentTime, bool fromResend) - { - OutgoingPacket ackedPacket; - if (client.NeedAcks.RemoveUnsafe(ack, out ackedPacket) && !fromResend) - { - // Update stats - Interlocked.Add(ref client.UnackedBytes, -ackedPacket.Buffer.DataLength); - - // Calculate the round-trip time for this packet and its ACK - int rtt = currentTime - ackedPacket.TickCount; - if (rtt > 0) - client.UpdateRoundTrip(rtt); - } - } - private void IncomingPacketHandler() { // Set this culture for the thread that incoming packets are received @@ -775,11 +743,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP packetInbox.Clear(); } - public bool SignalOutgoingPacketHandler() - { - return m_outgoingWaitHandle.Set(); - } - private void OutgoingPacketHandler() { // Set this culture for the thread that outgoing packets are sent @@ -790,28 +753,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP { try { - m_minTimeout = Int32.MaxValue; + m_packetSent = false; // Handle outgoing packets, resends, acknowledgements, and pings for each - // client. m_minTimeout will be set to 0 if more packets are waiting in the - // queues with bandwidth to spare, or the number of milliseconds we need to - // wait before at least one packet can be sent to a client + // client. m_packetSent will be set to true if a packet is sent m_scene.ClientManager.ForEachSync(ClientOutgoingPacketHandler); - // Can't wait for a negative amount of time, and put a 100ms ceiling on our - // maximum wait time - m_minTimeout = Utils.Clamp(m_minTimeout, 0, 100); - - if (m_minTimeout > 0) - { - // Don't bother waiting for a shorter interval than our TickCountResolution - // since the token buckets wouldn't update anyways - m_minTimeout = Math.Max(m_minTimeout, (int)TickCountResolution); - - // Wait for someone to signal that packets are ready to be sent, or for our - // sleep interval to expire - m_outgoingWaitHandle.WaitOne(m_minTimeout); - } + // If a packet was sent, only do a minimum length context switch to allow + // other parts of the code to do work. If nothing was sent, sleep for the + // minimum amount of time before a token bucket could get more tokens + if (m_packetSent) + Thread.Sleep(0); + else + Thread.Sleep((int)TickCountResolution); } catch (Exception ex) { @@ -841,7 +795,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (udpClient.ElapsedMSOutgoingPacketHandler >= 100) { ResendUnacked(udpClient); - udpClient.ElapsedMSOutgoingPacketHandler -= 100; + udpClient.ElapsedMSOutgoingPacketHandler = 0; udpClient.Elapsed100MSOutgoingPacketHandler += 1; } @@ -849,7 +803,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (udpClient.Elapsed100MSOutgoingPacketHandler >= 5) { SendAcks(udpClient); - udpClient.Elapsed100MSOutgoingPacketHandler -= 5; + udpClient.Elapsed100MSOutgoingPacketHandler = 0; udpClient.Elapsed500MSOutgoingPacketHandler += 1; } @@ -857,19 +811,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (udpClient.Elapsed500MSOutgoingPacketHandler >= 10) { SendPing(udpClient); - udpClient.Elapsed500MSOutgoingPacketHandler -= 10; + udpClient.Elapsed500MSOutgoingPacketHandler = 0; } // Dequeue any outgoing packets that are within the throttle limits - // and get the minimum time we would have to sleep before this client - // could send a packet out - int minTimeoutThisLoop = udpClient.DequeueOutgoing(); - - // Although this is not thread safe, it is cheaper than locking and the - // worst that will happen is we sleep for slightly longer than the - // minimum necessary interval - if (minTimeoutThisLoop < m_minTimeout) - m_minTimeout = minTimeoutThisLoop; + if (udpClient.DequeueOutgoing()) + m_packetSent = true; } udpClient.TickLastOutgoingPacketHandler = thisTick; diff --git a/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs b/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs index 87c7df4..12f0c0a 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs @@ -37,97 +37,57 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// public sealed class UnackedPacketCollection { - /// Synchronization primitive. A lock must be acquired on this - /// object before calling any of the unsafe methods - public object SyncRoot = new object(); - - /// Holds the actual unacked packet data, sorted by sequence number - private SortedDictionary packets = new SortedDictionary(); - - /// Gets the total number of unacked packets - public int Count { get { return packets.Count; } } - /// - /// Default constructor + /// Holds information about a pending acknowledgement /// - public UnackedPacketCollection() + private struct PendingAck { - } + /// Sequence number of the packet to remove + public uint SequenceNumber; + /// Environment.TickCount value when the remove was queued. + /// This is used to update round-trip times for packets + public int RemoveTime; + /// Whether or not this acknowledgement was attached to a + /// resent packet. If so, round-trip time will not be calculated + public bool FromResend; - /// - /// Add an unacked packet to the collection - /// - /// Packet that is awaiting acknowledgement - /// True if the packet was successfully added, false if the - /// packet already existed in the collection - public bool Add(OutgoingPacket packet) - { - lock (SyncRoot) + public PendingAck(uint sequenceNumber, int currentTime, bool fromResend) { - if (!packets.ContainsKey(packet.SequenceNumber)) - { - packets.Add(packet.SequenceNumber, packet); - return true; - } - return false; + SequenceNumber = sequenceNumber; + RemoveTime = currentTime; + FromResend = fromResend; } } - /// - /// Removes a packet from the collection without attempting to obtain a - /// lock first - /// - /// Sequence number of the packet to remove - /// True if the packet was found and removed, otherwise false - public bool RemoveUnsafe(uint sequenceNumber) - { - return packets.Remove(sequenceNumber); - } - - /// - /// Removes a packet from the collection without attempting to obtain a - /// lock first - /// - /// Sequence number of the packet to remove - /// Returns the removed packet - /// True if the packet was found and removed, otherwise false - public bool RemoveUnsafe(uint sequenceNumber, out OutgoingPacket packet) - { - if (packets.TryGetValue(sequenceNumber, out packet)) - { - packets.Remove(sequenceNumber); - return true; - } - - return false; - } + /// Holds the actual unacked packet data, sorted by sequence number + private SortedDictionary m_packets = new SortedDictionary(); + /// Holds packets that need to be added to the unacknowledged list + private LocklessQueue m_pendingAdds = new LocklessQueue(); + /// Holds information about pending acknowledgements + private LocklessQueue m_pendingRemoves = new LocklessQueue(); /// - /// Removes all elements from the collection + /// Add an unacked packet to the collection /// - public void Clear() + /// Packet that is awaiting acknowledgement + /// True if the packet was successfully added, false if the + /// packet already existed in the collection + /// This does not immediately add the ACK to the collection, + /// it only queues it so it can be added in a thread-safe way later + public void Add(OutgoingPacket packet) { - lock (SyncRoot) - packets.Clear(); + m_pendingAdds.Enqueue(packet); } /// - /// Gets the packet with the lowest sequence number + /// Marks a packet as acknowledged /// - /// The packet with the lowest sequence number, or null if the - /// collection is empty - public OutgoingPacket GetOldest() + /// Sequence number of the packet to + /// acknowledge + /// Current value of Environment.TickCount + public void Remove(uint sequenceNumber, int currentTime, bool fromResend) { - lock (SyncRoot) - { - using (SortedDictionary.ValueCollection.Enumerator e = packets.Values.GetEnumerator()) - { - if (e.MoveNext()) - return e.Current; - else - return null; - } - } + m_pendingRemoves.Enqueue(new PendingAck(sequenceNumber, currentTime, fromResend)); } /// @@ -138,14 +98,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// packet is considered expired /// A list of all expired packets according to the given /// expiration timeout + /// This function is not thread safe, and cannot be called + /// multiple times concurrently public List GetExpiredPackets(int timeoutMS) { + ProcessQueues(); + List expiredPackets = null; - lock (SyncRoot) + if (m_packets.Count > 0) { int now = Environment.TickCount; - foreach (OutgoingPacket packet in packets.Values) + + foreach (OutgoingPacket packet in m_packets.Values) { // TickCount of zero means a packet is in the resend queue // but hasn't actually been sent over the wire yet @@ -167,5 +132,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP return expiredPackets; } + + private void ProcessQueues() + { + // Process all the pending adds + OutgoingPacket pendingAdd; + while (m_pendingAdds.Dequeue(out pendingAdd)) + m_packets[pendingAdd.SequenceNumber] = pendingAdd; + + // Process all the pending removes, including updating statistics and round-trip times + PendingAck pendingRemove; + OutgoingPacket ackedPacket; + while (m_pendingRemoves.Dequeue(out pendingRemove)) + { + if (m_packets.TryGetValue(pendingRemove.SequenceNumber, out ackedPacket)) + { + m_packets.Remove(pendingRemove.SequenceNumber); + + // Update stats + System.Threading.Interlocked.Add(ref ackedPacket.Client.UnackedBytes, -ackedPacket.Buffer.DataLength); + + if (!pendingRemove.FromResend) + { + // Calculate the round-trip time for this packet and its ACK + int rtt = pendingRemove.RemoveTime - ackedPacket.TickCount; + if (rtt > 0) + ackedPacket.Client.UpdateRoundTrip(rtt); + } + } + } + } } } -- cgit v1.1 From d88bb83136752fadb1c2e3b64641acc2b3b6dd30 Mon Sep 17 00:00:00 2001 From: Melanie Date: Wed, 21 Oct 2009 20:47:24 +0100 Subject: Fix llParticleSystem to accept LSL variables and LSL constants in place of the named constants for the rule selector. Information provided by Snowcrash --- OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 224b3cc..9a70890 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -5844,7 +5844,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api for (int i = 0; i < rules.Length; i += 2) { - switch ((int)rules.Data[i]) + switch (Convert.ToInt32(rules.Data[i])) { case (int)ScriptBaseClass.PSYS_PART_FLAGS: prules.PartDataFlags = (Primitive.ParticleSystem.ParticleDataFlags)(uint)rules.GetLSLIntegerItem(i + 1); -- cgit v1.1 From 7ee422a344ff22cf988aea2355628d2dee831983 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Wed, 21 Oct 2009 13:47:16 -0700 Subject: * Handle UseCircuitCode packets asynchronously. Adding an agent to a scene can take several seconds, and was blocking up packet handling in the meantime * Clamp retransmission timeout values between three and 10 seconds * Log outgoing time for a packet right after it is sent instead of well before * Loop through the entire UnackedPacketCollection when looking for expired packets --- .../Region/ClientStack/LindenUDP/LLUDPClient.cs | 7 +++- .../Region/ClientStack/LindenUDP/LLUDPServer.cs | 47 ++++++++++++++++++---- .../LindenUDP/UnackedPacketCollection.cs | 8 ++-- 3 files changed, 49 insertions(+), 13 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs index 458e78d..a43197d 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs @@ -505,8 +505,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP SRTT = (1.0f - ALPHA) * SRTT + ALPHA * r; } - // Always round retransmission timeout up to two seconds - RTO = Math.Max(2000, (int)(SRTT + Math.Max(m_udpServer.TickCountResolution, K * RTTVAR))); + RTO = (int)(SRTT + Math.Max(m_udpServer.TickCountResolution, K * RTTVAR)); + + // Clamp the retransmission timeout to manageable values + RTO = Utils.Clamp(RTO, 3000, 10000); + //m_log.Debug("[LLUDPCLIENT]: Setting agent " + this.Agent.FullName + "'s RTO to " + RTO + "ms with an RTTVAR of " + // RTTVAR + " based on new RTT of " + r + "ms"); } diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index a8ce102..209c0e0 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -381,7 +381,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Disconnect an agent if no packets are received for some time //FIXME: Make 60 an .ini setting - if (Environment.TickCount - udpClient.TickLastPacketReceived > 1000 * 60) + if ((Environment.TickCount & Int32.MaxValue) - udpClient.TickLastPacketReceived > 1000 * 60) { m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + udpClient.AgentID); @@ -439,9 +439,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (!udpClient.IsConnected) return; - // Keep track of when this packet was sent out (right now) - outgoingPacket.TickCount = Environment.TickCount; - #region ACK Appending int dataLength = buffer.DataLength; @@ -494,6 +491,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Put the UDP payload on the wire AsyncBeginSend(buffer); + + // Keep track of when this packet was sent out (right now) + outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue; } protected override void PacketReceived(UDPPacketBuffer buffer) @@ -536,7 +536,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP // UseCircuitCode handling if (packet.Type == PacketType.UseCircuitCode) { - AddNewClient((UseCircuitCodePacket)packet, (IPEndPoint)buffer.RemoteEndPoint); + Util.FireAndForget( + delegate(object o) + { + IPEndPoint remoteEndPoint = (IPEndPoint)buffer.RemoteEndPoint; + + // Begin the process of adding the client to the simulator + AddNewClient((UseCircuitCodePacket)packet, remoteEndPoint); + + // Acknowledge the UseCircuitCode packet + SendAckImmediate(remoteEndPoint, packet.Header.Sequence); + } + ); + return; } // Determine which agent this packet came from @@ -558,11 +570,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Stats tracking Interlocked.Increment(ref udpClient.PacketsReceived); - #region ACK Receiving - - int now = Environment.TickCount; + int now = Environment.TickCount & Int32.MaxValue; udpClient.TickLastPacketReceived = now; + #region ACK Receiving + // Handle appended ACKs if (packet.Header.AppendedAcks && packet.Header.AckList != null) { @@ -650,6 +662,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP { } + private void SendAckImmediate(IPEndPoint remoteEndpoint, uint sequenceNumber) + { + PacketAckPacket ack = new PacketAckPacket(); + ack.Header.Reliable = false; + ack.Packets = new PacketAckPacket.PacketsBlock[1]; + ack.Packets[0] = new PacketAckPacket.PacketsBlock(); + ack.Packets[0].ID = sequenceNumber; + + byte[] packetData = ack.ToBytes(); + int length = packetData.Length; + + UDPPacketBuffer buffer = new UDPPacketBuffer(remoteEndpoint, length); + buffer.DataLength = length; + + Buffer.BlockCopy(packetData, 0, buffer.Data, 0, length); + + AsyncBeginSend(buffer); + } + private bool IsClientAuthorized(UseCircuitCodePacket useCircuitCode, out AuthenticateResponse sessionInfo) { UUID agentID = useCircuitCode.CircuitCode.ID; diff --git a/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs b/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs index 12f0c0a..bd5fe1c 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs @@ -85,6 +85,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Sequence number of the packet to /// acknowledge /// Current value of Environment.TickCount + /// This does not immediately acknowledge the packet, it only + /// queues the ack so it can be handled in a thread-safe way later public void Remove(uint sequenceNumber, int currentTime, bool fromResend) { m_pendingRemoves.Enqueue(new PendingAck(sequenceNumber, currentTime, fromResend)); @@ -108,7 +110,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (m_packets.Count > 0) { - int now = Environment.TickCount; + int now = Environment.TickCount & Int32.MaxValue; foreach (OutgoingPacket packet in m_packets.Values) { @@ -123,10 +125,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP expiredPackets = new List(); expiredPackets.Add(packet); } - else + /*else { break; - } + }*/ } } -- cgit v1.1 From bb4da417adac6189c4d999857d43ca7eb858e3c4 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Wed, 21 Oct 2009 14:03:49 -0700 Subject: Removing the Sleep(0) call from the OutgoingPacketHandler --- OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 209c0e0..be6f7ef 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -790,12 +790,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP // client. m_packetSent will be set to true if a packet is sent m_scene.ClientManager.ForEachSync(ClientOutgoingPacketHandler); - // If a packet was sent, only do a minimum length context switch to allow - // other parts of the code to do work. If nothing was sent, sleep for the - // minimum amount of time before a token bucket could get more tokens - if (m_packetSent) - Thread.Sleep(0); - else + // If nothing was sent, sleep for the minimum amount of time before a + // token bucket could get more tokens + if (!m_packetSent) Thread.Sleep((int)TickCountResolution); } catch (Exception ex) -- cgit v1.1 From 62f1bfd136df7a68e9f829acc1db22354772bad3 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Wed, 21 Oct 2009 14:25:22 -0700 Subject: Testing out a hack to identify the source of the high cpu usage --- OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs | 3 +++ 1 file changed, 3 insertions(+) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs index a43197d..de67ca7 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs @@ -552,6 +552,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + type + ") threw an exception: " + e.Message, e); } } + // HACK: Try spending some extra time here to slow down OnQueueEmpty calls + System.Threading.Thread.Sleep(100); + m_onQueueEmptyRunning[i] = false; } } -- cgit v1.1 From 2752a3525c6c57470024d0dddfd69d593abc4594 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Wed, 21 Oct 2009 15:22:23 -0700 Subject: * Changed the timing calculations for sending resends/acks/pings from per-client back to per-scene * Testing a fix from Jim to make the cpu usage fix cleaner --- .../Region/ClientStack/LindenUDP/LLClientView.cs | 6 +- .../Region/ClientStack/LindenUDP/LLUDPClient.cs | 13 +--- .../Region/ClientStack/LindenUDP/LLUDPServer.cs | 85 +++++++++++++++------- 3 files changed, 63 insertions(+), 41 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 997f38c..91afa4d 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -3558,7 +3558,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP ProcessTextureRequests(); break; case ThrottleOutPacketType.Task: - if (Monitor.TryEnter(m_avatarTerseUpdates.SyncRoot, 1)) + if (Monitor.TryEnter(m_avatarTerseUpdates.SyncRoot)) { try { @@ -3573,7 +3573,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } break; case ThrottleOutPacketType.State: - if (Monitor.TryEnter(m_primFullUpdates.SyncRoot, 1)) + if (Monitor.TryEnter(m_primFullUpdates.SyncRoot)) { try { @@ -3586,7 +3586,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP finally { Monitor.Exit(m_primFullUpdates.SyncRoot); } } - if (Monitor.TryEnter(m_primTerseUpdates.SyncRoot, 1)) + if (Monitor.TryEnter(m_primTerseUpdates.SyncRoot)) { try { diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs index de67ca7..0a090b4 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs @@ -103,14 +103,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP public bool IsPaused; /// Environment.TickCount when the last packet was received for this client public int TickLastPacketReceived; - /// Environment.TickCount of the last time the outgoing packet handler executed for this client - public int TickLastOutgoingPacketHandler; - /// Keeps track of the number of elapsed milliseconds since the last time the outgoing packet handler executed for this client - public int ElapsedMSOutgoingPacketHandler; - /// Keeps track of the number of 100 millisecond periods elapsed in the outgoing packet handler executed for this client - public int Elapsed100MSOutgoingPacketHandler; - /// Keeps track of the number of 500 millisecond periods elapsed in the outgoing packet handler executed for this client - public int Elapsed500MSOutgoingPacketHandler; /// Smoothed round-trip time. A smoothed average of the round-trip time for sending a /// reliable packet to the client and receiving an ACK @@ -191,9 +183,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Initialize this to a sane value to prevent early disconnects TickLastPacketReceived = Environment.TickCount & Int32.MaxValue; - ElapsedMSOutgoingPacketHandler = 0; - Elapsed100MSOutgoingPacketHandler = 0; - Elapsed500MSOutgoingPacketHandler = 0; } /// @@ -553,7 +542,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } // HACK: Try spending some extra time here to slow down OnQueueEmpty calls - System.Threading.Thread.Sleep(100); + //System.Threading.Thread.Sleep(100); m_onQueueEmptyRunning[i] = false; } diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index be6f7ef..4bdf132 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -125,6 +125,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// whether or not to sleep private bool m_packetSent; + /// Environment.TickCount of the last time the outgoing packet handler executed + private int m_tickLastOutgoingPacketHandler; + /// Keeps track of the number of elapsed milliseconds since the last time the outgoing packet handler looped + private int m_elapsedMSOutgoingPacketHandler; + /// Keeps track of the number of 100 millisecond periods elapsed in the outgoing packet handler executed + private int m_elapsed100MSOutgoingPacketHandler; + /// Keeps track of the number of 500 millisecond periods elapsed in the outgoing packet handler executed + private int m_elapsed500MSOutgoingPacketHandler; + + /// Flag to signal when clients should check for resends + private bool m_resendUnacked; + /// Flag to signal when clients should send ACKs + private bool m_sendAcks; + /// Flag to signal when clients should send pings + private bool m_sendPing; + public Socket Server { get { return null; } } public LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager) @@ -786,6 +802,46 @@ namespace OpenSim.Region.ClientStack.LindenUDP { m_packetSent = false; + #region Update Timers + + m_resendUnacked = false; + m_sendAcks = false; + m_sendPing = false; + + // Update elapsed time + int thisTick = Environment.TickCount & Int32.MaxValue; + if (m_tickLastOutgoingPacketHandler > thisTick) + m_elapsedMSOutgoingPacketHandler += ((Int32.MaxValue - m_tickLastOutgoingPacketHandler) + thisTick); + else + m_elapsedMSOutgoingPacketHandler += (thisTick - m_tickLastOutgoingPacketHandler); + + m_tickLastOutgoingPacketHandler = thisTick; + + // Check for pending outgoing resends every 100ms + if (m_elapsedMSOutgoingPacketHandler >= 100) + { + m_resendUnacked = true; + m_elapsedMSOutgoingPacketHandler = 0; + m_elapsed100MSOutgoingPacketHandler += 1; + } + + // Check for pending outgoing ACKs every 500ms + if (m_elapsed100MSOutgoingPacketHandler >= 5) + { + m_sendAcks = true; + m_elapsed100MSOutgoingPacketHandler = 0; + m_elapsed500MSOutgoingPacketHandler += 1; + } + + // Send pings to clients every 5000ms + if (m_elapsed500MSOutgoingPacketHandler >= 10) + { + m_sendPing = true; + m_elapsed500MSOutgoingPacketHandler = 0; + } + + #endregion Update Timers + // Handle outgoing packets, resends, acknowledgements, and pings for each // client. m_packetSent will be set to true if a packet is sent m_scene.ClientManager.ForEachSync(ClientOutgoingPacketHandler); @@ -810,44 +866,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP { LLUDPClient udpClient = ((LLClientView)client).UDPClient; - // Update ElapsedMSOutgoingPacketHandler - int thisTick = Environment.TickCount & Int32.MaxValue; - if (udpClient.TickLastOutgoingPacketHandler > thisTick) - udpClient.ElapsedMSOutgoingPacketHandler += ((Int32.MaxValue - udpClient.TickLastOutgoingPacketHandler) + thisTick); - else - udpClient.ElapsedMSOutgoingPacketHandler += (thisTick - udpClient.TickLastOutgoingPacketHandler); - if (udpClient.IsConnected) { - // Check for pending outgoing resends every 100ms - if (udpClient.ElapsedMSOutgoingPacketHandler >= 100) - { + if (m_resendUnacked) ResendUnacked(udpClient); - udpClient.ElapsedMSOutgoingPacketHandler = 0; - udpClient.Elapsed100MSOutgoingPacketHandler += 1; - } - // Check for pending outgoing ACKs every 500ms - if (udpClient.Elapsed100MSOutgoingPacketHandler >= 5) - { + if (m_sendAcks) SendAcks(udpClient); - udpClient.Elapsed100MSOutgoingPacketHandler = 0; - udpClient.Elapsed500MSOutgoingPacketHandler += 1; - } - // Send pings to clients every 5000ms - if (udpClient.Elapsed500MSOutgoingPacketHandler >= 10) - { + if (m_sendPing) SendPing(udpClient); - udpClient.Elapsed500MSOutgoingPacketHandler = 0; - } // Dequeue any outgoing packets that are within the throttle limits if (udpClient.DequeueOutgoing()) m_packetSent = true; } - - udpClient.TickLastOutgoingPacketHandler = thisTick; } } catch (Exception ex) -- cgit v1.1 From b06f258319f088bcf6658880ed371ef313bac3b6 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Wed, 21 Oct 2009 16:21:08 -0700 Subject: * FireQueueEmpty now checks if a measurable amount of time has passed, and if not it sleeps for a small amount of time. This throttles OnQueueEmpty calls where there is no callback or the callback is doing very little work * Changed HandleQueueEmpty()'s Monitor.TryEnter() calls to locks. We want to take our time in this function and do all the work necessary, since returning too fast will induce a sleep anyways --- .../Region/ClientStack/LindenUDP/LLClientView.cs | 42 ++++++---------------- .../Region/ClientStack/LindenUDP/LLUDPClient.cs | 8 +++-- .../LindenUDP/UnackedPacketCollection.cs | 4 --- 3 files changed, 16 insertions(+), 38 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 91afa4d..0bb7a71 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -3558,45 +3558,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP ProcessTextureRequests(); break; case ThrottleOutPacketType.Task: - if (Monitor.TryEnter(m_avatarTerseUpdates.SyncRoot)) + lock (m_avatarTerseUpdates.SyncRoot) { - try - { - if (m_avatarTerseUpdates.Count > 0) - { - - ProcessAvatarTerseUpdates(); - return; - } - } - finally { Monitor.Exit(m_avatarTerseUpdates.SyncRoot); } + if (m_avatarTerseUpdates.Count > 0) + ProcessAvatarTerseUpdates(); } break; case ThrottleOutPacketType.State: - if (Monitor.TryEnter(m_primFullUpdates.SyncRoot)) + lock (m_primFullUpdates.SyncRoot) { - try - { - if (m_primFullUpdates.Count > 0) - { - ProcessPrimFullUpdates(); - return; - } - } - finally { Monitor.Exit(m_primFullUpdates.SyncRoot); } + if (m_primFullUpdates.Count > 0) + ProcessPrimFullUpdates(); } - if (Monitor.TryEnter(m_primTerseUpdates.SyncRoot)) + lock (m_primTerseUpdates.SyncRoot) { - try - { - if (m_primTerseUpdates.Count > 0) - { - ProcessPrimTerseUpdates(); - return; - } - } - finally { Monitor.Exit(m_primTerseUpdates.SyncRoot); } + if (m_primTerseUpdates.Count > 0) + ProcessPrimTerseUpdates(); } break; } @@ -10344,7 +10322,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP { if (lookup.Heap.ContainsHandle(lookup.Handle)) lookup.Heap[lookup.Handle] = - new MinHeapItem(priority, item.Value, item.LocalID); + new MinHeapItem(priority, item.Value, item.LocalID, this.m_comparison); } else { diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs index 0a090b4..71f4c47 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs @@ -535,14 +535,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP ThrottleOutPacketType type = (ThrottleOutPacketType)i; QueueEmpty callback = OnQueueEmpty; + int start = Environment.TickCount; + if (callback != null) { try { callback(type); } catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + type + ") threw an exception: " + e.Message, e); } } - // HACK: Try spending some extra time here to slow down OnQueueEmpty calls - //System.Threading.Thread.Sleep(100); + // Make sure all queue empty calls take at least a measurable amount of time, + // otherwise we'll peg a CPU trying to fire these too fast + if (Environment.TickCount == start) + System.Threading.Thread.Sleep((int)m_udpServer.TickCountResolution); m_onQueueEmptyRunning[i] = false; } diff --git a/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs b/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs index bd5fe1c..016712f 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs @@ -125,10 +125,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP expiredPackets = new List(); expiredPackets.Add(packet); } - /*else - { - break; - }*/ } } -- cgit v1.1 From 4e04f6b3a5a875c7d8820c679bcbcdcfba1227bf Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Wed, 21 Oct 2009 17:02:55 -0700 Subject: * Clarified what FireQueueEmpty is doing with a MIN_CALLBACK_MS constant and upped it to 30ms * Removed the unused PacketSent() function * Switched UnackedPacketCollection from a SortedDictionary to a Dictionary now that the sorting is no longer needed. Big performance improvement for ResendUnacked() --- OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs | 11 +++++++---- OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs | 4 ---- OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs | 9 --------- .../Region/ClientStack/LindenUDP/UnackedPacketCollection.cs | 2 +- 4 files changed, 8 insertions(+), 18 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs index 71f4c47..2d86a40 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs @@ -531,11 +531,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// as an object to match the WaitCallback delegate signature private void FireQueueEmpty(object o) { + const int MIN_CALLBACK_MS = 30; + int i = (int)o; ThrottleOutPacketType type = (ThrottleOutPacketType)i; QueueEmpty callback = OnQueueEmpty; - int start = Environment.TickCount; + int start = Environment.TickCount & Int32.MaxValue; if (callback != null) { @@ -543,10 +545,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + type + ") threw an exception: " + e.Message, e); } } - // Make sure all queue empty calls take at least a measurable amount of time, + // Make sure all queue empty calls take at least some amount of time, // otherwise we'll peg a CPU trying to fire these too fast - if (Environment.TickCount == start) - System.Threading.Thread.Sleep((int)m_udpServer.TickCountResolution); + int elapsedMS = (Environment.TickCount & Int32.MaxValue) - start; + if (elapsedMS < MIN_CALLBACK_MS) + System.Threading.Thread.Sleep(MIN_CALLBACK_MS - elapsedMS); m_onQueueEmptyRunning[i] = false; } diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 4bdf132..40d3771 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -674,10 +674,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP packetInbox.Enqueue(new IncomingPacket(udpClient, packet)); } - protected override void PacketSent(UDPPacketBuffer buffer, int bytesSent) - { - } - private void SendAckImmediate(IPEndPoint remoteEndpoint, uint sequenceNumber) { PacketAckPacket ack = new PacketAckPacket(); diff --git a/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs index d16837d..552cc4a 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs @@ -45,13 +45,6 @@ namespace OpenMetaverse /// /// Incoming packet buffer protected abstract void PacketReceived(UDPPacketBuffer buffer); - - /// - /// This method is called when an outgoing packet is sent - /// - /// Outgoing packet buffer - /// Number of bytes written to the wire - protected abstract void PacketSent(UDPPacketBuffer buffer, int bytesSent); /// UDP port to bind to in server mode protected int m_udpPort; @@ -279,8 +272,6 @@ namespace OpenMetaverse { UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState; int bytesSent = m_udpSocket.EndSendTo(result); - - PacketSent(buf, bytesSent); } catch (SocketException) { } catch (ObjectDisposedException) { } diff --git a/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs b/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs index 016712f..3e2e81c 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs @@ -60,7 +60,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } /// Holds the actual unacked packet data, sorted by sequence number - private SortedDictionary m_packets = new SortedDictionary(); + private Dictionary m_packets = new Dictionary(); /// Holds packets that need to be added to the unacknowledged list private LocklessQueue m_pendingAdds = new LocklessQueue(); /// Holds information about pending acknowledgements -- cgit v1.1 From 6492640e72776d9f0a015e6a719c8cef28ccb7e3 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Wed, 21 Oct 2009 18:03:41 -0700 Subject: * Change the OnQueueEmpty signature to send the flags of the queues that are empty instead of firing once per empty queue * Change the OnQueueEmpty firing to use a minimum time until next fire instead of a sleep * Set OutgoingPacket.TickCount = 0 earlier to avoid extra resends when things are running slowly (inside a profiler, for example) --- .../Region/ClientStack/LindenUDP/LLClientView.cs | 50 +++++----- .../Region/ClientStack/LindenUDP/LLUDPClient.cs | 110 ++++++++++++++------- .../Region/ClientStack/LindenUDP/LLUDPServer.cs | 4 - .../LindenUDP/UnackedPacketCollection.cs | 5 + 4 files changed, 108 insertions(+), 61 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 0bb7a71..432fee7 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -3550,33 +3550,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(attach, ThrottleOutPacketType.Task); } - void HandleQueueEmpty(ThrottleOutPacketType queue) + void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories) { - switch (queue) + if ((categories & ThrottleOutPacketTypeFlags.Task) != 0) { - case ThrottleOutPacketType.Texture: - ProcessTextureRequests(); - break; - case ThrottleOutPacketType.Task: - lock (m_avatarTerseUpdates.SyncRoot) - { - if (m_avatarTerseUpdates.Count > 0) - ProcessAvatarTerseUpdates(); - } - break; - case ThrottleOutPacketType.State: - lock (m_primFullUpdates.SyncRoot) - { - if (m_primFullUpdates.Count > 0) - ProcessPrimFullUpdates(); - } + lock (m_avatarTerseUpdates.SyncRoot) + { + if (m_avatarTerseUpdates.Count > 0) + ProcessAvatarTerseUpdates(); + } + } - lock (m_primTerseUpdates.SyncRoot) - { - if (m_primTerseUpdates.Count > 0) - ProcessPrimTerseUpdates(); - } - break; + if ((categories & ThrottleOutPacketTypeFlags.State) != 0) + { + lock (m_primFullUpdates.SyncRoot) + { + if (m_primFullUpdates.Count > 0) + ProcessPrimFullUpdates(); + } + + lock (m_primTerseUpdates.SyncRoot) + { + if (m_primTerseUpdates.Count > 0) + ProcessPrimTerseUpdates(); + } + } + + if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0) + { + ProcessTextureRequests(); } } diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs index 2d86a40..a9bc7d2 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs @@ -50,11 +50,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// are waiting on ACKs for public delegate void PacketStats(int inPackets, int outPackets, int unAckedBytes); /// - /// Fired when the queue for a packet category is empty. This event can be - /// hooked to put more data on the empty queue + /// Fired when the queue for one or more packet categories is empty. This + /// event can be hooked to put more data on the empty queues /// - /// Category of the packet queue that is empty - public delegate void QueueEmpty(ThrottleOutPacketType category); + /// Categories of the packet queues that are empty + public delegate void QueueEmpty(ThrottleOutPacketTypeFlags categories); #endregion Delegates @@ -128,6 +128,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP private int m_packetsReceivedReported; /// Total number of sent packets that we have reported to the OnPacketStats event(s) private int m_packetsSentReported; + /// Holds the Environment.TickCount value of when the next OnQueueEmpty can be fired + private int m_nextOnQueueEmpty = 1; /// Throttle bucket for this agent's connection private readonly TokenBucket m_throttle; @@ -140,9 +142,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// A container that can hold one packet for each outbox, used to store /// dequeued packets that are being held for throttling private readonly OutgoingPacket[] m_nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT]; - /// Flags to prevent queue empty callbacks from stacking up on - /// top of each other - private readonly bool[] m_onQueueEmptyRunning = new bool[THROTTLE_CATEGORY_COUNT]; /// A reference to the LLUDPServer that is managing this client private readonly LLUDPServer m_udpServer; @@ -405,6 +404,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP OpenSim.Framework.LocklessQueue queue; TokenBucket bucket; bool packetSent = false; + ThrottleOutPacketTypeFlags emptyCategories = 0; //string queueDebugOutput = String.Empty; // Serious debug business @@ -452,17 +452,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP // empty callback now so it has a chance to fill before we // get back here if (queue.Count == 0) - BeginFireQueueEmpty(i); + emptyCategories |= CategoryToFlag(i); } else { // No packets in this queue. Fire the queue empty callback // if it has not been called recently - BeginFireQueueEmpty(i); + emptyCategories |= CategoryToFlag(i); } } } + if (emptyCategories != 0) + BeginFireQueueEmpty(emptyCategories); + //m_log.Info("[LLUDPCLIENT]: Queues: " + queueDebugOutput); // Serious debug business return packetSent; } @@ -509,49 +512,90 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// /// Throttle category to fire the callback /// for - private void BeginFireQueueEmpty(int throttleIndex) + private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories) { - // Unknown is -1 and Resend is 0. Make sure we are only firing the - // callback for categories other than those - if (throttleIndex > 0) + if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty) { - if (!m_onQueueEmptyRunning[throttleIndex]) - { - m_onQueueEmptyRunning[throttleIndex] = true; - Util.FireAndForget(FireQueueEmpty, throttleIndex); - } + // Use a value of 0 to signal that FireQueueEmpty is running + m_nextOnQueueEmpty = 0; + // Asynchronously run the callback + Util.FireAndForget(FireQueueEmpty, categories); } } /// - /// Checks to see if this queue empty callback is already running, - /// then firing the event + /// Fires the OnQueueEmpty callback and sets the minimum time that it + /// can be called again /// - /// Throttle category to fire the callback for, stored - /// as an object to match the WaitCallback delegate signature + /// Throttle categories to fire the callback for, + /// stored as an object to match the WaitCallback delegate + /// signature private void FireQueueEmpty(object o) { const int MIN_CALLBACK_MS = 30; - int i = (int)o; - ThrottleOutPacketType type = (ThrottleOutPacketType)i; + ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o; QueueEmpty callback = OnQueueEmpty; - + int start = Environment.TickCount & Int32.MaxValue; if (callback != null) { - try { callback(type); } - catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + type + ") threw an exception: " + e.Message, e); } + try { callback(categories); } + catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); } } - // Make sure all queue empty calls take at least some amount of time, - // otherwise we'll peg a CPU trying to fire these too fast - int elapsedMS = (Environment.TickCount & Int32.MaxValue) - start; - if (elapsedMS < MIN_CALLBACK_MS) - System.Threading.Thread.Sleep(MIN_CALLBACK_MS - elapsedMS); + m_nextOnQueueEmpty = start + MIN_CALLBACK_MS; + if (m_nextOnQueueEmpty == 0) + m_nextOnQueueEmpty = 1; + } - m_onQueueEmptyRunning[i] = false; + /// + /// Converts a integer to a + /// flag value + /// + /// Throttle category to convert + /// Flag representation of the throttle category + private static ThrottleOutPacketTypeFlags CategoryToFlag(int i) + { + ThrottleOutPacketType category = (ThrottleOutPacketType)i; + + /* + * Land = 1, + /// Wind data + Wind = 2, + /// Cloud data + Cloud = 3, + /// Any packets that do not fit into the other throttles + Task = 4, + /// Texture assets + Texture = 5, + /// Non-texture assets + Asset = 6, + /// Avatar and primitive data + /// This is a sub-category of Task + State = 7, + */ + + switch (category) + { + case ThrottleOutPacketType.Land: + return ThrottleOutPacketTypeFlags.Land; + case ThrottleOutPacketType.Wind: + return ThrottleOutPacketTypeFlags.Wind; + case ThrottleOutPacketType.Cloud: + return ThrottleOutPacketTypeFlags.Cloud; + case ThrottleOutPacketType.Task: + return ThrottleOutPacketTypeFlags.Task; + case ThrottleOutPacketType.Texture: + return ThrottleOutPacketTypeFlags.Texture; + case ThrottleOutPacketType.Asset: + return ThrottleOutPacketTypeFlags.Asset; + case ThrottleOutPacketType.State: + return ThrottleOutPacketTypeFlags.State; + default: + return 0; + } } } } diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 40d3771..a9f4b2c 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -424,10 +424,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT); outgoingPacket.Category = ThrottleOutPacketType.Resend; - // The TickCount will be set to the current time when the packet - // is actually sent out again - outgoingPacket.TickCount = 0; - // Bump up the resend count on this packet Interlocked.Increment(ref outgoingPacket.ResendCount); //Interlocked.Increment(ref Stats.ResentPackets); diff --git a/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs b/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs index 3e2e81c..e43f7cf 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs @@ -123,6 +123,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP { if (expiredPackets == null) expiredPackets = new List(); + + // The TickCount will be set to the current time when the packet + // is actually sent out again + packet.TickCount = 0; + expiredPackets.Add(packet); } } -- cgit v1.1 From 8a336c6860d66b9fbba6922c32e7a57fd355c57e Mon Sep 17 00:00:00 2001 From: Melanie Date: Thu, 22 Oct 2009 02:28:53 +0100 Subject: Add MaxPoolThreads in startup to limit the size of the thread pool used for FireAndForget. This lets us limit concurrency to make OpenSim play nice --- OpenSim/Region/Application/OpenSim.cs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index 143dd2a..42e2a1e 100644 --- a/OpenSim/Region/Application/OpenSim.cs +++ b/OpenSim/Region/Application/OpenSim.cs @@ -67,6 +67,8 @@ namespace OpenSim IConfig startupConfig = m_config.Source.Configs["Startup"]; + Util.SetMaxThreads(startupConfig.GetInt("MaxPoolThreads", 30)); + if (startupConfig != null) { m_startupCommandsFile = startupConfig.GetString("startup_console_commands_file", "startup_commands.txt"); -- cgit v1.1 From 8ce4fd7234bd460652f6159a3b7a21d2bebee05d Mon Sep 17 00:00:00 2001 From: Melanie Date: Thu, 22 Oct 2009 04:02:26 +0100 Subject: Reduce the default pool threads to 15 (from 30) and the minimum from 5 to 2 --- OpenSim/Region/Application/OpenSim.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index 42e2a1e..c9cec75 100644 --- a/OpenSim/Region/Application/OpenSim.cs +++ b/OpenSim/Region/Application/OpenSim.cs @@ -67,7 +67,7 @@ namespace OpenSim IConfig startupConfig = m_config.Source.Configs["Startup"]; - Util.SetMaxThreads(startupConfig.GetInt("MaxPoolThreads", 30)); + Util.SetMaxThreads(startupConfig.GetInt("MaxPoolThreads", 15)); if (startupConfig != null) { -- cgit v1.1 From 624af66c35cdd203b6210a1932c737cb21e2b05d Mon Sep 17 00:00:00 2001 From: Melanie Date: Thu, 22 Oct 2009 05:42:34 +0100 Subject: Make the LSL scripting delays take full effect. To tune, tweat the ScriptDelayFactor in config --- .../Shared/Api/Implementation/LSL_Api.cs | 105 ++++++++++----------- 1 file changed, 49 insertions(+), 56 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index a94b4e4..6e17639 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -133,13 +133,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return lease; } - protected virtual void ConditionalScriptSleep(int delay) - { - // Uncomment to get SL compatibility! - // - // ScriptSleep(delay); - } - protected virtual void ScriptSleep(int delay) { delay = (int)((float)delay * m_ScriptDelayFactor); @@ -1682,7 +1675,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); SetTexture(m_host, texture, face); - ConditionalScriptSleep(200); + ScriptSleep(200); } public void llSetLinkTexture(int linknumber, string texture, int face) @@ -1694,7 +1687,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api foreach (SceneObjectPart part in parts) SetTexture(part, texture, face); - ConditionalScriptSleep(200); + ScriptSleep(200); } protected void SetTexture(SceneObjectPart part, string texture, int face) @@ -1739,7 +1732,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); ScaleTexture(m_host, u, v, face); - ConditionalScriptSleep(200); + ScriptSleep(200); } protected void ScaleTexture(SceneObjectPart part, double u, double v, int face) @@ -1775,7 +1768,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); OffsetTexture(m_host, u, v, face); - ConditionalScriptSleep(200); + ScriptSleep(200); } protected void OffsetTexture(SceneObjectPart part, double u, double v, int face) @@ -1811,7 +1804,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); RotateTexture(m_host, rotation, face); - ConditionalScriptSleep(200); + ScriptSleep(200); } protected void RotateTexture(SceneObjectPart part, double rotation, int face) @@ -2283,7 +2276,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); m_host.PreloadSound(sound); - ConditionalScriptSleep(1000); + ScriptSleep(1000); } /// @@ -2575,28 +2568,28 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); Deprecated("llMakeExplosion"); - ConditionalScriptSleep(100); + ScriptSleep(100); } public void llMakeFountain(int particles, double scale, double vel, double lifetime, double arc, int bounce, string texture, LSL_Vector offset, double bounce_offset) { m_host.AddScriptLPS(1); Deprecated("llMakeFountain"); - ConditionalScriptSleep(100); + ScriptSleep(100); } public void llMakeSmoke(int particles, double scale, double vel, double lifetime, double arc, string texture, LSL_Vector offset) { m_host.AddScriptLPS(1); Deprecated("llMakeSmoke"); - ConditionalScriptSleep(100); + ScriptSleep(100); } public void llMakeFire(int particles, double scale, double vel, double lifetime, double arc, string texture, LSL_Vector offset) { m_host.AddScriptLPS(1); Deprecated("llMakeFire"); - ConditionalScriptSleep(100); + ScriptSleep(100); } public void llRezAtRoot(string inventory, LSL_Vector pos, LSL_Vector vel, LSL_Rotation rot, int param) @@ -2655,7 +2648,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } // Variable script delay? (see (http://wiki.secondlife.com/wiki/LSL_Delay) ScriptSleep((int)((groupmass * velmag) / 10)); - ConditionalScriptSleep(100); + ScriptSleep(100); return; } } @@ -2941,7 +2934,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } emailModule.SendEmail(m_host.UUID, address, subject, message); - ConditionalScriptSleep(20000); + ScriptSleep(20000); } public void llGetNextEmail(string address, string subject) @@ -3745,7 +3738,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // destination is an object World.MoveTaskInventoryItem(destId, m_host, objId); } - ConditionalScriptSleep(3000); + ScriptSleep(3000); } public void llRemoveInventory(string name) @@ -3846,7 +3839,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api AsyncCommands. DataserverPlugin.DataserverReply(rq.ToString(), reply); - ConditionalScriptSleep(100); + ScriptSleep(100); return tid.ToString(); } @@ -3884,11 +3877,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api reply); }); - ConditionalScriptSleep(1000); + ScriptSleep(1000); return tid.ToString(); } } - ConditionalScriptSleep(1000); + ScriptSleep(1000); return String.Empty; } @@ -3916,7 +3909,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } } - ConditionalScriptSleep(5000); + ScriptSleep(5000); } public void llTextBox(string avatar, string message, int chat_channel) @@ -5376,7 +5369,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); m_host.AdjustSoundGain(volume); - ConditionalScriptSleep(100); + ScriptSleep(100); } public void llSetSoundQueueing(int queue) @@ -5459,7 +5452,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api World.TeleportClientHome(agentId, presence.ControllingClient); } } - ConditionalScriptSleep(5000); + ScriptSleep(5000); } public LSL_List llParseString2List(string str, LSL_List separators, LSL_List in_spacers) @@ -6151,7 +6144,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api land.ParcelAccessList.Add(entry); } } - ConditionalScriptSleep(100); + ScriptSleep(100); } public void llSetTouchText(string text) @@ -6248,7 +6241,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api av, m_host.Name, m_host.UUID, m_host.OwnerID, message, new UUID("00000000-0000-2222-3333-100000001000"), chat_channel, buts); - ConditionalScriptSleep(1000); + ScriptSleep(1000); } public void llVolumeDetect(int detect) @@ -6273,7 +6266,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); // Report an error as it does in SL ShoutError("Deprecated. Please use llRemoteLoadScriptPin instead."); - ConditionalScriptSleep(3000); + ScriptSleep(3000); } public void llSetRemoteScriptAccessPin(int pin) @@ -6359,14 +6352,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams("remote_data", resobj, new DetectParams[0])); } - ConditionalScriptSleep(1000); + ScriptSleep(1000); } public LSL_String llSendRemoteData(string channel, string dest, int idata, string sdata) { m_host.AddScriptLPS(1); IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface(); - ConditionalScriptSleep(3000); + ScriptSleep(3000); return (xmlrpcMod.SendRemoteData(m_localID, m_itemID, channel, dest, idata, sdata)).ToString(); } @@ -6375,7 +6368,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface(); xmlrpcMod.RemoteDataReply(channel, message_id, sdata, idata); - ConditionalScriptSleep(3000); + ScriptSleep(3000); } public void llCloseRemoteDataChannel(string channel) @@ -6383,7 +6376,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface(); xmlrpcMod.CloseXMLRPCChannel((UUID)channel); - ConditionalScriptSleep(1000); + ScriptSleep(1000); } public LSL_String llMD5String(string src, int nonce) @@ -7114,7 +7107,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); Deprecated("llXorBase64Strings"); - ConditionalScriptSleep(300); + ScriptSleep(300); return String.Empty; } @@ -7162,7 +7155,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api land.SetMusicUrl(url); - ConditionalScriptSleep(2000); + ScriptSleep(2000); } public LSL_Vector llGetRootPosition() @@ -8207,7 +8200,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api case 5: // DATA_SIM_POS if (info == null) { - ConditionalScriptSleep(1000); + ScriptSleep(1000); return UUID.Zero.ToString(); } reply = new LSL_Vector( @@ -8224,7 +8217,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api case 7: // DATA_SIM_RATING if (info == null) { - ConditionalScriptSleep(1000); + ScriptSleep(1000); return UUID.Zero.ToString(); } int access = info.Maturity; @@ -8243,7 +8236,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api reply = "OpenSim"; break; default: - ConditionalScriptSleep(1000); + ScriptSleep(1000); return UUID.Zero.ToString(); // Raise no event } UUID rq = UUID.Random(); @@ -8254,7 +8247,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api AsyncCommands. DataserverPlugin.DataserverReply(rq.ToString(), reply); - ConditionalScriptSleep(1000); + ScriptSleep(1000); return tid.ToString(); } catch(Exception) @@ -8398,7 +8391,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api dm.SendUrlToUser( new UUID(avatar_id), m_host.Name, m_host.UUID, m_host.OwnerID, false, message, url); - ConditionalScriptSleep(10000); + ScriptSleep(10000); } public void llParcelMediaCommandList(LSL_List commandList) @@ -8634,7 +8627,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api time); } } - ConditionalScriptSleep(2000); + ScriptSleep(2000); } public LSL_List llParcelMediaQuery(LSL_List aList) @@ -8672,7 +8665,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } - ConditionalScriptSleep(2000); + ScriptSleep(2000); return list; } @@ -8681,7 +8674,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); Int64 tmp = 0; Math.DivRem(Convert.ToInt64(Math.Pow(a, b)), c, out tmp); - ConditionalScriptSleep(1000); + ScriptSleep(1000); return Convert.ToInt32(tmp); } @@ -8785,7 +8778,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void llSetPrimURL(string url) { m_host.AddScriptLPS(1); - ConditionalScriptSleep(2000); + ScriptSleep(2000); } /// @@ -8796,7 +8789,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); ShoutError("llRefreshPrimURL - not yet supported"); - ConditionalScriptSleep(20000); + ScriptSleep(20000); } public LSL_String llEscapeURL(string url) @@ -8838,7 +8831,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api new Vector3((float)pos.x, (float)pos.y, (float)pos.z), new Vector3((float)lookAt.x, (float)lookAt.y, (float)lookAt.z)); } - ConditionalScriptSleep(1000); + ScriptSleep(1000); } public void llAddToLandBanList(string avatar, double hours) @@ -8857,7 +8850,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api land.ParcelAccessList.Add(entry); } } - ConditionalScriptSleep(100); + ScriptSleep(100); } public void llRemoveFromLandPassList(string avatar) @@ -8879,7 +8872,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } } - ConditionalScriptSleep(100); + ScriptSleep(100); } public void llRemoveFromLandBanList(string avatar) @@ -8901,7 +8894,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } } - ConditionalScriptSleep(100); + ScriptSleep(100); } public void llSetCameraParams(LSL_List rules) @@ -9163,7 +9156,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } } - ConditionalScriptSleep(100); + ScriptSleep(100); } public void llResetLandPassList() @@ -9180,7 +9173,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } } - ConditionalScriptSleep(100); + ScriptSleep(100); } public LSL_Integer llGetParcelPrimCount(LSL_Vector pos, int category, int sim_wide) @@ -9259,7 +9252,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api ret.Add(detectedParams.Value); } } - ConditionalScriptSleep(2000); + ScriptSleep(2000); return ret; } @@ -9517,7 +9510,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api AsyncCommands. DataserverPlugin.DataserverReply(assetID.ToString(), NotecardCache.GetLines(assetID).ToString()); - ConditionalScriptSleep(100); + ScriptSleep(100); return tid.ToString(); } @@ -9539,7 +9532,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api NotecardCache.GetLines(id).ToString()); }); - ConditionalScriptSleep(100); + ScriptSleep(100); return tid.ToString(); } @@ -9578,7 +9571,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { AsyncCommands.DataserverPlugin.DataserverReply(assetID.ToString(), NotecardCache.GetLine(assetID, line, m_notecardLineReadCharsMax)); - ConditionalScriptSleep(100); + ScriptSleep(100); return tid.ToString(); } @@ -9599,7 +9592,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api NotecardCache.GetLine(id, line, m_notecardLineReadCharsMax)); }); - ConditionalScriptSleep(100); + ScriptSleep(100); return tid.ToString(); } } -- cgit v1.1 From 32ccd5bb40447ea4d96f1181cf73edff3645a55a Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Wed, 21 Oct 2009 23:03:18 -0700 Subject: * Changed the misc. methods calling ThreadPool.UnsafeQueueUserWorkItem() to Util.FireAndForget() * Changed Util.FireAndForget() to use any of five different methods set with async_call_method in the [Startup] section of OpenSim.ini. Look at the example config for possible values --- OpenSim/Region/Application/OpenSim.cs | 9 ++++++++- OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs | 6 +++--- OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs | 8 ++------ OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs | 2 +- 4 files changed, 14 insertions(+), 11 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index 143dd2a..5be1816 100644 --- a/OpenSim/Region/Application/OpenSim.cs +++ b/OpenSim/Region/Application/OpenSim.cs @@ -90,10 +90,17 @@ namespace OpenSim appender.File = fileName; appender.ActivateOptions(); } - m_log.InfoFormat("[LOGGING] Logging started to file {0}", appender.File); + m_log.InfoFormat("[LOGGING]: Logging started to file {0}", appender.File); } } + + string asyncCallMethodStr = startupConfig.GetString("async_call_method", String.Empty); + FireAndForgetMethod asyncCallMethod; + if (!String.IsNullOrEmpty(asyncCallMethodStr) && Utils.EnumTryParse(asyncCallMethodStr, out asyncCallMethod)) + Util.FireAndForgetMethod = asyncCallMethod; } + + m_log.Info("[OPENSIM MAIN]: Using async_call_method " + Util.FireAndForgetMethod); } /// diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 432fee7..0ba76ec 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -791,7 +791,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// heightmap public virtual void SendLayerData(float[] map) { - ThreadPool.UnsafeQueueUserWorkItem(DoSendLayerData, map); + Util.FireAndForget(DoSendLayerData, map); } /// @@ -931,7 +931,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// 16x16 array of wind speeds public virtual void SendWindData(Vector2[] windSpeeds) { - ThreadPool.UnsafeQueueUserWorkItem(new WaitCallback(DoSendWindData), (object)windSpeeds); + Util.FireAndForget(DoSendWindData, windSpeeds); } /// @@ -940,7 +940,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// 16x16 array of cloud densities public virtual void SendCloudData(float[] cloudDensity) { - ThreadPool.UnsafeQueueUserWorkItem(new WaitCallback(DoSendCloudData), (object)cloudDensity); + Util.FireAndForget(DoSendCloudData, cloudDensity); } /// diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs index cbdca16..c6af806 100644 --- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs @@ -302,12 +302,8 @@ namespace Flotsam.RegionModules.AssetCache } - ThreadPool.UnsafeQueueUserWorkItem( - delegate - { - WriteFileCache(filename, asset); - }, null - ); + Util.FireAndForget( + delegate { WriteFileCache(filename, asset); }); } } catch (Exception e) diff --git a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs index 1260584..4e40084 100644 --- a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs +++ b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs @@ -1095,7 +1095,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap // The reason is so we don't cause the thread to freeze waiting // for the 1 second it costs to start a thread manually. if (!threadrunning) - ThreadPool.UnsafeQueueUserWorkItem(this.StartThread, null); + Util.FireAndForget(this.StartThread); lock (m_rootAgents) { -- cgit v1.1