From d44b50ee462978b4899c0b142f6ecbfb553f06b6 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Thu, 15 Oct 2009 15:25:02 -0700 Subject: [PATCH] * 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) --- .../ClientStack/LindenUDP/LLClientView.cs | 229 +++++++++++++++++- .../CoreModules/Avatar/Chat/ChatModule.cs | 11 +- .../World/Estate/EstateManagementModule.cs | 2 +- .../World/Land/LandManagementModule.cs | 6 +- OpenSim/Region/Framework/Scenes/Scene.cs | 31 +-- OpenSim/Region/Framework/Scenes/SceneGraph.cs | 17 -- .../Framework/Scenes/SceneObjectPart.cs | 12 +- .../Region/Framework/Scenes/ScenePresence.cs | 11 +- .../Scripting/Minimodule/MRMModule.cs | 4 +- 9 files changed, 255 insertions(+), 68 deletions(-) diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 8487adc7f5..82a2cdd037 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 66a9b5a540..cd59bdb613 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 4896edfdf6..3bb162e469 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 d2b5cb19e5..332d3ce59e 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 d3d397dde2..d13d4fb8ec 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -1193,15 +1193,6 @@ namespace OpenSim.Region.Framework.Scenes m_eventManager.TriggerOnFrame(); } - /// - /// 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 9cd2247b3a..04397adcec 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 801a7db3a5..377cb6e987 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 2a06f9eb9a..387db4456b 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 ce50f9e34d..4521f8ef6a 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.");