diff options
Diffstat (limited to 'OpenSim/Region')
23 files changed, 798 insertions, 514 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 05a2a63..43c3c7c 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs | |||
@@ -51,6 +51,44 @@ using Nini.Config; | |||
51 | 51 | ||
52 | namespace OpenSim.Region.ClientStack.LindenUDP | 52 | namespace OpenSim.Region.ClientStack.LindenUDP |
53 | { | 53 | { |
54 | #region Enums | ||
55 | |||
56 | /// <summary> | ||
57 | /// Specifies the fields that have been changed when sending a prim or | ||
58 | /// avatar update | ||
59 | /// </summary> | ||
60 | [Flags] | ||
61 | public enum PrimUpdateFlags : uint | ||
62 | { | ||
63 | None = 0, | ||
64 | AttachmentPoint = 1 << 0, | ||
65 | Material = 1 << 1, | ||
66 | ClickAction = 1 << 2, | ||
67 | Scale = 1 << 3, | ||
68 | ParentID = 1 << 4, | ||
69 | PrimFlags = 1 << 5, | ||
70 | PrimData = 1 << 6, | ||
71 | MediaURL = 1 << 7, | ||
72 | ScratchPad = 1 << 8, | ||
73 | Textures = 1 << 9, | ||
74 | TextureAnim = 1 << 10, | ||
75 | NameValue = 1 << 11, | ||
76 | Position = 1 << 12, | ||
77 | Rotation = 1 << 13, | ||
78 | Velocity = 1 << 14, | ||
79 | Acceleration = 1 << 15, | ||
80 | AngularVelocity = 1 << 16, | ||
81 | CollisionPlane = 1 << 17, | ||
82 | Text = 1 << 18, | ||
83 | Particles = 1 << 19, | ||
84 | ExtraData = 1 << 20, | ||
85 | Sound = 1 << 21, | ||
86 | Joint = 1 << 22, | ||
87 | FullUpdate = UInt32.MaxValue | ||
88 | } | ||
89 | |||
90 | #endregion Enums | ||
91 | |||
54 | public delegate bool PacketMethod(IClientAPI simClient, Packet packet); | 92 | public delegate bool PacketMethod(IClientAPI simClient, Packet packet); |
55 | 93 | ||
56 | /// <summary> | 94 | /// <summary> |
@@ -282,12 +320,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
282 | private readonly IGroupsModule m_GroupsModule; | 320 | private readonly IGroupsModule m_GroupsModule; |
283 | 321 | ||
284 | private int m_cachedTextureSerial; | 322 | private int m_cachedTextureSerial; |
285 | private Timer m_avatarTerseUpdateTimer; | 323 | private PriorityQueue<double, ImprovedTerseObjectUpdatePacket.ObjectDataBlock> m_avatarTerseUpdates = |
286 | private List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> m_avatarTerseUpdates = new List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>(); | 324 | new PriorityQueue<double, ImprovedTerseObjectUpdatePacket.ObjectDataBlock>(); |
287 | private Timer m_primTerseUpdateTimer; | 325 | private PriorityQueue<double, ImprovedTerseObjectUpdatePacket.ObjectDataBlock> m_primTerseUpdates = |
288 | private List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> m_primTerseUpdates = new List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>(); | 326 | new PriorityQueue<double, ImprovedTerseObjectUpdatePacket.ObjectDataBlock>(); |
289 | private Timer m_primFullUpdateTimer; | 327 | private PriorityQueue<double, ObjectUpdatePacket.ObjectDataBlock> m_primFullUpdates = |
290 | private List<ObjectUpdatePacket.ObjectDataBlock> m_primFullUpdates = new List<ObjectUpdatePacket.ObjectDataBlock>(); | 328 | new PriorityQueue<double, ObjectUpdatePacket.ObjectDataBlock>(); |
291 | private int m_moneyBalance; | 329 | private int m_moneyBalance; |
292 | private int m_animationSequenceNumber = 1; | 330 | private int m_animationSequenceNumber = 1; |
293 | private bool m_SendLogoutPacketWhenClosing = true; | 331 | private bool m_SendLogoutPacketWhenClosing = true; |
@@ -309,13 +347,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
309 | protected Dictionary<UUID,ulong> m_groupPowers = new Dictionary<UUID, ulong>(); | 347 | protected Dictionary<UUID,ulong> m_groupPowers = new Dictionary<UUID, ulong>(); |
310 | protected int m_terrainCheckerCount; | 348 | protected int m_terrainCheckerCount; |
311 | 349 | ||
312 | // LL uses these limits, apparently. Compressed terse would be 23, but we don't have that yet | 350 | // These numbers are guesses at a decent tradeoff between responsiveness |
313 | protected int m_primTerseUpdatesPerPacket = 10; | 351 | // of the interest list and throughput. Lower is more responsive, higher |
314 | protected int m_primFullUpdatesPerPacket = 14; | 352 | // is better throughput |
315 | protected int m_primTerseUpdateRate = 10; | 353 | protected int m_primTerseUpdatesPerPacket = 25; |
316 | protected int m_primFullUpdateRate = 14; | 354 | protected int m_primFullUpdatesPerPacket = 100; |
317 | protected int m_avatarTerseUpdateRate = 50; | 355 | protected int m_avatarTerseUpdatesPerPacket = 10; |
318 | protected int m_avatarTerseUpdatesPerPacket = 5; | ||
319 | /// <summary>Number of texture packets to put on the queue each time the | 356 | /// <summary>Number of texture packets to put on the queue each time the |
320 | /// OnQueueEmpty event is triggered for the texture category</summary> | 357 | /// OnQueueEmpty event is triggered for the texture category</summary> |
321 | protected int m_textureSendLimit = 20; | 358 | protected int m_textureSendLimit = 20; |
@@ -438,25 +475,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
438 | // Remove ourselves from the scene | 475 | // Remove ourselves from the scene |
439 | m_scene.RemoveClient(AgentId); | 476 | m_scene.RemoveClient(AgentId); |
440 | 477 | ||
441 | // Shut down timers. Thread Context of this method is murky. Lock all timers | ||
442 | if (m_avatarTerseUpdateTimer.Enabled) | ||
443 | lock (m_avatarTerseUpdateTimer) | ||
444 | m_avatarTerseUpdateTimer.Stop(); | ||
445 | if (m_primTerseUpdateTimer.Enabled) | ||
446 | lock (m_primTerseUpdateTimer) | ||
447 | m_primTerseUpdateTimer.Stop(); | ||
448 | if (m_primFullUpdateTimer.Enabled) | ||
449 | lock (m_primFullUpdateTimer) | ||
450 | m_primFullUpdateTimer.Stop(); | ||
451 | |||
452 | // We can't reach into other scenes and close the connection | 478 | // We can't reach into other scenes and close the connection |
453 | // We need to do this over grid communications | 479 | // We need to do this over grid communications |
454 | //m_scene.CloseAllAgents(CircuitCode); | 480 | //m_scene.CloseAllAgents(CircuitCode); |
455 | 481 | ||
456 | m_avatarTerseUpdateTimer.Dispose(); | ||
457 | m_primTerseUpdateTimer.Dispose(); | ||
458 | m_primFullUpdateTimer.Dispose(); | ||
459 | |||
460 | // Disable UDP handling for this client | 482 | // Disable UDP handling for this client |
461 | m_udpClient.Shutdown(); | 483 | m_udpClient.Shutdown(); |
462 | 484 | ||
@@ -483,18 +505,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
483 | 505 | ||
484 | public void Stop() | 506 | public void Stop() |
485 | { | 507 | { |
486 | // Shut down timers. Thread Context is Murky, lock all timers! | ||
487 | if (m_avatarTerseUpdateTimer.Enabled) | ||
488 | lock (m_avatarTerseUpdateTimer) | ||
489 | m_avatarTerseUpdateTimer.Stop(); | ||
490 | |||
491 | if (m_primTerseUpdateTimer.Enabled) | ||
492 | lock (m_primTerseUpdateTimer) | ||
493 | m_primTerseUpdateTimer.Stop(); | ||
494 | 508 | ||
495 | if (m_primFullUpdateTimer.Enabled) | ||
496 | lock (m_primFullUpdateTimer) | ||
497 | m_primFullUpdateTimer.Stop(); | ||
498 | } | 509 | } |
499 | 510 | ||
500 | #endregion Client Methods | 511 | #endregion Client Methods |
@@ -590,18 +601,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
590 | 601 | ||
591 | public virtual void Start() | 602 | public virtual void Start() |
592 | { | 603 | { |
593 | m_avatarTerseUpdateTimer = new Timer(m_avatarTerseUpdateRate); | ||
594 | m_avatarTerseUpdateTimer.Elapsed += new ElapsedEventHandler(ProcessAvatarTerseUpdates); | ||
595 | m_avatarTerseUpdateTimer.AutoReset = false; | ||
596 | |||
597 | m_primTerseUpdateTimer = new Timer(m_primTerseUpdateRate); | ||
598 | m_primTerseUpdateTimer.Elapsed += new ElapsedEventHandler(ProcessPrimTerseUpdates); | ||
599 | m_primTerseUpdateTimer.AutoReset = false; | ||
600 | |||
601 | m_primFullUpdateTimer = new Timer(m_primFullUpdateRate); | ||
602 | m_primFullUpdateTimer.Elapsed += new ElapsedEventHandler(ProcessPrimFullUpdates); | ||
603 | m_primFullUpdateTimer.AutoReset = false; | ||
604 | |||
605 | m_scene.AddNewClient(this); | 604 | m_scene.AddNewClient(this); |
606 | 605 | ||
607 | RefreshGroupMembership(); | 606 | RefreshGroupMembership(); |
@@ -3127,7 +3126,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3127 | 3126 | ||
3128 | avp.Sender.IsTrial = false; | 3127 | avp.Sender.IsTrial = false; |
3129 | avp.Sender.ID = agentID; | 3128 | avp.Sender.ID = agentID; |
3130 | OutPacket(avp, ThrottleOutPacketType.State); | 3129 | OutPacket(avp, ThrottleOutPacketType.Task); |
3131 | } | 3130 | } |
3132 | 3131 | ||
3133 | public void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs) | 3132 | public void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs) |
@@ -3159,33 +3158,221 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3159 | 3158 | ||
3160 | #endregion | 3159 | #endregion |
3161 | 3160 | ||
3161 | #region Prim/Avatar Updates | ||
3162 | |||
3163 | /*void SendObjectUpdate(SceneObjectPart obj, PrimFlags creatorFlags, PrimUpdateFlags updateFlags) | ||
3164 | { | ||
3165 | bool canUseCompressed, canUseImproved; | ||
3166 | UpdateFlagsToPacketType(creatorFlags, updateFlags, out canUseCompressed, out canUseImproved); | ||
3167 | |||
3168 | if (!canUseImproved && !canUseCompressed) | ||
3169 | SendFullObjectUpdate(obj, creatorFlags, updateFlags); | ||
3170 | else if (!canUseImproved) | ||
3171 | SendObjectUpdateCompressed(obj, creatorFlags, updateFlags); | ||
3172 | else | ||
3173 | SendImprovedTerseObjectUpdate(obj, creatorFlags, updateFlags); | ||
3174 | } | ||
3175 | |||
3176 | void SendFullObjectUpdate(SceneObjectPart obj, PrimFlags creatorFlags, PrimUpdateFlags updateFlags) | ||
3177 | { | ||
3178 | IClientAPI owner; | ||
3179 | if (m_scene.ClientManager.TryGetValue(obj.OwnerID, out owner) && owner is LLClientView) | ||
3180 | { | ||
3181 | LLClientView llOwner = (LLClientView)owner; | ||
3182 | |||
3183 | // Send an update out to the owner | ||
3184 | ObjectUpdatePacket updateToOwner = new ObjectUpdatePacket(); | ||
3185 | updateToOwner.RegionData.RegionHandle = obj.RegionHandle; | ||
3186 | //updateToOwner.RegionData.TimeDilation = (ushort)(timeDilation * (float)UInt16.MaxValue); | ||
3187 | updateToOwner.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1]; | ||
3188 | updateToOwner.ObjectData[0] = BuildUpdateBlock(obj, obj.Flags | creatorFlags | PrimFlags.ObjectYouOwner, 0); | ||
3189 | |||
3190 | m_udpServer.SendPacket(llOwner.UDPClient, updateToOwner, ThrottleOutPacketType.State, true); | ||
3191 | } | ||
3192 | |||
3193 | // Send an update out to everyone else | ||
3194 | ObjectUpdatePacket updateToOthers = new ObjectUpdatePacket(); | ||
3195 | updateToOthers.RegionData.RegionHandle = obj.RegionHandle; | ||
3196 | //updateToOthers.RegionData.TimeDilation = (ushort)(timeDilation * (float)UInt16.MaxValue); | ||
3197 | updateToOthers.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1]; | ||
3198 | updateToOthers.ObjectData[0] = BuildUpdateBlock(obj, obj.Flags, 0); | ||
3199 | |||
3200 | m_scene.ClientManager.ForEach( | ||
3201 | delegate(IClientAPI client) | ||
3202 | { | ||
3203 | if (client.AgentId != obj.OwnerID && client is LLClientView) | ||
3204 | { | ||
3205 | LLClientView llClient = (LLClientView)client; | ||
3206 | m_udpServer.SendPacket(llClient.UDPClient, updateToOthers, ThrottleOutPacketType.State, true); | ||
3207 | } | ||
3208 | } | ||
3209 | ); | ||
3210 | } | ||
3211 | |||
3212 | void SendObjectUpdateCompressed(SceneObjectPart obj, PrimFlags creatorFlags, PrimUpdateFlags updateFlags) | ||
3213 | { | ||
3214 | } | ||
3215 | |||
3216 | void SendImprovedTerseObjectUpdate(SceneObjectPart obj, PrimFlags creatorFlags, PrimUpdateFlags updateFlags) | ||
3217 | { | ||
3218 | } | ||
3219 | |||
3220 | void UpdateFlagsToPacketType(PrimFlags creatorFlags, PrimUpdateFlags updateFlags, out bool canUseCompressed, out bool canUseImproved) | ||
3221 | { | ||
3222 | canUseCompressed = true; | ||
3223 | canUseImproved = true; | ||
3224 | |||
3225 | if ((updateFlags & PrimUpdateFlags.FullUpdate) == PrimUpdateFlags.FullUpdate || creatorFlags != PrimFlags.None) | ||
3226 | { | ||
3227 | canUseCompressed = false; | ||
3228 | canUseImproved = false; | ||
3229 | } | ||
3230 | else | ||
3231 | { | ||
3232 | if ((updateFlags & PrimUpdateFlags.Velocity) != 0 || | ||
3233 | (updateFlags & PrimUpdateFlags.Acceleration) != 0 || | ||
3234 | (updateFlags & PrimUpdateFlags.CollisionPlane) != 0 || | ||
3235 | (updateFlags & PrimUpdateFlags.Joint) != 0) | ||
3236 | { | ||
3237 | canUseCompressed = false; | ||
3238 | } | ||
3239 | |||
3240 | if ((updateFlags & PrimUpdateFlags.PrimFlags) != 0 || | ||
3241 | (updateFlags & PrimUpdateFlags.ParentID) != 0 || | ||
3242 | (updateFlags & PrimUpdateFlags.Scale) != 0 || | ||
3243 | (updateFlags & PrimUpdateFlags.PrimData) != 0 || | ||
3244 | (updateFlags & PrimUpdateFlags.Text) != 0 || | ||
3245 | (updateFlags & PrimUpdateFlags.NameValue) != 0 || | ||
3246 | (updateFlags & PrimUpdateFlags.ExtraData) != 0 || | ||
3247 | (updateFlags & PrimUpdateFlags.TextureAnim) != 0 || | ||
3248 | (updateFlags & PrimUpdateFlags.Sound) != 0 || | ||
3249 | (updateFlags & PrimUpdateFlags.Particles) != 0 || | ||
3250 | (updateFlags & PrimUpdateFlags.Material) != 0 || | ||
3251 | (updateFlags & PrimUpdateFlags.ClickAction) != 0 || | ||
3252 | (updateFlags & PrimUpdateFlags.MediaURL) != 0 || | ||
3253 | (updateFlags & PrimUpdateFlags.Joint) != 0) | ||
3254 | { | ||
3255 | canUseImproved = false; | ||
3256 | } | ||
3257 | } | ||
3258 | } | ||
3259 | |||
3260 | static ObjectUpdatePacket.ObjectDataBlock BuildUpdateBlockFromPrim(SceneObjectPart prim, UUID assetID, PrimFlags flags, uint crc) | ||
3261 | { | ||
3262 | byte[] objectData = new byte[60]; | ||
3263 | prim.OffsetPosition.ToBytes(objectData, 0); | ||
3264 | prim.Velocity.ToBytes(objectData, 12); | ||
3265 | prim.Acceleration.ToBytes(objectData, 24); | ||
3266 | prim.RotationOffset.ToBytes(objectData, 36); | ||
3267 | prim.AngularVelocity.ToBytes(objectData, 48); | ||
3268 | |||
3269 | ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); | ||
3270 | update.ClickAction = (byte)prim.ClickAction; | ||
3271 | update.CRC = crc; | ||
3272 | update.ExtraParams = prim.Shape.ExtraParams ?? Utils.EmptyBytes; | ||
3273 | update.Flags = (byte)flags; | ||
3274 | update.FullID = prim.UUID; | ||
3275 | update.ID = prim.LocalId; | ||
3276 | //update.JointAxisOrAnchor = Vector3.Zero; // These are deprecated | ||
3277 | //update.JointPivot = Vector3.Zero; | ||
3278 | //update.JointType = 0; | ||
3279 | update.Material = prim.Material; | ||
3280 | update.MediaURL = Utils.EmptyBytes; // FIXME: Support this in OpenSim | ||
3281 | if (prim.IsAttachment) | ||
3282 | update.NameValue = Util.StringToBytes256("AttachItemID STRING RW SV " + assetID); | ||
3283 | else | ||
3284 | update.NameValue = Utils.EmptyBytes; | ||
3285 | update.ObjectData = objectData; | ||
3286 | update.ParentID = prim.ParentID; | ||
3287 | update.PathBegin = prim.Shape.PathBegin; | ||
3288 | update.PathCurve = prim.Shape.PathCurve; | ||
3289 | update.PathEnd = prim.Shape.PathEnd; | ||
3290 | update.PathRadiusOffset = prim.Shape.PathRadiusOffset; | ||
3291 | update.PathRevolutions = prim.Shape.PathRevolutions; | ||
3292 | update.PathScaleX = prim.Shape.PathScaleX; | ||
3293 | update.PathScaleY = prim.Shape.PathScaleY; | ||
3294 | update.PathShearX = prim.Shape.PathShearX; | ||
3295 | update.PathShearY = prim.Shape.PathShearY; | ||
3296 | update.PathSkew = prim.Shape.PathSkew; | ||
3297 | update.PathTaperX = prim.Shape.PathTaperX; | ||
3298 | update.PathTaperY = prim.Shape.PathTaperY; | ||
3299 | update.PathTwist = prim.Shape.PathTwist; | ||
3300 | update.PathTwistBegin = prim.Shape.PathTwistBegin; | ||
3301 | update.PCode = prim.Shape.PCode; | ||
3302 | update.ProfileBegin = prim.Shape.ProfileBegin; | ||
3303 | update.ProfileCurve = prim.Shape.ProfileCurve; | ||
3304 | update.ProfileEnd = prim.Shape.ProfileEnd; | ||
3305 | update.ProfileHollow = prim.Shape.ProfileHollow; | ||
3306 | update.PSBlock = prim.ParticleSystem ?? Utils.EmptyBytes; | ||
3307 | update.TextColor = new Color4(prim.Color).GetBytes(true); | ||
3308 | update.TextureAnim = prim.TextureAnimation ?? Utils.EmptyBytes; | ||
3309 | update.TextureEntry = prim.Shape.TextureEntry ?? Utils.EmptyBytes; | ||
3310 | update.Scale = prim.Scale; | ||
3311 | update.State = prim.Shape.State; | ||
3312 | update.Text = Util.StringToBytes256(prim.Text); | ||
3313 | update.UpdateFlags = (uint)flags; | ||
3314 | |||
3315 | if (prim.Sound != UUID.Zero) | ||
3316 | { | ||
3317 | update.Sound = prim.Sound; | ||
3318 | update.OwnerID = prim.OwnerID; | ||
3319 | update.Gain = (float)prim.SoundGain; | ||
3320 | update.Radius = (float)prim.SoundRadius; | ||
3321 | } | ||
3322 | |||
3323 | switch ((PCode)prim.Shape.PCode) | ||
3324 | { | ||
3325 | case PCode.Grass: | ||
3326 | case PCode.Tree: | ||
3327 | case PCode.NewTree: | ||
3328 | update.Data = new byte[] { prim.Shape.State }; | ||
3329 | break; | ||
3330 | default: | ||
3331 | // TODO: Support ScratchPad | ||
3332 | //if (prim.ScratchPad != null) | ||
3333 | //{ | ||
3334 | // update.Data = new byte[prim.ScratchPad.Length]; | ||
3335 | // Buffer.BlockCopy(prim.ScratchPad, 0, update.Data, 0, update.Data.Length); | ||
3336 | //} | ||
3337 | //else | ||
3338 | //{ | ||
3339 | // update.Data = Utils.EmptyBytes; | ||
3340 | //} | ||
3341 | update.Data = Utils.EmptyBytes; | ||
3342 | break; | ||
3343 | } | ||
3344 | |||
3345 | return update; | ||
3346 | }*/ | ||
3347 | |||
3348 | #endregion Prim/Avatar Updates | ||
3349 | |||
3162 | #region Avatar Packet/data sending Methods | 3350 | #region Avatar Packet/data sending Methods |
3163 | 3351 | ||
3164 | /// <summary> | 3352 | /// <summary> |
3165 | /// send a objectupdate packet with information about the clients avatar | 3353 | /// send a objectupdate packet with information about the clients avatar |
3166 | /// </summary> | 3354 | /// </summary> |
3167 | public void SendAvatarData(ulong regionHandle, string firstName, string lastName, string grouptitle, UUID avatarID, | 3355 | public void SendAvatarData(SendAvatarData data) |
3168 | uint avatarLocalID, Vector3 Pos, byte[] textureEntry, uint parentID, Quaternion rotation) | ||
3169 | { | 3356 | { |
3170 | ObjectUpdatePacket objupdate = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate); | 3357 | ObjectUpdatePacket objupdate = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate); |
3171 | // TODO: don't create new blocks if recycling an old packet | 3358 | // TODO: don't create new blocks if recycling an old packet |
3172 | objupdate.RegionData.RegionHandle = regionHandle; | 3359 | objupdate.RegionData.RegionHandle = data.regionHandle; |
3173 | objupdate.RegionData.TimeDilation = ushort.MaxValue; | 3360 | objupdate.RegionData.TimeDilation = ushort.MaxValue; |
3174 | objupdate.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1]; | 3361 | objupdate.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1]; |
3175 | objupdate.ObjectData[0] = CreateDefaultAvatarPacket(textureEntry); | 3362 | objupdate.ObjectData[0] = CreateDefaultAvatarPacket(data.textureEntry); |
3176 | 3363 | ||
3177 | //give this avatar object a local id and assign the user a name | 3364 | //give this avatar object a local id and assign the user a name |
3178 | objupdate.ObjectData[0].ID = avatarLocalID; | 3365 | objupdate.ObjectData[0].ID = data.avatarLocalID; |
3179 | objupdate.ObjectData[0].FullID = avatarID; | 3366 | objupdate.ObjectData[0].FullID = data.avatarID; |
3180 | objupdate.ObjectData[0].ParentID = parentID; | 3367 | objupdate.ObjectData[0].ParentID = data.parentID; |
3181 | objupdate.ObjectData[0].NameValue = | 3368 | objupdate.ObjectData[0].NameValue = |
3182 | Utils.StringToBytes("FirstName STRING RW SV " + firstName + "\nLastName STRING RW SV " + lastName + "\nTitle STRING RW SV " + grouptitle); | 3369 | Utils.StringToBytes("FirstName STRING RW SV " + data.firstName + "\nLastName STRING RW SV " + data.lastName + "\nTitle STRING RW SV " + data.grouptitle); |
3183 | 3370 | ||
3184 | Vector3 pos2 = new Vector3(Pos.X, Pos.Y, Pos.Z); | 3371 | Vector3 pos2 = new Vector3(data.Pos.X, data.Pos.Y, data.Pos.Z); |
3185 | byte[] pb = pos2.GetBytes(); | 3372 | byte[] pb = pos2.GetBytes(); |
3186 | Array.Copy(pb, 0, objupdate.ObjectData[0].ObjectData, 16, pb.Length); | 3373 | Array.Copy(pb, 0, objupdate.ObjectData[0].ObjectData, 16, pb.Length); |
3187 | 3374 | ||
3188 | byte[] rot = rotation.GetBytes(); | 3375 | byte[] rot = data.rotation.GetBytes(); |
3189 | Array.Copy(rot, 0, objupdate.ObjectData[0].ObjectData, 52, rot.Length); | 3376 | Array.Copy(rot, 0, objupdate.ObjectData[0].ObjectData, 52, rot.Length); |
3190 | 3377 | ||
3191 | objupdate.Header.Zerocoded = true; | 3378 | objupdate.Header.Zerocoded = true; |
@@ -3196,38 +3383,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3196 | /// Send a terse positional/rotation/velocity update about an avatar | 3383 | /// Send a terse positional/rotation/velocity update about an avatar |
3197 | /// to the client. This avatar can be that of the client itself. | 3384 | /// to the client. This avatar can be that of the client itself. |
3198 | /// </summary> | 3385 | /// </summary> |
3199 | public virtual void SendAvatarTerseUpdate(ulong regionHandle, | 3386 | public virtual void SendAvatarTerseUpdate(SendAvatarTerseData data) |
3200 | ushort timeDilation, uint localID, Vector3 position, | ||
3201 | Vector3 velocity, Quaternion rotation, UUID agentid) | ||
3202 | { | 3387 | { |
3388 | if (data.priority == double.NaN) | ||
3389 | { | ||
3390 | m_log.Error("[LLClientView] SendAvatarTerseUpdate received a NaN priority, dropping update"); | ||
3391 | return; | ||
3392 | } | ||
3393 | |||
3394 | Quaternion rotation = data.rotation; | ||
3395 | |||
3203 | if (rotation.X == rotation.Y && | 3396 | if (rotation.X == rotation.Y && |
3204 | rotation.Y == rotation.Z && | 3397 | rotation.Y == rotation.Z && |
3205 | rotation.Z == rotation.W && rotation.W == 0) | 3398 | rotation.Z == rotation.W && rotation.W == 0) |
3206 | rotation = Quaternion.Identity; | 3399 | rotation = Quaternion.Identity; |
3207 | 3400 | ||
3208 | ImprovedTerseObjectUpdatePacket.ObjectDataBlock terseBlock = | 3401 | ImprovedTerseObjectUpdatePacket.ObjectDataBlock terseBlock = |
3209 | CreateAvatarImprovedBlock(localID, position, velocity,rotation); | 3402 | CreateAvatarImprovedBlock(data.localID, data.position, data.velocity, rotation); |
3210 | 3403 | ||
3211 | lock (m_avatarTerseUpdates) | 3404 | lock (m_avatarTerseUpdates.SyncRoot) |
3212 | { | 3405 | m_avatarTerseUpdates.Enqueue(data.priority, terseBlock, data.localID); |
3213 | m_avatarTerseUpdates.Add(terseBlock); | ||
3214 | |||
3215 | // If packet is full or own movement packet, send it. | ||
3216 | if (m_avatarTerseUpdates.Count >= m_avatarTerseUpdatesPerPacket) | ||
3217 | { | ||
3218 | ProcessAvatarTerseUpdates(this, null); | ||
3219 | } | ||
3220 | else if (m_avatarTerseUpdates.Count == 1) | ||
3221 | { | ||
3222 | lock (m_avatarTerseUpdateTimer) | ||
3223 | m_avatarTerseUpdateTimer.Start(); | ||
3224 | } | ||
3225 | } | ||
3226 | } | 3406 | } |
3227 | 3407 | ||
3228 | private void ProcessAvatarTerseUpdates(object sender, ElapsedEventArgs e) | 3408 | private void ProcessAvatarTerseUpdates() |
3229 | { | 3409 | { |
3230 | lock (m_avatarTerseUpdates) | 3410 | lock (m_avatarTerseUpdates.SyncRoot) |
3231 | { | 3411 | { |
3232 | ImprovedTerseObjectUpdatePacket terse = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); | 3412 | ImprovedTerseObjectUpdatePacket terse = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); |
3233 | 3413 | ||
@@ -3237,44 +3417,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3237 | terse.RegionData.TimeDilation = | 3417 | terse.RegionData.TimeDilation = |
3238 | (ushort)(Scene.TimeDilation * ushort.MaxValue); | 3418 | (ushort)(Scene.TimeDilation * ushort.MaxValue); |
3239 | 3419 | ||
3240 | int max = m_avatarTerseUpdatesPerPacket; | 3420 | int count = Math.Min(m_avatarTerseUpdates.Count, m_avatarTerseUpdatesPerPacket); |
3241 | if (max > m_avatarTerseUpdates.Count) | ||
3242 | max = m_avatarTerseUpdates.Count; | ||
3243 | |||
3244 | int count = 0; | ||
3245 | int size = 0; | ||
3246 | |||
3247 | byte[] zerobuffer = new byte[1024]; | ||
3248 | byte[] blockbuffer = new byte[1024]; | ||
3249 | |||
3250 | for (count = 0 ; count < max ; count++) | ||
3251 | { | ||
3252 | int length = 0; | ||
3253 | m_avatarTerseUpdates[count].ToBytes(blockbuffer, ref length); | ||
3254 | length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer); | ||
3255 | if (size + length > Packet.MTU) | ||
3256 | break; | ||
3257 | size += length; | ||
3258 | } | ||
3259 | 3421 | ||
3260 | terse.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[count]; | 3422 | terse.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[count]; |
3261 | 3423 | for (int i = 0; i < count; i++) | |
3262 | for (int i = 0 ; i < count ; i++) | 3424 | terse.ObjectData[i] = m_avatarTerseUpdates.Dequeue(); |
3263 | { | ||
3264 | terse.ObjectData[i] = m_avatarTerseUpdates[0]; | ||
3265 | m_avatarTerseUpdates.RemoveAt(0); | ||
3266 | } | ||
3267 | 3425 | ||
3268 | terse.Header.Reliable = false; | 3426 | terse.Header.Reliable = false; |
3269 | terse.Header.Zerocoded = true; | 3427 | terse.Header.Zerocoded = true; |
3270 | // FIXME: Move this to ThrottleOutPacketType.State when the real prioritization code is committed | ||
3271 | OutPacket(terse, ThrottleOutPacketType.Task); | ||
3272 | 3428 | ||
3273 | if (m_avatarTerseUpdates.Count == 0) | 3429 | OutPacket(terse, ThrottleOutPacketType.Task); |
3274 | { | ||
3275 | lock (m_avatarTerseUpdateTimer) | ||
3276 | m_avatarTerseUpdateTimer.Stop(); | ||
3277 | } | ||
3278 | } | 3430 | } |
3279 | } | 3431 | } |
3280 | 3432 | ||
@@ -3342,54 +3494,42 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3342 | OutPacket(attach, ThrottleOutPacketType.Task); | 3494 | OutPacket(attach, ThrottleOutPacketType.Task); |
3343 | } | 3495 | } |
3344 | 3496 | ||
3345 | public void SendPrimitiveToClient( | 3497 | public void SendPrimitiveToClient(SendPrimitiveData data) |
3346 | ulong regionHandle, ushort timeDilation, uint localID, PrimitiveBaseShape primShape, | ||
3347 | Vector3 pos, Vector3 vel, Vector3 acc, Quaternion rotation, Vector3 rvel, | ||
3348 | uint flags, UUID objectID, UUID ownerID, string text, byte[] color, | ||
3349 | uint parentID, byte[] particleSystem, byte clickAction, byte material) | ||
3350 | { | 3498 | { |
3351 | byte[] textureanim = new byte[0]; | 3499 | if (data.priority == double.NaN) |
3352 | 3500 | { | |
3353 | SendPrimitiveToClient(regionHandle, timeDilation, localID, primShape, pos, vel, | 3501 | m_log.Error("[LLClientView] SendPrimitiveToClient received a NaN priority, dropping update"); |
3354 | acc, rotation, rvel, flags, | 3502 | return; |
3355 | objectID, ownerID, text, color, parentID, particleSystem, | 3503 | } |
3356 | clickAction, material, textureanim, false, 0, UUID.Zero, UUID.Zero, 0, 0, 0); | ||
3357 | } | ||
3358 | 3504 | ||
3359 | public void SendPrimitiveToClient( | 3505 | Quaternion rotation = data.rotation; |
3360 | ulong regionHandle, ushort timeDilation, uint localID, PrimitiveBaseShape primShape, | ||
3361 | Vector3 pos, Vector3 velocity, Vector3 acceleration, Quaternion rotation, Vector3 rotational_velocity, | ||
3362 | uint flags, | ||
3363 | UUID objectID, UUID ownerID, string text, byte[] color, uint parentID, byte[] particleSystem, | ||
3364 | byte clickAction, byte material, byte[] textureanim, bool attachment, uint AttachPoint, UUID AssetId, UUID SoundId, double SoundGain, byte SoundFlags, double SoundRadius) | ||
3365 | { | ||
3366 | 3506 | ||
3367 | if (AttachPoint > 30 && ownerID != AgentId) // Someone else's HUD | 3507 | if (data.AttachPoint > 30 && data.ownerID != AgentId) // Someone else's HUD |
3368 | return; | 3508 | return; |
3369 | if (primShape.PCode == 9 && primShape.State != 0 && parentID == 0) | 3509 | if (data.primShape.PCode == 9 && data.primShape.State != 0 && data.parentID == 0) |
3370 | return; | 3510 | return; |
3371 | 3511 | ||
3372 | if (rotation.X == rotation.Y && rotation.Y == rotation.Z && rotation.Z == rotation.W && rotation.W == 0) | 3512 | if (rotation.X == rotation.Y && rotation.Y == rotation.Z && rotation.Z == rotation.W && rotation.W == 0.0f) |
3373 | rotation = Quaternion.Identity; | 3513 | rotation = Quaternion.Identity; |
3374 | 3514 | ||
3375 | ObjectUpdatePacket.ObjectDataBlock objectData = CreatePrimUpdateBlock(primShape, flags); | 3515 | ObjectUpdatePacket.ObjectDataBlock objectData = CreatePrimUpdateBlock(data.primShape, data.flags); |
3376 | 3516 | ||
3377 | objectData.ID = localID; | 3517 | objectData.ID = data.localID; |
3378 | objectData.FullID = objectID; | 3518 | objectData.FullID = data.objectID; |
3379 | objectData.OwnerID = ownerID; | 3519 | objectData.OwnerID = data.ownerID; |
3380 | 3520 | ||
3381 | objectData.Text = Util.StringToBytes256(text); | 3521 | objectData.Text = Util.StringToBytes256(data.text); |
3382 | objectData.TextColor[0] = color[0]; | 3522 | objectData.TextColor[0] = data.color[0]; |
3383 | objectData.TextColor[1] = color[1]; | 3523 | objectData.TextColor[1] = data.color[1]; |
3384 | objectData.TextColor[2] = color[2]; | 3524 | objectData.TextColor[2] = data.color[2]; |
3385 | objectData.TextColor[3] = color[3]; | 3525 | objectData.TextColor[3] = data.color[3]; |
3386 | objectData.ParentID = parentID; | 3526 | objectData.ParentID = data.parentID; |
3387 | objectData.PSBlock = particleSystem; | 3527 | objectData.PSBlock = data.particleSystem; |
3388 | objectData.ClickAction = clickAction; | 3528 | objectData.ClickAction = data.clickAction; |
3389 | objectData.Material = material; | 3529 | objectData.Material = data.material; |
3390 | objectData.Flags = 0; | 3530 | objectData.Flags = 0; |
3391 | 3531 | ||
3392 | if (attachment) | 3532 | if (data.attachment) |
3393 | { | 3533 | { |
3394 | // Necessary??? | 3534 | // Necessary??? |
3395 | objectData.JointAxisOrAnchor = new Vector3(0, 0, 2); | 3535 | objectData.JointAxisOrAnchor = new Vector3(0, 0, 2); |
@@ -3397,14 +3537,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3397 | 3537 | ||
3398 | // Item from inventory??? | 3538 | // Item from inventory??? |
3399 | objectData.NameValue = | 3539 | objectData.NameValue = |
3400 | Utils.StringToBytes("AttachItemID STRING RW SV " + AssetId.Guid); | 3540 | Utils.StringToBytes("AttachItemID STRING RW SV " + data.AssetId.Guid); |
3401 | objectData.State = (byte)((AttachPoint % 16) * 16 + (AttachPoint / 16)); | 3541 | objectData.State = (byte)((data.AttachPoint % 16) * 16 + (data.AttachPoint / 16)); |
3402 | } | 3542 | } |
3403 | 3543 | ||
3404 | // Xantor 20080528: Send sound info as well | 3544 | // Xantor 20080528: Send sound info as well |
3405 | // Xantor 20080530: Zero out everything if there's no SoundId, so zerocompression will work again | 3545 | // Xantor 20080530: Zero out everything if there's no SoundId, so zerocompression will work again |
3406 | objectData.Sound = SoundId; | 3546 | objectData.Sound = data.SoundId; |
3407 | if (SoundId == UUID.Zero) | 3547 | if (data.SoundId == UUID.Zero) |
3408 | { | 3548 | { |
3409 | objectData.OwnerID = UUID.Zero; | 3549 | objectData.OwnerID = UUID.Zero; |
3410 | objectData.Gain = 0.0f; | 3550 | objectData.Gain = 0.0f; |
@@ -3413,48 +3553,68 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3413 | } | 3553 | } |
3414 | else | 3554 | else |
3415 | { | 3555 | { |
3416 | objectData.OwnerID = ownerID; | 3556 | objectData.OwnerID = data.ownerID; |
3417 | objectData.Gain = (float)SoundGain; | 3557 | objectData.Gain = (float)data.SoundVolume; |
3418 | objectData.Radius = (float)SoundRadius; | 3558 | objectData.Radius = (float)data.SoundRadius; |
3419 | objectData.Flags = SoundFlags; | 3559 | objectData.Flags = data.SoundFlags; |
3420 | } | 3560 | } |
3421 | 3561 | ||
3422 | byte[] pb = pos.GetBytes(); | 3562 | byte[] pb = data.pos.GetBytes(); |
3423 | Array.Copy(pb, 0, objectData.ObjectData, 0, pb.Length); | 3563 | Buffer.BlockCopy(pb, 0, objectData.ObjectData, 0, pb.Length); |
3424 | 3564 | ||
3425 | byte[] vel = velocity.GetBytes(); | 3565 | byte[] vel = data.vel.GetBytes(); |
3426 | Array.Copy(vel, 0, objectData.ObjectData, pb.Length, vel.Length); | 3566 | Buffer.BlockCopy(vel, 0, objectData.ObjectData, pb.Length, vel.Length); |
3427 | 3567 | ||
3428 | byte[] rot = rotation.GetBytes(); | 3568 | byte[] rot = rotation.GetBytes(); |
3429 | Array.Copy(rot, 0, objectData.ObjectData, 36, rot.Length); | 3569 | Buffer.BlockCopy(rot, 0, objectData.ObjectData, 36, rot.Length); |
3430 | 3570 | ||
3431 | byte[] rvel = rotational_velocity.GetBytes(); | 3571 | byte[] rvel = data.rvel.GetBytes(); |
3432 | Array.Copy(rvel, 0, objectData.ObjectData, 36 + rot.Length, rvel.Length); | 3572 | Buffer.BlockCopy(rvel, 0, objectData.ObjectData, 36 + rot.Length, rvel.Length); |
3433 | 3573 | ||
3434 | if (textureanim.Length > 0) | 3574 | if (data.textureanim.Length > 0) |
3435 | { | 3575 | { |
3436 | objectData.TextureAnim = textureanim; | 3576 | objectData.TextureAnim = data.textureanim; |
3437 | } | 3577 | } |
3438 | 3578 | ||
3439 | lock (m_primFullUpdates) | 3579 | lock (m_primFullUpdates.SyncRoot) |
3440 | { | 3580 | m_primFullUpdates.Enqueue(data.priority, objectData, data.localID); |
3441 | if (m_primFullUpdates.Count == 0) | ||
3442 | m_primFullUpdateTimer.Start(); | ||
3443 | |||
3444 | m_primFullUpdates.Add(objectData); | ||
3445 | |||
3446 | if (m_primFullUpdates.Count >= m_primFullUpdatesPerPacket) | ||
3447 | ProcessPrimFullUpdates(this, null); | ||
3448 | } | ||
3449 | } | 3581 | } |
3450 | 3582 | ||
3451 | void HandleQueueEmpty(ThrottleOutPacketType queue) | 3583 | void HandleQueueEmpty(ThrottleOutPacketType queue) |
3452 | { | 3584 | { |
3585 | int count = 0; | ||
3586 | |||
3453 | switch (queue) | 3587 | switch (queue) |
3454 | { | 3588 | { |
3455 | case ThrottleOutPacketType.Texture: | 3589 | case ThrottleOutPacketType.Texture: |
3456 | ProcessTextureRequests(); | 3590 | ProcessTextureRequests(); |
3457 | break; | 3591 | break; |
3592 | case ThrottleOutPacketType.Task: | ||
3593 | lock (m_avatarTerseUpdates.SyncRoot) | ||
3594 | count = m_avatarTerseUpdates.Count; | ||
3595 | if (count > 0) | ||
3596 | { | ||
3597 | ProcessAvatarTerseUpdates(); | ||
3598 | return; | ||
3599 | } | ||
3600 | break; | ||
3601 | case ThrottleOutPacketType.State: | ||
3602 | lock (m_primFullUpdates.SyncRoot) | ||
3603 | count = m_primFullUpdates.Count; | ||
3604 | if (count > 0) | ||
3605 | { | ||
3606 | ProcessPrimFullUpdates(); | ||
3607 | return; | ||
3608 | } | ||
3609 | |||
3610 | lock (m_primTerseUpdates.SyncRoot) | ||
3611 | count = m_primTerseUpdates.Count; | ||
3612 | if (count > 0) | ||
3613 | { | ||
3614 | ProcessPrimTerseUpdates(); | ||
3615 | return; | ||
3616 | } | ||
3617 | break; | ||
3458 | } | 3618 | } |
3459 | } | 3619 | } |
3460 | 3620 | ||
@@ -3464,18 +3624,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3464 | m_imageManager.ProcessImageQueue(m_textureSendLimit); | 3624 | m_imageManager.ProcessImageQueue(m_textureSendLimit); |
3465 | } | 3625 | } |
3466 | 3626 | ||
3467 | void ProcessPrimFullUpdates(object sender, ElapsedEventArgs e) | 3627 | void ProcessPrimFullUpdates() |
3468 | { | 3628 | { |
3469 | lock (m_primFullUpdates) | 3629 | lock (m_primFullUpdates.SyncRoot) |
3470 | { | 3630 | { |
3471 | if (m_primFullUpdates.Count == 0 && m_primFullUpdateTimer.Enabled) | ||
3472 | { | ||
3473 | lock (m_primFullUpdateTimer) | ||
3474 | m_primFullUpdateTimer.Stop(); | ||
3475 | |||
3476 | return; | ||
3477 | } | ||
3478 | |||
3479 | ObjectUpdatePacket outPacket = | 3631 | ObjectUpdatePacket outPacket = |
3480 | (ObjectUpdatePacket)PacketPool.Instance.GetPacket( | 3632 | (ObjectUpdatePacket)PacketPool.Instance.GetPacket( |
3481 | PacketType.ObjectUpdate); | 3633 | PacketType.ObjectUpdate); |
@@ -3485,84 +3637,50 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3485 | outPacket.RegionData.TimeDilation = | 3637 | outPacket.RegionData.TimeDilation = |
3486 | (ushort)(Scene.TimeDilation * ushort.MaxValue); | 3638 | (ushort)(Scene.TimeDilation * ushort.MaxValue); |
3487 | 3639 | ||
3488 | int max = m_primFullUpdates.Count; | 3640 | int count = Math.Min(m_primFullUpdates.Count, m_primFullUpdatesPerPacket); |
3489 | if (max > m_primFullUpdatesPerPacket) | ||
3490 | max = m_primFullUpdatesPerPacket; | ||
3491 | |||
3492 | int count = 0; | ||
3493 | int size = 0; | ||
3494 | |||
3495 | byte[] zerobuffer = new byte[1024]; | ||
3496 | byte[] blockbuffer = new byte[1024]; | ||
3497 | 3641 | ||
3498 | for (count = 0 ; count < max ; count++) | 3642 | outPacket.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[count]; |
3499 | { | 3643 | for (int i = 0; i < count; i++) |
3500 | int length = 0; | 3644 | outPacket.ObjectData[i] = m_primFullUpdates.Dequeue(); |
3501 | m_primFullUpdates[count].ToBytes(blockbuffer, ref length); | ||
3502 | length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer); | ||
3503 | if (size + length > Packet.MTU) | ||
3504 | break; | ||
3505 | size += length; | ||
3506 | } | ||
3507 | |||
3508 | outPacket.ObjectData = | ||
3509 | new ObjectUpdatePacket.ObjectDataBlock[count]; | ||
3510 | |||
3511 | for (int index = 0 ; index < count ; index++) | ||
3512 | { | ||
3513 | outPacket.ObjectData[index] = m_primFullUpdates[0]; | ||
3514 | m_primFullUpdates.RemoveAt(0); | ||
3515 | } | ||
3516 | 3645 | ||
3517 | outPacket.Header.Zerocoded = true; | 3646 | outPacket.Header.Zerocoded = true; |
3518 | OutPacket(outPacket, ThrottleOutPacketType.State); | 3647 | OutPacket(outPacket, ThrottleOutPacketType.State); |
3519 | |||
3520 | if (m_primFullUpdates.Count == 0 && m_primFullUpdateTimer.Enabled) | ||
3521 | lock (m_primFullUpdateTimer) | ||
3522 | m_primFullUpdateTimer.Stop(); | ||
3523 | } | 3648 | } |
3524 | } | 3649 | } |
3525 | 3650 | ||
3526 | /// <summary> | 3651 | /// <summary> |
3527 | /// | 3652 | /// |
3528 | /// </summary> | 3653 | /// </summary> |
3529 | public void SendPrimTerseUpdate(ulong regionHandle, ushort timeDilation, uint localID, Vector3 position, | 3654 | //public void SendPrimTerseUpdate(ulong regionHandle, ushort timeDilation, uint localID, Vector3 position, |
3530 | Quaternion rotation, Vector3 velocity, Vector3 rotationalvelocity, byte state, UUID AssetId, UUID ownerID, int attachPoint) | 3655 | // Quaternion rotation, Vector3 velocity, Vector3 rotationalvelocity, byte state, UUID AssetId, UUID ownerID, int attachPoint) |
3656 | public void SendPrimTerseUpdate(SendPrimitiveTerseData data) | ||
3531 | { | 3657 | { |
3532 | if (attachPoint > 30 && ownerID != AgentId) // Someone else's HUD | 3658 | if (data.priority == double.NaN) |
3659 | { | ||
3660 | m_log.Error("[LLClientView] SendPrimTerseUpdate received a NaN priority, dropping update"); | ||
3661 | return; | ||
3662 | } | ||
3663 | |||
3664 | Quaternion rotation = data.rotation; | ||
3665 | |||
3666 | if (data.attachPoint > 30 && data.owner != AgentId) // Someone else's HUD | ||
3533 | return; | 3667 | return; |
3534 | 3668 | ||
3535 | if (rotation.X == rotation.Y && rotation.Y == rotation.Z && rotation.Z == rotation.W && rotation.W == 0) | 3669 | if (rotation.X == rotation.Y && rotation.Y == rotation.Z && rotation.Z == rotation.W && rotation.W == 0) |
3536 | rotation = Quaternion.Identity; | 3670 | rotation = Quaternion.Identity; |
3537 | 3671 | ||
3538 | ImprovedTerseObjectUpdatePacket.ObjectDataBlock objectData = | 3672 | ImprovedTerseObjectUpdatePacket.ObjectDataBlock objectData = |
3539 | CreatePrimImprovedBlock(localID, position, rotation, | 3673 | CreatePrimImprovedBlock(data.localID, data.position, rotation, |
3540 | velocity, rotationalvelocity, state); | 3674 | data.velocity, data.rotationalvelocity, data.state); |
3541 | |||
3542 | lock (m_primTerseUpdates) | ||
3543 | { | ||
3544 | if (m_primTerseUpdates.Count == 0) | ||
3545 | m_primTerseUpdateTimer.Start(); | ||
3546 | |||
3547 | m_primTerseUpdates.Add(objectData); | ||
3548 | 3675 | ||
3549 | if (m_primTerseUpdates.Count >= m_primTerseUpdatesPerPacket) | 3676 | lock (m_primTerseUpdates.SyncRoot) |
3550 | ProcessPrimTerseUpdates(this, null); | 3677 | m_primTerseUpdates.Enqueue(data.priority, objectData, data.localID); |
3551 | } | ||
3552 | } | 3678 | } |
3553 | 3679 | ||
3554 | void ProcessPrimTerseUpdates(object sender, ElapsedEventArgs e) | 3680 | void ProcessPrimTerseUpdates() |
3555 | { | 3681 | { |
3556 | lock (m_primTerseUpdates) | 3682 | lock (m_primTerseUpdates.SyncRoot) |
3557 | { | 3683 | { |
3558 | if (m_primTerseUpdates.Count == 0) | ||
3559 | { | ||
3560 | lock (m_primTerseUpdateTimer) | ||
3561 | m_primTerseUpdateTimer.Stop(); | ||
3562 | |||
3563 | return; | ||
3564 | } | ||
3565 | |||
3566 | ImprovedTerseObjectUpdatePacket outPacket = | 3684 | ImprovedTerseObjectUpdatePacket outPacket = |
3567 | (ImprovedTerseObjectUpdatePacket) | 3685 | (ImprovedTerseObjectUpdatePacket) |
3568 | PacketPool.Instance.GetPacket( | 3686 | PacketPool.Instance.GetPacket( |
@@ -3573,43 +3691,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3573 | outPacket.RegionData.TimeDilation = | 3691 | outPacket.RegionData.TimeDilation = |
3574 | (ushort)(Scene.TimeDilation * ushort.MaxValue); | 3692 | (ushort)(Scene.TimeDilation * ushort.MaxValue); |
3575 | 3693 | ||
3576 | int max = m_primTerseUpdates.Count; | 3694 | int count = Math.Min(m_primTerseUpdates.Count, m_primTerseUpdatesPerPacket); |
3577 | if (max > m_primTerseUpdatesPerPacket) | ||
3578 | max = m_primTerseUpdatesPerPacket; | ||
3579 | |||
3580 | int count = 0; | ||
3581 | int size = 0; | ||
3582 | 3695 | ||
3583 | byte[] zerobuffer = new byte[1024]; | 3696 | outPacket.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[count]; |
3584 | byte[] blockbuffer = new byte[1024]; | 3697 | for (int i = 0; i < count; i++) |
3585 | 3698 | outPacket.ObjectData[i] = m_primTerseUpdates.Dequeue(); | |
3586 | for (count = 0 ; count < max ; count++) | ||
3587 | { | ||
3588 | int length = 0; | ||
3589 | m_primTerseUpdates[count].ToBytes(blockbuffer, ref length); | ||
3590 | length = Helpers.ZeroEncode(blockbuffer, length, zerobuffer); | ||
3591 | if (size + length > Packet.MTU) | ||
3592 | break; | ||
3593 | size += length; | ||
3594 | } | ||
3595 | |||
3596 | outPacket.ObjectData = | ||
3597 | new ImprovedTerseObjectUpdatePacket. | ||
3598 | ObjectDataBlock[count]; | ||
3599 | |||
3600 | for (int index = 0 ; index < count ; index++) | ||
3601 | { | ||
3602 | outPacket.ObjectData[index] = m_primTerseUpdates[0]; | ||
3603 | m_primTerseUpdates.RemoveAt(0); | ||
3604 | } | ||
3605 | 3699 | ||
3606 | outPacket.Header.Reliable = false; | 3700 | outPacket.Header.Reliable = false; |
3607 | outPacket.Header.Zerocoded = true; | 3701 | outPacket.Header.Zerocoded = true; |
3608 | OutPacket(outPacket, ThrottleOutPacketType.State); | 3702 | OutPacket(outPacket, ThrottleOutPacketType.State); |
3609 | |||
3610 | if (m_primTerseUpdates.Count == 0) | ||
3611 | lock (m_primTerseUpdateTimer) | ||
3612 | m_primTerseUpdateTimer.Stop(); | ||
3613 | } | 3703 | } |
3614 | } | 3704 | } |
3615 | 3705 | ||
@@ -3617,15 +3707,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3617 | { | 3707 | { |
3618 | while (m_primFullUpdates.Count > 0) | 3708 | while (m_primFullUpdates.Count > 0) |
3619 | { | 3709 | { |
3620 | ProcessPrimFullUpdates(this, null); | 3710 | ProcessPrimFullUpdates(); |
3621 | } | 3711 | } |
3622 | while (m_primTerseUpdates.Count > 0) | 3712 | while (m_primTerseUpdates.Count > 0) |
3623 | { | 3713 | { |
3624 | ProcessPrimTerseUpdates(this, null); | 3714 | ProcessPrimTerseUpdates(); |
3625 | } | 3715 | } |
3626 | while (m_avatarTerseUpdates.Count > 0) | 3716 | while (m_avatarTerseUpdates.Count > 0) |
3627 | { | 3717 | { |
3628 | ProcessAvatarTerseUpdates(this, null); | 3718 | ProcessAvatarTerseUpdates(); |
3629 | } | 3719 | } |
3630 | } | 3720 | } |
3631 | 3721 | ||
@@ -10371,5 +10461,136 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
10371 | pack.TextureData.TextureID = textureID; | 10461 | pack.TextureData.TextureID = textureID; |
10372 | OutPacket(pack, ThrottleOutPacketType.Task); | 10462 | OutPacket(pack, ThrottleOutPacketType.Task); |
10373 | } | 10463 | } |
10464 | |||
10465 | #region PriorityQueue | ||
10466 | private class PriorityQueue<TPriority, TValue> | ||
10467 | { | ||
10468 | private MinHeap<MinHeapItem>[] heaps = new MinHeap<MinHeapItem>[1]; | ||
10469 | private Dictionary<uint, LookupItem> lookup_table = new Dictionary<uint, LookupItem>(); | ||
10470 | private Comparison<TPriority> comparison; | ||
10471 | private object sync_root = new object(); | ||
10472 | |||
10473 | internal PriorityQueue() : | ||
10474 | this(MinHeap<MinHeapItem>.DEFAULT_CAPACITY, Comparer<TPriority>.Default) { } | ||
10475 | internal PriorityQueue(int capacity) : | ||
10476 | this(capacity, Comparer<TPriority>.Default) { } | ||
10477 | internal PriorityQueue(IComparer<TPriority> comparer) : | ||
10478 | this(new Comparison<TPriority>(comparer.Compare)) { } | ||
10479 | internal PriorityQueue(Comparison<TPriority> comparison) : | ||
10480 | this(MinHeap<MinHeapItem>.DEFAULT_CAPACITY, comparison) { } | ||
10481 | internal PriorityQueue(int capacity, IComparer<TPriority> comparer) : | ||
10482 | this(capacity, new Comparison<TPriority>(comparer.Compare)) { } | ||
10483 | internal PriorityQueue(int capacity, Comparison<TPriority> comparison) | ||
10484 | { | ||
10485 | for (int i = 0; i < heaps.Length; ++i) | ||
10486 | heaps[i] = new MinHeap<MinHeapItem>(capacity); | ||
10487 | this.comparison = comparison; | ||
10488 | } | ||
10489 | |||
10490 | internal object SyncRoot { get { return this.sync_root; } } | ||
10491 | internal int Count | ||
10492 | { | ||
10493 | get | ||
10494 | { | ||
10495 | int count = 0; | ||
10496 | for (int i = 0; i < heaps.Length; ++i) | ||
10497 | count = heaps[i].Count; | ||
10498 | return count; | ||
10499 | } | ||
10500 | } | ||
10501 | |||
10502 | internal bool Enqueue(TPriority priority, TValue value, uint local_id) | ||
10503 | { | ||
10504 | LookupItem item; | ||
10505 | |||
10506 | if (lookup_table.TryGetValue(local_id, out item)) | ||
10507 | { | ||
10508 | item.Heap[item.Handle] = new MinHeapItem(priority, value, local_id, this.comparison); | ||
10509 | return false; | ||
10510 | } | ||
10511 | else | ||
10512 | { | ||
10513 | item.Heap = heaps[0]; | ||
10514 | item.Heap.Add(new MinHeapItem(priority, value, local_id, this.comparison), ref item.Handle); | ||
10515 | lookup_table.Add(local_id, item); | ||
10516 | return true; | ||
10517 | } | ||
10518 | } | ||
10519 | |||
10520 | internal TValue Peek() | ||
10521 | { | ||
10522 | for (int i = 0; i < heaps.Length; ++i) | ||
10523 | if (heaps[i].Count > 0) | ||
10524 | return heaps[i].Min().Value; | ||
10525 | throw new InvalidOperationException(string.Format("The {0} is empty", this.GetType().ToString())); | ||
10526 | } | ||
10527 | |||
10528 | internal TValue Dequeue() | ||
10529 | { | ||
10530 | for (int i = 0; i < heaps.Length; ++i) | ||
10531 | { | ||
10532 | if (heaps[i].Count > 0) | ||
10533 | { | ||
10534 | MinHeapItem item = heaps[i].RemoveMin(); | ||
10535 | lookup_table.Remove(item.LocalID); | ||
10536 | return item.Value; | ||
10537 | } | ||
10538 | } | ||
10539 | throw new InvalidOperationException(string.Format("The {0} is empty", this.GetType().ToString())); | ||
10540 | } | ||
10541 | |||
10542 | #region MinHeapItem | ||
10543 | private struct MinHeapItem : IComparable<MinHeapItem> | ||
10544 | { | ||
10545 | private TPriority priority; | ||
10546 | private TValue value; | ||
10547 | private uint local_id; | ||
10548 | private Comparison<TPriority> comparison; | ||
10549 | |||
10550 | internal MinHeapItem(TPriority priority, TValue value, uint local_id) : | ||
10551 | this(priority, value, local_id, Comparer<TPriority>.Default) { } | ||
10552 | internal MinHeapItem(TPriority priority, TValue value, uint local_id, IComparer<TPriority> comparer) : | ||
10553 | this(priority, value, local_id, new Comparison<TPriority>(comparer.Compare)) { } | ||
10554 | internal MinHeapItem(TPriority priority, TValue value, uint local_id, Comparison<TPriority> comparison) | ||
10555 | { | ||
10556 | this.priority = priority; | ||
10557 | this.value = value; | ||
10558 | this.local_id = local_id; | ||
10559 | this.comparison = comparison; | ||
10560 | } | ||
10561 | |||
10562 | internal TPriority Priority { get { return this.priority; } } | ||
10563 | internal TValue Value { get { return this.value; } } | ||
10564 | internal uint LocalID { get { return this.local_id; } } | ||
10565 | |||
10566 | public override string ToString() | ||
10567 | { | ||
10568 | StringBuilder sb = new StringBuilder(); | ||
10569 | sb.Append("["); | ||
10570 | if (this.priority != null) | ||
10571 | sb.Append(this.priority.ToString()); | ||
10572 | sb.Append(","); | ||
10573 | if (this.value != null) | ||
10574 | sb.Append(this.value.ToString()); | ||
10575 | sb.Append("]"); | ||
10576 | return sb.ToString(); | ||
10577 | } | ||
10578 | |||
10579 | public int CompareTo(MinHeapItem other) | ||
10580 | { | ||
10581 | return this.comparison(this.priority, other.priority); | ||
10582 | } | ||
10583 | } | ||
10584 | #endregion | ||
10585 | |||
10586 | #region LookupItem | ||
10587 | private struct LookupItem { | ||
10588 | internal MinHeap<MinHeapItem> Heap; | ||
10589 | internal IHandle Handle; | ||
10590 | } | ||
10591 | #endregion | ||
10592 | } | ||
10593 | #endregion | ||
10594 | |||
10374 | } | 10595 | } |
10375 | } | 10596 | } |
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs index 4eee6b6..9476eed 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs | |||
@@ -170,7 +170,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
170 | { | 170 | { |
171 | ThrottleOutPacketType type = (ThrottleOutPacketType)i; | 171 | ThrottleOutPacketType type = (ThrottleOutPacketType)i; |
172 | 172 | ||
173 | // Initialize the packet outboxes, where packets sit while they are waiting for tokens | ||
173 | m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>(); | 174 | m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>(); |
175 | // Initialize the token buckets that control the throttling for each category | ||
174 | m_throttleCategories[i] = new TokenBucket(m_throttle, rates.GetLimit(type), rates.GetRate(type)); | 176 | m_throttleCategories[i] = new TokenBucket(m_throttle, rates.GetLimit(type), rates.GetRate(type)); |
175 | } | 177 | } |
176 | 178 | ||
@@ -293,36 +295,54 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
293 | int state = (int)((float)task * STATE_TASK_PERCENTAGE); | 295 | int state = (int)((float)task * STATE_TASK_PERCENTAGE); |
294 | task -= state; | 296 | task -= state; |
295 | 297 | ||
296 | int ceiling = Int32.MaxValue; | 298 | // Make sure none of the throttles are set below our packet MTU, |
297 | if (m_defaultThrottleRates.Total != 0) | 299 | // otherwise a throttle could become permanently clogged |
298 | { | 300 | resend = Math.Max(resend, LLUDPServer.MTU); |
299 | ceiling = m_defaultThrottleRates.Total; | 301 | land = Math.Max(land, LLUDPServer.MTU); |
300 | if (ceiling < Packet.MTU) ceiling = Packet.MTU; | 302 | wind = Math.Max(wind, LLUDPServer.MTU); |
301 | } | 303 | cloud = Math.Max(cloud, LLUDPServer.MTU); |
302 | 304 | task = Math.Max(task, LLUDPServer.MTU); | |
303 | resend = Utils.Clamp(resend, Packet.MTU, ceiling); | 305 | texture = Math.Max(texture, LLUDPServer.MTU); |
304 | land = Utils.Clamp(land, Packet.MTU, ceiling); | 306 | asset = Math.Max(asset, LLUDPServer.MTU); |
305 | wind = Utils.Clamp(wind, Packet.MTU, ceiling); | 307 | state = Math.Max(state, LLUDPServer.MTU); |
306 | cloud = Utils.Clamp(cloud, Packet.MTU, ceiling); | ||
307 | task = Utils.Clamp(task, Packet.MTU, ceiling); | ||
308 | texture = Utils.Clamp(texture, Packet.MTU, ceiling); | ||
309 | asset = Utils.Clamp(asset, Packet.MTU, ceiling); | ||
310 | state = Utils.Clamp(state, Packet.MTU, ceiling); | ||
311 | 308 | ||
312 | int total = resend + land + wind + cloud + task + texture + asset + state; | 309 | int total = resend + land + wind + cloud + task + texture + asset + state; |
313 | int taskTotal = task + state; | ||
314 | 310 | ||
315 | 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}", | 311 | 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}", |
316 | AgentID, resend, land, wind, cloud, task, texture, asset, state, total); | 312 | AgentID, resend, land, wind, cloud, task, texture, asset, state, total); |
317 | 313 | ||
318 | SetThrottle(ThrottleOutPacketType.Resend, resend, resend); | 314 | // Update the token buckets with new throttle values |
319 | SetThrottle(ThrottleOutPacketType.Land, land, land); | 315 | TokenBucket bucket; |
320 | SetThrottle(ThrottleOutPacketType.Wind, wind, wind); | 316 | |
321 | SetThrottle(ThrottleOutPacketType.Cloud, cloud, cloud); | 317 | bucket = m_throttle; |
322 | SetThrottle(ThrottleOutPacketType.Task, task, taskTotal); | 318 | bucket.MaxBurst = total; |
323 | SetThrottle(ThrottleOutPacketType.Texture, texture, texture); | 319 | |
324 | SetThrottle(ThrottleOutPacketType.Asset, asset, asset); | 320 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend]; |
325 | SetThrottle(ThrottleOutPacketType.State, state, taskTotal); | 321 | bucket.DripRate = bucket.MaxBurst = resend; |
322 | |||
323 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land]; | ||
324 | bucket.DripRate = bucket.MaxBurst = land; | ||
325 | |||
326 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind]; | ||
327 | bucket.DripRate = bucket.MaxBurst = wind; | ||
328 | |||
329 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud]; | ||
330 | bucket.DripRate = bucket.MaxBurst = cloud; | ||
331 | |||
332 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset]; | ||
333 | bucket.DripRate = bucket.MaxBurst = asset; | ||
334 | |||
335 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task]; | ||
336 | bucket.DripRate = task + state + texture; | ||
337 | bucket.MaxBurst = task + state + texture; | ||
338 | |||
339 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.State]; | ||
340 | bucket.DripRate = state + texture; | ||
341 | bucket.MaxBurst = state + texture; | ||
342 | |||
343 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture]; | ||
344 | bucket.DripRate = texture; | ||
345 | bucket.MaxBurst = texture; | ||
326 | } | 346 | } |
327 | 347 | ||
328 | public byte[] GetThrottlesPacked() | 348 | public byte[] GetThrottlesPacked() |
@@ -342,17 +362,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
342 | return data; | 362 | return data; |
343 | } | 363 | } |
344 | 364 | ||
345 | public void SetThrottle(ThrottleOutPacketType category, int rate, int maxBurst) | ||
346 | { | ||
347 | int i = (int)category; | ||
348 | if (i >= 0 && i < m_throttleCategories.Length) | ||
349 | { | ||
350 | TokenBucket bucket = m_throttleCategories[(int)category]; | ||
351 | bucket.DripRate = rate; | ||
352 | bucket.MaxBurst = maxBurst; | ||
353 | } | ||
354 | } | ||
355 | |||
356 | public bool EnqueueOutgoing(OutgoingPacket packet) | 365 | public bool EnqueueOutgoing(OutgoingPacket packet) |
357 | { | 366 | { |
358 | int category = (int)packet.Category; | 367 | int category = (int)packet.Category; |
@@ -395,9 +404,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
395 | TokenBucket bucket; | 404 | TokenBucket bucket; |
396 | bool packetSent = false; | 405 | bool packetSent = false; |
397 | 406 | ||
407 | //string queueDebugOutput = String.Empty; // Serious debug business | ||
408 | |||
398 | for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) | 409 | for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) |
399 | { | 410 | { |
400 | bucket = m_throttleCategories[i]; | 411 | bucket = m_throttleCategories[i]; |
412 | //queueDebugOutput += m_packetOutboxes[i].Count + " "; // Serious debug business | ||
401 | 413 | ||
402 | if (m_nextPackets[i] != null) | 414 | if (m_nextPackets[i] != null) |
403 | { | 415 | { |
@@ -449,6 +461,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
449 | } | 461 | } |
450 | } | 462 | } |
451 | 463 | ||
464 | //m_log.Info("[LLUDPCLIENT]: Queues: " + queueDebugOutput); // Serious debug business | ||
452 | return packetSent; | 465 | return packetSent; |
453 | } | 466 | } |
454 | 467 | ||
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 545a0bc..8bfab6a 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs | |||
@@ -89,6 +89,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
89 | /// </summary> | 89 | /// </summary> |
90 | public class LLUDPServer : OpenSimUDPBase | 90 | public class LLUDPServer : OpenSimUDPBase |
91 | { | 91 | { |
92 | /// <summary>Maximum transmission unit, or UDP packet size, for the LLUDP protocol</summary> | ||
93 | public const int MTU = 1400; | ||
94 | |||
92 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 95 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
93 | 96 | ||
94 | /// <summary>Handlers for incoming packets</summary> | 97 | /// <summary>Handlers for incoming packets</summary> |
@@ -267,38 +270,54 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
267 | { | 270 | { |
268 | int dataLength = data.Length; | 271 | int dataLength = data.Length; |
269 | bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0; | 272 | bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0; |
273 | bool doCopy = true; | ||
270 | 274 | ||
271 | // Frequency analysis of outgoing packet sizes shows a large clump of packets at each end of the spectrum. | 275 | // Frequency analysis of outgoing packet sizes shows a large clump of packets at each end of the spectrum. |
272 | // The vast majority of packets are less than 200 bytes, although due to asset transfers and packet splitting | 276 | // The vast majority of packets are less than 200 bytes, although due to asset transfers and packet splitting |
273 | // there are a decent number of packets in the 1000-1140 byte range. We allocate one of two sizes of data here | 277 | // there are a decent number of packets in the 1000-1140 byte range. We allocate one of two sizes of data here |
274 | // to accomodate for both common scenarios and provide ample room for ACK appending in both | 278 | // to accomodate for both common scenarios and provide ample room for ACK appending in both |
275 | int bufferSize = (dataLength > 180) ? Packet.MTU : 200; | 279 | int bufferSize = (dataLength > 180) ? LLUDPServer.MTU : 200; |
276 | 280 | ||
277 | UDPPacketBuffer buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize); | 281 | UDPPacketBuffer buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize); |
278 | 282 | ||
279 | // Zerocode if needed | 283 | // Zerocode if needed |
280 | if (doZerocode) | 284 | if (doZerocode) |
281 | { | 285 | { |
282 | try { dataLength = Helpers.ZeroEncode(data, dataLength, buffer.Data); } | 286 | try |
287 | { | ||
288 | dataLength = Helpers.ZeroEncode(data, dataLength, buffer.Data); | ||
289 | doCopy = false; | ||
290 | } | ||
283 | catch (IndexOutOfRangeException) | 291 | catch (IndexOutOfRangeException) |
284 | { | 292 | { |
285 | // The packet grew larger than the bufferSize while zerocoding. | 293 | // The packet grew larger than the bufferSize while zerocoding. |
286 | // Remove the MSG_ZEROCODED flag and send the unencoded data | 294 | // Remove the MSG_ZEROCODED flag and send the unencoded data |
287 | // instead | 295 | // instead |
288 | m_log.Debug("[LLUDPSERVER]: Packet exceeded buffer size during zerocoding for " + type + ". Removing MSG_ZEROCODED flag"); | 296 | m_log.Debug("[LLUDPSERVER]: Packet exceeded buffer size during zerocoding for " + type + ". DataLength=" + dataLength + |
297 | " and BufferLength=" + buffer.Data.Length + ". Removing MSG_ZEROCODED flag"); | ||
289 | data[0] = (byte)(data[0] & ~Helpers.MSG_ZEROCODED); | 298 | data[0] = (byte)(data[0] & ~Helpers.MSG_ZEROCODED); |
290 | Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); | ||
291 | } | 299 | } |
292 | } | 300 | } |
293 | else | 301 | |
302 | // If the packet data wasn't already copied during zerocoding, copy it now | ||
303 | if (doCopy) | ||
294 | { | 304 | { |
295 | Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); | 305 | if (dataLength <= buffer.Data.Length) |
306 | { | ||
307 | Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); | ||
308 | } | ||
309 | else | ||
310 | { | ||
311 | m_log.Error("[LLUDPSERVER]: Packet exceeded buffer size! This could be an indication of packet assembly not obeying the MTU. Type=" + | ||
312 | type + ", DataLength=" + dataLength + ", BufferLength=" + buffer.Data.Length + ". Dropping packet"); | ||
313 | return; | ||
314 | } | ||
296 | } | 315 | } |
316 | |||
297 | buffer.DataLength = dataLength; | 317 | buffer.DataLength = dataLength; |
298 | 318 | ||
299 | #region Queue or Send | 319 | #region Queue or Send |
300 | 320 | ||
301 | // Look up the UDPClient this is going to | ||
302 | OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category); | 321 | OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category); |
303 | 322 | ||
304 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) | 323 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) |
@@ -513,7 +532,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
513 | IClientAPI client; | 532 | IClientAPI client; |
514 | if (!m_scene.ClientManager.TryGetValue(address, out client) || !(client is LLClientView)) | 533 | if (!m_scene.ClientManager.TryGetValue(address, out client) || !(client is LLClientView)) |
515 | { | 534 | { |
516 | m_log.Warn("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + | 535 | m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + |
517 | " in " + m_scene.RegionInfo.RegionName + ", currently tracking " + m_scene.ClientManager.Count + " clients"); | 536 | " in " + m_scene.RegionInfo.RegionName + ", currently tracking " + m_scene.ClientManager.Count + " clients"); |
518 | return; | 537 | return; |
519 | } | 538 | } |
@@ -568,9 +587,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
568 | // client.BytesSinceLastACK. Lockless thread safety | 587 | // client.BytesSinceLastACK. Lockless thread safety |
569 | int bytesSinceLastACK = Interlocked.Exchange(ref udpClient.BytesSinceLastACK, 0); | 588 | int bytesSinceLastACK = Interlocked.Exchange(ref udpClient.BytesSinceLastACK, 0); |
570 | bytesSinceLastACK += buffer.DataLength; | 589 | bytesSinceLastACK += buffer.DataLength; |
571 | if (bytesSinceLastACK > Packet.MTU * 2) | 590 | if (bytesSinceLastACK > LLUDPServer.MTU * 2) |
572 | { | 591 | { |
573 | bytesSinceLastACK -= Packet.MTU * 2; | 592 | bytesSinceLastACK -= LLUDPServer.MTU * 2; |
574 | SendAcks(udpClient); | 593 | SendAcks(udpClient); |
575 | } | 594 | } |
576 | Interlocked.Add(ref udpClient.BytesSinceLastACK, bytesSinceLastACK); | 595 | Interlocked.Add(ref udpClient.BytesSinceLastACK, bytesSinceLastACK); |
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 | |||
224 | 224 | ||
225 | foreach (Scene s in m_scenes) | 225 | foreach (Scene s in m_scenes) |
226 | { | 226 | { |
227 | s.ForEachScenePresence(delegate(ScenePresence presence) | 227 | s.ForEachScenePresence( |
228 | { | 228 | delegate(ScenePresence presence) |
229 | TrySendChatMessage(presence, fromPos, regionPos, fromID, fromName, | 229 | { |
230 | c.Type, message, sourceType); | 230 | TrySendChatMessage(presence, fromPos, regionPos, fromID, fromName, c.Type, message, sourceType); |
231 | }); | 231 | } |
232 | ); | ||
232 | } | 233 | } |
233 | } | 234 | } |
234 | 235 | ||
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 | |||
756 | 756 | ||
757 | public void sendRegionHandshakeToAll() | 757 | public void sendRegionHandshakeToAll() |
758 | { | 758 | { |
759 | m_scene.Broadcast(sendRegionHandshake); | 759 | m_scene.ForEachClient(sendRegionHandshake); |
760 | } | 760 | } |
761 | 761 | ||
762 | public void handleEstateChangeInfo(IClientAPI remoteClient, UUID invoice, UUID senderID, UInt32 parms1, UInt32 parms2) | 762 | 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 | |||
1061 | { | 1061 | { |
1062 | land.LandData.OwnerID = ownerID; | 1062 | land.LandData.OwnerID = ownerID; |
1063 | 1063 | ||
1064 | m_scene.Broadcast(SendParcelOverlay); | 1064 | m_scene.ForEachClient(SendParcelOverlay); |
1065 | land.SendLandUpdateToClient(remote_client); | 1065 | land.SendLandUpdateToClient(remote_client); |
1066 | } | 1066 | } |
1067 | } | 1067 | } |
@@ -1083,7 +1083,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1083 | land.LandData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner; | 1083 | land.LandData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner; |
1084 | else | 1084 | else |
1085 | land.LandData.OwnerID = m_scene.RegionInfo.MasterAvatarAssignedUUID; | 1085 | land.LandData.OwnerID = m_scene.RegionInfo.MasterAvatarAssignedUUID; |
1086 | m_scene.Broadcast(SendParcelOverlay); | 1086 | m_scene.ForEachClient(SendParcelOverlay); |
1087 | land.SendLandUpdateToClient(remote_client); | 1087 | land.SendLandUpdateToClient(remote_client); |
1088 | } | 1088 | } |
1089 | } | 1089 | } |
@@ -1107,7 +1107,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1107 | land.LandData.OwnerID = m_scene.RegionInfo.MasterAvatarAssignedUUID; | 1107 | land.LandData.OwnerID = m_scene.RegionInfo.MasterAvatarAssignedUUID; |
1108 | land.LandData.ClaimDate = Util.UnixTimeSinceEpoch(); | 1108 | land.LandData.ClaimDate = Util.UnixTimeSinceEpoch(); |
1109 | land.LandData.IsGroupOwned = false; | 1109 | land.LandData.IsGroupOwned = false; |
1110 | m_scene.Broadcast(SendParcelOverlay); | 1110 | m_scene.ForEachClient(SendParcelOverlay); |
1111 | land.SendLandUpdateToClient(remote_client); | 1111 | land.SendLandUpdateToClient(remote_client); |
1112 | } | 1112 | } |
1113 | } | 1113 | } |
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 | |||
81 | 81 | ||
82 | public void RegionLoaded(Scene scene) | 82 | public void RegionLoaded(Scene scene) |
83 | { | 83 | { |
84 | if (!enabledYN) | 84 | if (enabledYN) |
85 | return; | 85 | RegionLoadedDoWork(scene); |
86 | } | ||
87 | |||
88 | private void RegionLoadedDoWork(Scene scene) | ||
89 | { | ||
86 | /* | 90 | /* |
87 | // For testing on a single instance | 91 | // For testing on a single instance |
88 | if (scene.RegionInfo.RegionLocX == 1004 && scene.RegionInfo.RegionLocY == 1000) | 92 | if (scene.RegionInfo.RegionLocX == 1004 && scene.RegionInfo.RegionLocY == 1000) |
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 | |||
499 | { | 499 | { |
500 | } | 500 | } |
501 | 501 | ||
502 | public virtual void SendAvatarData(ulong regionHandle, string firstName, string lastName, string grouptitle, UUID avatarID, | 502 | public virtual void SendAvatarData(SendAvatarData data) |
503 | uint avatarLocalID, Vector3 Pos, byte[] textureEntry, uint parentID, Quaternion rotation) | ||
504 | { | 503 | { |
505 | } | 504 | } |
506 | 505 | ||
507 | public virtual void SendAvatarTerseUpdate(ulong regionHandle, ushort timeDilation, uint localID, | 506 | public virtual void SendAvatarTerseUpdate(SendAvatarTerseData data) |
508 | Vector3 position, Vector3 velocity, Quaternion rotation, UUID agentid) | ||
509 | { | 507 | { |
510 | } | 508 | } |
511 | 509 | ||
@@ -521,27 +519,11 @@ namespace OpenSim.Region.Examples.SimpleModule | |||
521 | { | 519 | { |
522 | } | 520 | } |
523 | 521 | ||
524 | public virtual void SendPrimitiveToClient(ulong regionHandle, ushort timeDilation, uint localID, | 522 | public virtual void SendPrimitiveToClient(SendPrimitiveData data) |
525 | PrimitiveBaseShape primShape, Vector3 pos, Vector3 vel, | ||
526 | Vector3 acc, Quaternion rotation, Vector3 rvel, uint flags, | ||
527 | UUID objectID, UUID ownerID, string text, byte[] color, | ||
528 | uint parentID, | ||
529 | byte[] particleSystem, byte clickAction, byte material) | ||
530 | { | 523 | { |
531 | } | 524 | } |
532 | public virtual void SendPrimitiveToClient(ulong regionHandle, ushort timeDilation, uint localID, | 525 | |
533 | PrimitiveBaseShape primShape, Vector3 pos, Vector3 vel, | 526 | public virtual void SendPrimTerseUpdate(SendPrimitiveTerseData data) |
534 | Vector3 acc, Quaternion rotation, Vector3 rvel, uint flags, | ||
535 | UUID objectID, UUID ownerID, string text, byte[] color, | ||
536 | uint parentID, | ||
537 | byte[] particleSystem, byte clickAction, byte material, byte[] textureanimation, | ||
538 | bool attachment, uint AttachmentPoint, UUID AssetId, UUID SoundId, double SoundVolume, byte SoundFlags, double SoundRadius) | ||
539 | { | ||
540 | } | ||
541 | public virtual void SendPrimTerseUpdate(ulong regionHandle, ushort timeDilation, uint localID, | ||
542 | Vector3 position, Quaternion rotation, Vector3 velocity, | ||
543 | Vector3 rotationalvelocity, byte state, UUID AssetId, | ||
544 | UUID ownerID, int attachPoint) | ||
545 | { | 527 | { |
546 | } | 528 | } |
547 | 529 | ||
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 | |||
34 | { | 34 | { |
35 | void Reset(); | 35 | void Reset(); |
36 | void Close(); | 36 | void Close(); |
37 | int MaxPrimsPerFrame { get; set; } | ||
38 | void QueuePartForUpdate(SceneObjectPart part); | 37 | void QueuePartForUpdate(SceneObjectPart part); |
39 | void SendPrimUpdates(); | 38 | void SendPrimUpdates(); |
40 | } | 39 | } |
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 29d2a84..49c1ebf 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs | |||
@@ -57,6 +57,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
57 | 57 | ||
58 | public partial class Scene : SceneBase | 58 | public partial class Scene : SceneBase |
59 | { | 59 | { |
60 | public enum UpdatePrioritizationSchemes { | ||
61 | Time = 0, | ||
62 | Distance = 1, | ||
63 | SimpleAngularDistance = 2, | ||
64 | } | ||
65 | |||
60 | public delegate void SynchronizeSceneHandler(Scene scene); | 66 | public delegate void SynchronizeSceneHandler(Scene scene); |
61 | public SynchronizeSceneHandler SynchronizeScene = null; | 67 | public SynchronizeSceneHandler SynchronizeScene = null; |
62 | 68 | ||
@@ -269,9 +275,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
269 | private volatile bool shuttingdown = false; | 275 | private volatile bool shuttingdown = false; |
270 | 276 | ||
271 | private int m_lastUpdate = Environment.TickCount; | 277 | private int m_lastUpdate = Environment.TickCount; |
272 | private int m_maxPrimsPerFrame = 200; | ||
273 | private bool m_firstHeartbeat = true; | 278 | private bool m_firstHeartbeat = true; |
274 | 279 | ||
280 | private UpdatePrioritizationSchemes m_update_prioritization_scheme = UpdatePrioritizationSchemes.Time; | ||
281 | |||
275 | private object m_deleting_scene_object = new object(); | 282 | private object m_deleting_scene_object = new object(); |
276 | 283 | ||
277 | // the minimum time that must elapse before a changed object will be considered for persisted | 284 | // the minimum time that must elapse before a changed object will be considered for persisted |
@@ -283,6 +290,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
283 | 290 | ||
284 | #region Properties | 291 | #region Properties |
285 | 292 | ||
293 | public UpdatePrioritizationSchemes UpdatePrioritizationScheme { get { return this.m_update_prioritization_scheme; } } | ||
294 | |||
286 | public AgentCircuitManager AuthenticateHandler | 295 | public AgentCircuitManager AuthenticateHandler |
287 | { | 296 | { |
288 | get { return m_authenticateHandler; } | 297 | get { return m_authenticateHandler; } |
@@ -327,12 +336,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
327 | get { return m_sceneGraph.m_syncRoot; } | 336 | get { return m_sceneGraph.m_syncRoot; } |
328 | } | 337 | } |
329 | 338 | ||
330 | public int MaxPrimsPerFrame | ||
331 | { | ||
332 | get { return m_maxPrimsPerFrame; } | ||
333 | set { m_maxPrimsPerFrame = value; } | ||
334 | } | ||
335 | |||
336 | /// <summary> | 339 | /// <summary> |
337 | /// This is for llGetRegionFPS | 340 | /// This is for llGetRegionFPS |
338 | /// </summary> | 341 | /// </summary> |
@@ -510,7 +513,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
510 | 513 | ||
511 | m_defaultScriptEngine = startupConfig.GetString("DefaultScriptEngine", "DotNetEngine"); | 514 | m_defaultScriptEngine = startupConfig.GetString("DefaultScriptEngine", "DotNetEngine"); |
512 | 515 | ||
513 | m_maxPrimsPerFrame = startupConfig.GetInt("MaxPrimsPerFrame", 200); | ||
514 | IConfig packetConfig = m_config.Configs["PacketPool"]; | 516 | IConfig packetConfig = m_config.Configs["PacketPool"]; |
515 | if (packetConfig != null) | 517 | if (packetConfig != null) |
516 | { | 518 | { |
@@ -519,6 +521,30 @@ namespace OpenSim.Region.Framework.Scenes | |||
519 | } | 521 | } |
520 | 522 | ||
521 | m_strictAccessControl = startupConfig.GetBoolean("StrictAccessControl", m_strictAccessControl); | 523 | m_strictAccessControl = startupConfig.GetBoolean("StrictAccessControl", m_strictAccessControl); |
524 | |||
525 | IConfig interest_management_config = m_config.Configs["InterestManagement"]; | ||
526 | if (interest_management_config != null) | ||
527 | { | ||
528 | string update_prioritization_scheme = interest_management_config.GetString("UpdatePrioritizationScheme", "Time").Trim().ToLower(); | ||
529 | switch (update_prioritization_scheme) | ||
530 | { | ||
531 | case "time": | ||
532 | m_update_prioritization_scheme = UpdatePrioritizationSchemes.Time; | ||
533 | break; | ||
534 | case "distance": | ||
535 | m_update_prioritization_scheme = UpdatePrioritizationSchemes.Distance; | ||
536 | break; | ||
537 | case "simpleangulardistance": | ||
538 | m_update_prioritization_scheme = UpdatePrioritizationSchemes.SimpleAngularDistance; | ||
539 | break; | ||
540 | default: | ||
541 | m_log.Warn("[SCENE]: UpdatePrioritizationScheme was not recognized, setting to default settomg of Time"); | ||
542 | m_update_prioritization_scheme = UpdatePrioritizationSchemes.Time; | ||
543 | break; | ||
544 | } | ||
545 | } | ||
546 | |||
547 | m_log.Info("[SCENE]: Using the " + m_update_prioritization_scheme + " prioritization scheme"); | ||
522 | } | 548 | } |
523 | catch | 549 | catch |
524 | { | 550 | { |
@@ -1200,15 +1226,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
1200 | } | 1226 | } |
1201 | 1227 | ||
1202 | /// <summary> | 1228 | /// <summary> |
1203 | /// Perform delegate action on all clients subscribing to updates from this region. | ||
1204 | /// </summary> | ||
1205 | /// <returns></returns> | ||
1206 | public void Broadcast(Action<IClientAPI> whatToDo) | ||
1207 | { | ||
1208 | ForEachScenePresence(delegate(ScenePresence presence) { whatToDo(presence.ControllingClient); }); | ||
1209 | } | ||
1210 | |||
1211 | /// <summary> | ||
1212 | /// Backup the scene. This acts as the main method of the backup thread. | 1229 | /// Backup the scene. This acts as the main method of the backup thread. |
1213 | /// </summary> | 1230 | /// </summary> |
1214 | /// <returns></returns> | 1231 | /// <returns></returns> |
@@ -3054,17 +3071,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
3054 | } | 3071 | } |
3055 | 3072 | ||
3056 | m_eventManager.TriggerOnRemovePresence(agentID); | 3073 | m_eventManager.TriggerOnRemovePresence(agentID); |
3057 | Broadcast(delegate(IClientAPI client) | 3074 | ForEachClient( |
3058 | { | 3075 | delegate(IClientAPI client) |
3059 | try | 3076 | { |
3060 | { | 3077 | //We can safely ignore null reference exceptions. It means the avatar is dead and cleaned up anyway |
3061 | client.SendKillObject(avatar.RegionHandle, avatar.LocalId); | 3078 | try { client.SendKillObject(avatar.RegionHandle, avatar.LocalId); } |
3062 | } | 3079 | catch (NullReferenceException) { } |
3063 | catch (NullReferenceException) | 3080 | }); |
3064 | { | ||
3065 | //We can safely ignore null reference exceptions. It means the avatar are dead and cleaned up anyway. | ||
3066 | } | ||
3067 | }); | ||
3068 | 3081 | ||
3069 | ForEachScenePresence( | 3082 | ForEachScenePresence( |
3070 | delegate(ScenePresence presence) { presence.CoarseLocationChange(); }); | 3083 | delegate(ScenePresence presence) { presence.CoarseLocationChange(); }); |
@@ -3149,7 +3162,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3149 | return; | 3162 | return; |
3150 | } | 3163 | } |
3151 | } | 3164 | } |
3152 | Broadcast(delegate(IClientAPI client) { client.SendKillObject(m_regionHandle, localID); }); | 3165 | ForEachClient(delegate(IClientAPI client) { client.SendKillObject(m_regionHandle, localID); }); |
3153 | } | 3166 | } |
3154 | 3167 | ||
3155 | #endregion | 3168 | #endregion |
@@ -4222,7 +4235,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
4222 | 4235 | ||
4223 | public void ForEachClient(Action<IClientAPI> action) | 4236 | public void ForEachClient(Action<IClientAPI> action) |
4224 | { | 4237 | { |
4225 | m_sceneGraph.ForEachClient(action); | 4238 | ClientManager.ForEach(action); |
4226 | } | 4239 | } |
4227 | 4240 | ||
4228 | public void ForEachSOG(Action<SceneObjectGroup> action) | 4241 | public void ForEachSOG(Action<SceneObjectGroup> action) |
diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index 9cd2247..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 | |||
613 | 613 | ||
614 | newAvatar = new ScenePresence(client, m_parentScene, m_regInfo, appearance); | 614 | newAvatar = new ScenePresence(client, m_parentScene, m_regInfo, appearance); |
615 | newAvatar.IsChildAgent = true; | 615 | newAvatar.IsChildAgent = true; |
616 | newAvatar.MaxPrimsPerFrame = m_parentScene.MaxPrimsPerFrame; | ||
617 | 616 | ||
618 | AddScenePresence(newAvatar); | 617 | AddScenePresence(newAvatar); |
619 | 618 | ||
@@ -1107,23 +1106,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
1107 | return UUID.Zero; | 1106 | return UUID.Zero; |
1108 | } | 1107 | } |
1109 | 1108 | ||
1110 | protected internal void ForEachClient(Action<IClientAPI> action) | ||
1111 | { | ||
1112 | List<ScenePresence> splist = GetScenePresences(); | ||
1113 | foreach (ScenePresence presence in splist) | ||
1114 | { | ||
1115 | try | ||
1116 | { | ||
1117 | action(presence.ControllingClient); | ||
1118 | } | ||
1119 | catch (Exception e) | ||
1120 | { | ||
1121 | // Catch it and move on. This includes situations where splist has inconsistent info | ||
1122 | m_log.WarnFormat("[SCENE]: Problem processing action in ForEachClient: ", e.Message); | ||
1123 | } | ||
1124 | } | ||
1125 | } | ||
1126 | |||
1127 | protected internal void ForEachSOG(Action<SceneObjectGroup> action) | 1109 | protected internal void ForEachSOG(Action<SceneObjectGroup> action) |
1128 | { | 1110 | { |
1129 | List<SceneObjectGroup> objlist = new List<SceneObjectGroup>(SceneObjectGroupsByFullID.Values); | 1111 | List<SceneObjectGroup> objlist = new List<SceneObjectGroup>(SceneObjectGroupsByFullID.Values); |
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 | |||
1817 | public void ServiceObjectPropertiesFamilyRequest(IClientAPI remoteClient, UUID AgentID, uint RequestFlags) | 1817 | public void ServiceObjectPropertiesFamilyRequest(IClientAPI remoteClient, UUID AgentID, uint RequestFlags) |
1818 | { | 1818 | { |
1819 | 1819 | ||
1820 | remoteClient.SendObjectPropertiesFamilyData(RequestFlags, RootPart.UUID, RootPart.ObjectOwner, RootPart.GroupID, RootPart.BaseMask, | 1820 | remoteClient.SendObjectPropertiesFamilyData(RequestFlags, RootPart.UUID, RootPart.OwnerID, RootPart.GroupID, RootPart.BaseMask, |
1821 | RootPart.OwnerMask, RootPart.GroupMask, RootPart.EveryoneMask, RootPart.NextOwnerMask, | 1821 | RootPart.OwnerMask, RootPart.GroupMask, RootPart.EveryoneMask, RootPart.NextOwnerMask, |
1822 | RootPart.OwnershipCost, RootPart.ObjectSaleType, RootPart.SalePrice, RootPart.Category, | 1822 | RootPart.OwnershipCost, RootPart.ObjectSaleType, RootPart.SalePrice, RootPart.Category, |
1823 | RootPart.CreatorID, RootPart.Name, RootPart.Description); | 1823 | RootPart.CreatorID, RootPart.Name, RootPart.Description); |
@@ -3343,5 +3343,77 @@ namespace OpenSim.Region.Framework.Scenes | |||
3343 | 3343 | ||
3344 | return true; | 3344 | return true; |
3345 | } | 3345 | } |
3346 | |||
3347 | public double GetUpdatePriority(IClientAPI client) | ||
3348 | { | ||
3349 | switch (Scene.UpdatePrioritizationScheme) | ||
3350 | { | ||
3351 | case Scene.UpdatePrioritizationSchemes.Time: | ||
3352 | return GetPriorityByTime(); | ||
3353 | case Scene.UpdatePrioritizationSchemes.Distance: | ||
3354 | return GetPriorityByDistance(client); | ||
3355 | case Scene.UpdatePrioritizationSchemes.SimpleAngularDistance: | ||
3356 | return GetPriorityBySimpleAngularDistance(client); | ||
3357 | default: | ||
3358 | throw new InvalidOperationException("UpdatePrioritizationScheme not defined"); | ||
3359 | } | ||
3360 | } | ||
3361 | |||
3362 | private double GetPriorityByTime() | ||
3363 | { | ||
3364 | return DateTime.Now.ToOADate(); | ||
3365 | } | ||
3366 | |||
3367 | private double GetPriorityByDistance(IClientAPI client) | ||
3368 | { | ||
3369 | ScenePresence presence = Scene.GetScenePresence(client.AgentId); | ||
3370 | if (presence != null) | ||
3371 | { | ||
3372 | return GetPriorityByDistance((presence.IsChildAgent) ? | ||
3373 | presence.AbsolutePosition : presence.CameraPosition); | ||
3374 | } | ||
3375 | return double.NaN; | ||
3376 | } | ||
3377 | |||
3378 | private double GetPriorityBySimpleAngularDistance(IClientAPI client) | ||
3379 | { | ||
3380 | ScenePresence presence = Scene.GetScenePresence(client.AgentId); | ||
3381 | if (presence != null) | ||
3382 | { | ||
3383 | return GetPriorityBySimpleAngularDistance((presence.IsChildAgent) ? | ||
3384 | presence.AbsolutePosition : presence.CameraPosition); | ||
3385 | } | ||
3386 | return double.NaN; | ||
3387 | } | ||
3388 | |||
3389 | public double GetPriorityByDistance(Vector3 position) | ||
3390 | { | ||
3391 | return Vector3.Distance(AbsolutePosition, position); | ||
3392 | } | ||
3393 | |||
3394 | public double GetPriorityBySimpleAngularDistance(Vector3 position) | ||
3395 | { | ||
3396 | double distance = Vector3.Distance(position, AbsolutePosition); | ||
3397 | if (distance >= double.Epsilon) | ||
3398 | { | ||
3399 | float height; | ||
3400 | Vector3 box = GetAxisAlignedBoundingBox(out height); | ||
3401 | |||
3402 | double angle = box.X / distance; | ||
3403 | double max = angle; | ||
3404 | |||
3405 | angle = box.Y / distance; | ||
3406 | if (max < angle) | ||
3407 | max = angle; | ||
3408 | |||
3409 | angle = box.Z / distance; | ||
3410 | if (max < angle) | ||
3411 | max = angle; | ||
3412 | |||
3413 | return -max; | ||
3414 | } | ||
3415 | else | ||
3416 | return double.MinValue; | ||
3417 | } | ||
3346 | } | 3418 | } |
3347 | } | 3419 | } |
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 801a7db..79f6366 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | |||
@@ -853,16 +853,6 @@ if (m_shape != null) { | |||
853 | return m_offsetPosition + m_groupPosition; } | 853 | return m_offsetPosition + m_groupPosition; } |
854 | } | 854 | } |
855 | 855 | ||
856 | public UUID ObjectCreator | ||
857 | { | ||
858 | get { return _creatorID; } | ||
859 | } | ||
860 | |||
861 | public UUID ObjectOwner | ||
862 | { | ||
863 | get { return _ownerID; } | ||
864 | } | ||
865 | |||
866 | public SceneObjectGroup ParentGroup | 856 | public SceneObjectGroup ParentGroup |
867 | { | 857 | { |
868 | get { return m_parentGroup; } | 858 | get { return m_parentGroup; } |
@@ -1440,7 +1430,7 @@ if (m_shape != null) { | |||
1440 | // Move afterwards ResetIDs as it clears the localID | 1430 | // Move afterwards ResetIDs as it clears the localID |
1441 | dupe.LocalId = localID; | 1431 | dupe.LocalId = localID; |
1442 | // This may be wrong... it might have to be applied in SceneObjectGroup to the object that's being duplicated. | 1432 | // This may be wrong... it might have to be applied in SceneObjectGroup to the object that's being duplicated. |
1443 | dupe._lastOwnerID = ObjectOwner; | 1433 | dupe._lastOwnerID = OwnerID; |
1444 | 1434 | ||
1445 | byte[] extraP = new byte[Shape.ExtraParams.Length]; | 1435 | byte[] extraP = new byte[Shape.ExtraParams.Length]; |
1446 | Array.Copy(Shape.ExtraParams, extraP, extraP.Length); | 1436 | Array.Copy(Shape.ExtraParams, extraP, extraP.Length); |
@@ -2410,10 +2400,10 @@ if (m_shape != null) { | |||
2410 | //isattachment = ParentGroup.RootPart.IsAttachment; | 2400 | //isattachment = ParentGroup.RootPart.IsAttachment; |
2411 | 2401 | ||
2412 | byte[] color = new byte[] {m_color.R, m_color.G, m_color.B, m_color.A}; | 2402 | byte[] color = new byte[] {m_color.R, m_color.G, m_color.B, m_color.A}; |
2413 | remoteClient.SendPrimitiveToClient(m_regionHandle, (ushort)(m_parentGroup.GetTimeDilation() * (float)ushort.MaxValue), LocalId, m_shape, | 2403 | remoteClient.SendPrimitiveToClient(new SendPrimitiveData(m_regionHandle, (ushort)(m_parentGroup.GetTimeDilation() * (float)ushort.MaxValue), LocalId, m_shape, |
2414 | lPos, Velocity, Acceleration, RotationOffset, RotationalVelocity, clientFlags, m_uuid, _ownerID, | 2404 | lPos, Velocity, Acceleration, RotationOffset, RotationalVelocity, clientFlags, m_uuid, _ownerID, |
2415 | m_text, color, _parentID, m_particleSystem, m_clickAction, (byte)m_material, m_TextureAnimation, IsAttachment, | 2405 | m_text, color, _parentID, m_particleSystem, m_clickAction, (byte)m_material, m_TextureAnimation, IsAttachment, |
2416 | AttachmentPoint,FromItemID, Sound, SoundGain, SoundFlags, SoundRadius); | 2406 | AttachmentPoint,FromItemID, Sound, SoundGain, SoundFlags, SoundRadius, ParentGroup.GetUpdatePriority(remoteClient))); |
2417 | } | 2407 | } |
2418 | 2408 | ||
2419 | /// <summary> | 2409 | /// <summary> |
@@ -3804,12 +3794,12 @@ if (m_shape != null) { | |||
3804 | 3794 | ||
3805 | // Causes this thread to dig into the Client Thread Data. | 3795 | // Causes this thread to dig into the Client Thread Data. |
3806 | // Remember your locking here! | 3796 | // Remember your locking here! |
3807 | remoteClient.SendPrimTerseUpdate(m_regionHandle, | 3797 | remoteClient.SendPrimTerseUpdate(new SendPrimitiveTerseData(m_regionHandle, |
3808 | (ushort)(m_parentGroup.GetTimeDilation() * | 3798 | (ushort)(m_parentGroup.GetTimeDilation() * |
3809 | (float)ushort.MaxValue), LocalId, lPos, | 3799 | (float)ushort.MaxValue), LocalId, lPos, |
3810 | RotationOffset, Velocity, | 3800 | RotationOffset, Velocity, |
3811 | RotationalVelocity, state, FromItemID, | 3801 | RotationalVelocity, state, FromItemID, |
3812 | OwnerID, (int)AttachmentPoint); | 3802 | OwnerID, (int)AttachmentPoint, ParentGroup.GetUpdatePriority(remoteClient))); |
3813 | } | 3803 | } |
3814 | 3804 | ||
3815 | public void AddScriptLPS(int count) | 3805 | public void AddScriptLPS(int count) |
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index c25fa55..9d13ad4 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs | |||
@@ -403,12 +403,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
403 | set { m_parentPosition = value; } | 403 | set { m_parentPosition = value; } |
404 | } | 404 | } |
405 | 405 | ||
406 | public int MaxPrimsPerFrame | ||
407 | { | ||
408 | get { return m_sceneViewer.MaxPrimsPerFrame; } | ||
409 | set { m_sceneViewer.MaxPrimsPerFrame = value; } | ||
410 | } | ||
411 | |||
412 | /// <summary> | 406 | /// <summary> |
413 | /// Absolute position of this avatar in 'region cordinates' | 407 | /// Absolute position of this avatar in 'region cordinates' |
414 | /// </summary> | 408 | /// </summary> |
@@ -2456,11 +2450,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
2456 | m_perfMonMS = Environment.TickCount; | 2450 | m_perfMonMS = Environment.TickCount; |
2457 | 2451 | ||
2458 | Vector3 pos = m_pos; | 2452 | Vector3 pos = m_pos; |
2459 | Vector3 vel = Velocity; | ||
2460 | Quaternion rot = m_bodyRot; | ||
2461 | pos.Z -= m_appearance.HipOffset; | 2453 | pos.Z -= m_appearance.HipOffset; |
2462 | remoteClient.SendAvatarTerseUpdate(m_regionHandle, (ushort)(m_scene.TimeDilation * ushort.MaxValue), LocalId, new Vector3(pos.X, pos.Y, pos.Z), | 2454 | |
2463 | new Vector3(vel.X, vel.Y, vel.Z), rot, m_uuid); | 2455 | remoteClient.SendAvatarTerseUpdate(new SendAvatarTerseData(m_regionHandle, (ushort)(m_scene.TimeDilation * ushort.MaxValue), LocalId, |
2456 | pos, m_velocity, m_rotation, m_uuid, GetUpdatePriority(remoteClient))); | ||
2464 | 2457 | ||
2465 | m_scene.StatsReporter.AddAgentTime(Environment.TickCount - m_perfMonMS); | 2458 | m_scene.StatsReporter.AddAgentTime(Environment.TickCount - m_perfMonMS); |
2466 | m_scene.StatsReporter.AddAgentUpdates(1); | 2459 | m_scene.StatsReporter.AddAgentUpdates(1); |
@@ -2474,7 +2467,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2474 | { | 2467 | { |
2475 | m_perfMonMS = Environment.TickCount; | 2468 | m_perfMonMS = Environment.TickCount; |
2476 | 2469 | ||
2477 | m_scene.Broadcast(SendTerseUpdateToClient); | 2470 | m_scene.ForEachClient(SendTerseUpdateToClient); |
2478 | 2471 | ||
2479 | m_lastVelocity = m_velocity; | 2472 | m_lastVelocity = m_velocity; |
2480 | lastPhysPos = AbsolutePosition; | 2473 | lastPhysPos = AbsolutePosition; |
@@ -2566,9 +2559,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
2566 | Vector3 pos = m_pos; | 2559 | Vector3 pos = m_pos; |
2567 | pos.Z -= m_appearance.HipOffset; | 2560 | pos.Z -= m_appearance.HipOffset; |
2568 | 2561 | ||
2569 | remoteAvatar.m_controllingClient.SendAvatarData(m_regionInfo.RegionHandle, m_firstname, m_lastname, m_grouptitle, m_uuid, | 2562 | remoteAvatar.m_controllingClient.SendAvatarData(new SendAvatarData(m_regionInfo.RegionHandle, m_firstname, m_lastname, m_grouptitle, m_uuid, |
2570 | LocalId, m_pos, m_appearance.Texture.GetBytes(), | 2563 | LocalId, m_pos, m_appearance.Texture.GetBytes(), |
2571 | m_parentID, rot); | 2564 | m_parentID, rot)); |
2572 | m_scene.StatsReporter.AddAgentUpdates(1); | 2565 | m_scene.StatsReporter.AddAgentUpdates(1); |
2573 | } | 2566 | } |
2574 | 2567 | ||
@@ -2637,8 +2630,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
2637 | Vector3 pos = m_pos; | 2630 | Vector3 pos = m_pos; |
2638 | pos.Z -= m_appearance.HipOffset; | 2631 | pos.Z -= m_appearance.HipOffset; |
2639 | 2632 | ||
2640 | m_controllingClient.SendAvatarData(m_regionInfo.RegionHandle, m_firstname, m_lastname, m_grouptitle, m_uuid, LocalId, | 2633 | m_controllingClient.SendAvatarData(new SendAvatarData(m_regionInfo.RegionHandle, m_firstname, m_lastname, m_grouptitle, m_uuid, LocalId, |
2641 | m_pos, m_appearance.Texture.GetBytes(), m_parentID, rot); | 2634 | m_pos, m_appearance.Texture.GetBytes(), m_parentID, rot)); |
2642 | 2635 | ||
2643 | if (!m_isChildAgent) | 2636 | if (!m_isChildAgent) |
2644 | { | 2637 | { |
@@ -2744,8 +2737,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
2744 | } | 2737 | } |
2745 | 2738 | ||
2746 | Quaternion rot = m_bodyRot; | 2739 | Quaternion rot = m_bodyRot; |
2747 | m_controllingClient.SendAvatarData(m_regionInfo.RegionHandle, m_firstname, m_lastname, m_grouptitle, m_uuid, LocalId, | 2740 | m_controllingClient.SendAvatarData(new SendAvatarData(m_regionInfo.RegionHandle, m_firstname, m_lastname, m_grouptitle, m_uuid, LocalId, |
2748 | m_pos, m_appearance.Texture.GetBytes(), m_parentID, rot); | 2741 | m_pos, m_appearance.Texture.GetBytes(), m_parentID, rot)); |
2749 | 2742 | ||
2750 | } | 2743 | } |
2751 | 2744 | ||
@@ -2776,7 +2769,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2776 | if (m_isChildAgent) | 2769 | if (m_isChildAgent) |
2777 | return; | 2770 | return; |
2778 | 2771 | ||
2779 | m_scene.Broadcast( | 2772 | m_scene.ForEachClient( |
2780 | delegate(IClientAPI client) { client.SendAnimations(animations, seqs, m_controllingClient.AgentId, objectIDs); }); | 2773 | delegate(IClientAPI client) { client.SendAnimations(animations, seqs, m_controllingClient.AgentId, objectIDs); }); |
2781 | } | 2774 | } |
2782 | 2775 | ||
@@ -3884,5 +3877,41 @@ namespace OpenSim.Region.Framework.Scenes | |||
3884 | } | 3877 | } |
3885 | } | 3878 | } |
3886 | } | 3879 | } |
3880 | |||
3881 | public double GetUpdatePriority(IClientAPI client) | ||
3882 | { | ||
3883 | switch (Scene.UpdatePrioritizationScheme) | ||
3884 | { | ||
3885 | case Scene.UpdatePrioritizationSchemes.Time: | ||
3886 | return GetPriorityByTime(); | ||
3887 | case Scene.UpdatePrioritizationSchemes.Distance: | ||
3888 | return GetPriorityByDistance(client); | ||
3889 | case Scene.UpdatePrioritizationSchemes.SimpleAngularDistance: | ||
3890 | return GetPriorityByDistance(client); | ||
3891 | default: | ||
3892 | throw new InvalidOperationException("UpdatePrioritizationScheme not defined."); | ||
3893 | } | ||
3894 | } | ||
3895 | |||
3896 | private double GetPriorityByTime() | ||
3897 | { | ||
3898 | return DateTime.Now.ToOADate(); | ||
3899 | } | ||
3900 | |||
3901 | private double GetPriorityByDistance(IClientAPI client) | ||
3902 | { | ||
3903 | ScenePresence presence = Scene.GetScenePresence(client.AgentId); | ||
3904 | if (presence != null) | ||
3905 | { | ||
3906 | return GetPriorityByDistance((presence.IsChildAgent) ? | ||
3907 | presence.AbsolutePosition : presence.CameraPosition); | ||
3908 | } | ||
3909 | return double.NaN; | ||
3910 | } | ||
3911 | |||
3912 | private double GetPriorityByDistance(Vector3 position) | ||
3913 | { | ||
3914 | return Vector3.Distance(AbsolutePosition, position); | ||
3915 | } | ||
3887 | } | 3916 | } |
3888 | } | 3917 | } |
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 | |||
45 | 45 | ||
46 | protected Dictionary<UUID, ScenePartUpdate> m_updateTimes = new Dictionary<UUID, ScenePartUpdate>(); | 46 | protected Dictionary<UUID, ScenePartUpdate> m_updateTimes = new Dictionary<UUID, ScenePartUpdate>(); |
47 | 47 | ||
48 | protected int m_maxPrimsPerFrame = 200; | ||
49 | |||
50 | public int MaxPrimsPerFrame | ||
51 | { | ||
52 | get { return m_maxPrimsPerFrame; } | ||
53 | set { m_maxPrimsPerFrame = value; } | ||
54 | } | ||
55 | |||
56 | public SceneViewer() | 48 | public SceneViewer() |
57 | { | 49 | { |
58 | } | 50 | } |
@@ -82,16 +74,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
82 | { | 74 | { |
83 | m_pendingObjects = new Queue<SceneObjectGroup>(); | 75 | m_pendingObjects = new Queue<SceneObjectGroup>(); |
84 | 76 | ||
85 | List<EntityBase> ents = new List<EntityBase>(m_presence.Scene.Entities); | 77 | foreach (EntityBase e in m_presence.Scene.Entities) |
86 | if (!m_presence.IsChildAgent) // Proximity sort makes no sense for | ||
87 | { // Child agents | ||
88 | ents.Sort(delegate(EntityBase a, EntityBase b) | ||
89 | { | ||
90 | return Vector3.Distance(m_presence.AbsolutePosition, a.AbsolutePosition).CompareTo(Vector3.Distance(m_presence.AbsolutePosition, b.AbsolutePosition)); | ||
91 | }); | ||
92 | } | ||
93 | |||
94 | foreach (EntityBase e in ents) | ||
95 | { | 78 | { |
96 | if (e is SceneObjectGroup) | 79 | if (e is SceneObjectGroup) |
97 | m_pendingObjects.Enqueue((SceneObjectGroup)e); | 80 | m_pendingObjects.Enqueue((SceneObjectGroup)e); |
@@ -99,7 +82,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
99 | } | 82 | } |
100 | } | 83 | } |
101 | 84 | ||
102 | while (m_pendingObjects != null && m_pendingObjects.Count > 0 && m_partsUpdateQueue.Count < m_maxPrimsPerFrame) | 85 | while (m_pendingObjects != null && m_pendingObjects.Count > 0) |
103 | { | 86 | { |
104 | SceneObjectGroup g = m_pendingObjects.Dequeue(); | 87 | SceneObjectGroup g = m_pendingObjects.Dequeue(); |
105 | 88 | ||
@@ -183,8 +166,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
183 | m_presence.GenerateClientFlags(part.UUID)); | 166 | m_presence.GenerateClientFlags(part.UUID)); |
184 | } | 167 | } |
185 | } | 168 | } |
186 | |||
187 | m_presence.ControllingClient.FlushPrimUpdates(); | ||
188 | } | 169 | } |
189 | 170 | ||
190 | public void Reset() | 171 | 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 | |||
35 | string Description { get; set; } | 35 | string Description { get; set; } |
36 | 36 | ||
37 | UUID UUID { get; } | 37 | UUID UUID { get; } |
38 | UUID ObjectOwner { get; } | 38 | UUID OwnerID { get; } |
39 | UUID ObjectCreator { get; } | 39 | UUID CreatorID { get; } |
40 | Vector3 AbsolutePosition { get; } | 40 | Vector3 AbsolutePosition { get; } |
41 | 41 | ||
42 | string SitName { get; set; } | 42 | 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 | |||
68 | get { return UUID.Zero; } | 68 | get { return UUID.Zero; } |
69 | } | 69 | } |
70 | 70 | ||
71 | public UUID ObjectOwner | 71 | public UUID OwnerID |
72 | { | 72 | { |
73 | get { return UUID.Zero; } | 73 | get { return UUID.Zero; } |
74 | } | 74 | } |
75 | 75 | ||
76 | public UUID ObjectCreator | 76 | public UUID CreatorID |
77 | { | 77 | { |
78 | get { return UUID.Zero; } | 78 | get { return UUID.Zero; } |
79 | } | 79 | } |
diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs index 434da0a..1a24dec 100644 --- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs +++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs | |||
@@ -1013,12 +1013,12 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server | |||
1013 | 1013 | ||
1014 | } | 1014 | } |
1015 | 1015 | ||
1016 | public void SendAvatarData(ulong regionHandle, string firstName, string lastName, string grouptitle, UUID avatarID, uint avatarLocalID, Vector3 Pos, byte[] textureEntry, uint parentID, Quaternion rotation) | 1016 | public void SendAvatarData(SendAvatarData data) |
1017 | { | 1017 | { |
1018 | 1018 | ||
1019 | } | 1019 | } |
1020 | 1020 | ||
1021 | public void SendAvatarTerseUpdate(ulong regionHandle, ushort timeDilation, uint localID, Vector3 position, Vector3 velocity, Quaternion rotation, UUID agentid) | 1021 | public void SendAvatarTerseUpdate(SendAvatarTerseData data) |
1022 | { | 1022 | { |
1023 | 1023 | ||
1024 | } | 1024 | } |
@@ -1038,17 +1038,12 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server | |||
1038 | 1038 | ||
1039 | } | 1039 | } |
1040 | 1040 | ||
1041 | 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) | 1041 | public void SendPrimitiveToClient(SendPrimitiveData data) |
1042 | { | 1042 | { |
1043 | 1043 | ||
1044 | } | 1044 | } |
1045 | 1045 | ||
1046 | 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) | 1046 | public void SendPrimTerseUpdate(SendPrimitiveTerseData data) |
1047 | { | ||
1048 | |||
1049 | } | ||
1050 | |||
1051 | 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) | ||
1052 | { | 1047 | { |
1053 | 1048 | ||
1054 | } | 1049 | } |
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 | |||
188 | // MISC COMPARISONS (UUID, Byte) | 188 | // MISC COMPARISONS (UUID, Byte) |
189 | if (first.ClickAction != second.ClickAction) | 189 | if (first.ClickAction != second.ClickAction) |
190 | result |= Diff.CLICKACTION; | 190 | result |= Diff.CLICKACTION; |
191 | if (first.ObjectOwner != second.ObjectOwner) | 191 | if (first.OwnerID != second.OwnerID) |
192 | result |= Diff.OBJECTOWNER; | 192 | result |= Diff.OBJECTOWNER; |
193 | 193 | ||
194 | 194 | ||
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 | |||
259 | if (e.InnerException != null) | 259 | if (e.InnerException != null) |
260 | m_log.Error("[MRM] " + e.InnerException); | 260 | m_log.Error("[MRM] " + e.InnerException); |
261 | 261 | ||
262 | m_scene.Broadcast(delegate(IClientAPI user) | 262 | m_scene.ForEachClient(delegate(IClientAPI user) |
263 | { | 263 | { |
264 | user.SendAlertMessage( | 264 | user.SendAlertMessage( |
265 | "MRM UnAuthorizedAccess: " + e); | 265 | "MRM UnAuthorizedAccess: " + e); |
@@ -268,7 +268,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.Minimodule | |||
268 | catch (Exception e) | 268 | catch (Exception e) |
269 | { | 269 | { |
270 | m_log.Info("[MRM] Error: " + e); | 270 | m_log.Info("[MRM] Error: " + e); |
271 | m_scene.Broadcast(delegate(IClientAPI user) | 271 | m_scene.ForEachClient(delegate(IClientAPI user) |
272 | { | 272 | { |
273 | user.SendAlertMessage( | 273 | user.SendAlertMessage( |
274 | "Compile error while building MRM script, check OpenSim console for more information."); | 274 | "Compile error while building MRM script, check OpenSim console for more information."); |
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 | |||
588 | { | 588 | { |
589 | } | 589 | } |
590 | 590 | ||
591 | public virtual void SendAvatarData(ulong regionHandle, string firstName, string lastName, string grouptitle, UUID avatarID, | 591 | public virtual void SendAvatarData(SendAvatarData data) |
592 | uint avatarLocalID, Vector3 Pos, byte[] textureEntry, uint parentID, Quaternion rotation) | ||
593 | { | 592 | { |
594 | } | 593 | } |
595 | 594 | ||
596 | public virtual void SendAvatarTerseUpdate(ulong regionHandle, ushort timeDilation, uint localID, | 595 | public virtual void SendAvatarTerseUpdate(SendAvatarTerseData data) |
597 | Vector3 position, Vector3 velocity, Quaternion rotation, UUID agentId) | ||
598 | { | 596 | { |
599 | } | 597 | } |
600 | 598 | ||
@@ -610,26 +608,11 @@ namespace OpenSim.Region.OptionalModules.World.NPC | |||
610 | { | 608 | { |
611 | } | 609 | } |
612 | 610 | ||
613 | public virtual void SendPrimitiveToClient(ulong regionHandle, ushort timeDilation, uint localID, | 611 | public virtual void SendPrimitiveToClient(SendPrimitiveData data) |
614 | PrimitiveBaseShape primShape, Vector3 pos, Vector3 vel, | ||
615 | Vector3 acc, Quaternion rotation, Vector3 rvel, uint flags, | ||
616 | UUID objectID, UUID ownerID, string text, byte[] color, | ||
617 | uint parentID, | ||
618 | byte[] particleSystem, byte clickAction, byte material) | ||
619 | { | 612 | { |
620 | } | 613 | } |
621 | public virtual void SendPrimitiveToClient(ulong regionHandle, ushort timeDilation, uint localID, | 614 | |
622 | PrimitiveBaseShape primShape, Vector3 pos, Vector3 vel, | 615 | public virtual void SendPrimTerseUpdate(SendPrimitiveTerseData data) |
623 | Vector3 acc, Quaternion rotation, Vector3 rvel, uint flags, | ||
624 | UUID objectID, UUID ownerID, string text, byte[] color, | ||
625 | uint parentID, | ||
626 | byte[] particleSystem, byte clickAction, byte material, byte[] textureanimation, | ||
627 | bool attachment, uint AttachmentPoint, UUID AssetId, UUID SoundId, double SoundVolume, byte SoundFlags, double SoundRadius) | ||
628 | { | ||
629 | } | ||
630 | public virtual void SendPrimTerseUpdate(ulong regionHandle, ushort timeDilation, uint localID, | ||
631 | Vector3 position, Quaternion rotation, Vector3 velocity, | ||
632 | Vector3 rotationalvelocity, byte state, UUID AssetId, UUID ownerID, int attachPoint) | ||
633 | { | 616 | { |
634 | } | 617 | } |
635 | 618 | ||
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 | |||
2875 | { | 2875 | { |
2876 | m_host.AddScriptLPS(1); | 2876 | m_host.AddScriptLPS(1); |
2877 | 2877 | ||
2878 | return m_host.ObjectOwner.ToString(); | 2878 | return m_host.OwnerID.ToString(); |
2879 | } | 2879 | } |
2880 | 2880 | ||
2881 | public void llInstantMessage(string user, string message) | 2881 | public void llInstantMessage(string user, string message) |
@@ -5634,7 +5634,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
5634 | ILandObject parcel = World.LandChannel.GetLandObject(av.AbsolutePosition.X, av.AbsolutePosition.Y); | 5634 | ILandObject parcel = World.LandChannel.GetLandObject(av.AbsolutePosition.X, av.AbsolutePosition.Y); |
5635 | if (parcel != null) | 5635 | if (parcel != null) |
5636 | { | 5636 | { |
5637 | if (m_host.ObjectOwner == parcel.LandData.OwnerID || | 5637 | if (m_host.OwnerID == parcel.LandData.OwnerID || |
5638 | (m_host.OwnerID == m_host.GroupID && m_host.GroupID == parcel.LandData.GroupID | 5638 | (m_host.OwnerID == m_host.GroupID && m_host.GroupID == parcel.LandData.GroupID |
5639 | && parcel.LandData.IsGroupOwned) || World.Permissions.IsGod(m_host.OwnerID)) | 5639 | && parcel.LandData.IsGroupOwned) || World.Permissions.IsGod(m_host.OwnerID)) |
5640 | { | 5640 | { |
@@ -7157,7 +7157,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
7157 | 7157 | ||
7158 | ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); | 7158 | ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); |
7159 | 7159 | ||
7160 | if (land.LandData.OwnerID != m_host.ObjectOwner) | 7160 | if (land.LandData.OwnerID != m_host.OwnerID) |
7161 | return; | 7161 | return; |
7162 | 7162 | ||
7163 | land.SetMusicUrl(url); | 7163 | land.SetMusicUrl(url); |
@@ -7215,7 +7215,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
7215 | public LSL_String llGetCreator() | 7215 | public LSL_String llGetCreator() |
7216 | { | 7216 | { |
7217 | m_host.AddScriptLPS(1); | 7217 | m_host.AddScriptLPS(1); |
7218 | return m_host.ObjectCreator.ToString(); | 7218 | return m_host.CreatorID.ToString(); |
7219 | } | 7219 | } |
7220 | 7220 | ||
7221 | public LSL_String llGetTimestamp() | 7221 | public LSL_String llGetTimestamp() |
@@ -8396,7 +8396,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
8396 | IDialogModule dm = World.RequestModuleInterface<IDialogModule>(); | 8396 | IDialogModule dm = World.RequestModuleInterface<IDialogModule>(); |
8397 | if (null != dm) | 8397 | if (null != dm) |
8398 | dm.SendUrlToUser( | 8398 | dm.SendUrlToUser( |
8399 | new UUID(avatar_id), m_host.Name, m_host.UUID, m_host.ObjectOwner, false, message, url); | 8399 | new UUID(avatar_id), m_host.Name, m_host.UUID, m_host.OwnerID, false, message, url); |
8400 | 8400 | ||
8401 | ConditionalScriptSleep(10000); | 8401 | ConditionalScriptSleep(10000); |
8402 | } | 8402 | } |
@@ -8411,7 +8411,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
8411 | // according to the docs, this command only works if script owner and land owner are the same | 8411 | // according to the docs, this command only works if script owner and land owner are the same |
8412 | // lets add estate owners and gods, too, and use the generic permission check. | 8412 | // lets add estate owners and gods, too, and use the generic permission check. |
8413 | ILandObject landObject = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); | 8413 | ILandObject landObject = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); |
8414 | if (!World.Permissions.CanEditParcel(m_host.ObjectOwner, landObject)) return; | 8414 | if (!World.Permissions.CanEditParcel(m_host.OwnerID, landObject)) return; |
8415 | 8415 | ||
8416 | bool update = false; // send a ParcelMediaUpdate (and possibly change the land's media URL)? | 8416 | bool update = false; // send a ParcelMediaUpdate (and possibly change the land's media URL)? |
8417 | byte loop = 0; | 8417 | byte loop = 0; |
@@ -9081,9 +9081,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
9081 | Vector3 velocity = m_host.Velocity; | 9081 | Vector3 velocity = m_host.Velocity; |
9082 | Quaternion rotation = m_host.RotationOffset; | 9082 | Quaternion rotation = m_host.RotationOffset; |
9083 | string ownerName = String.Empty; | 9083 | string ownerName = String.Empty; |
9084 | ScenePresence scenePresence = World.GetScenePresence(m_host.ObjectOwner); | 9084 | ScenePresence scenePresence = World.GetScenePresence(m_host.OwnerID); |
9085 | if (scenePresence == null) | 9085 | if (scenePresence == null) |
9086 | ownerName = resolveName(m_host.ObjectOwner); | 9086 | ownerName = resolveName(m_host.OwnerID); |
9087 | else | 9087 | else |
9088 | ownerName = scenePresence.Name; | 9088 | ownerName = scenePresence.Name; |
9089 | 9089 | ||
@@ -9108,7 +9108,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
9108 | httpHeaders["X-SecondLife-Local-Velocity"] = string.Format("({0:0.000000}, {1:0.000000}, {2:0.000000})", velocity.X, velocity.Y, velocity.Z); | 9108 | httpHeaders["X-SecondLife-Local-Velocity"] = string.Format("({0:0.000000}, {1:0.000000}, {2:0.000000})", velocity.X, velocity.Y, velocity.Z); |
9109 | 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); | 9109 | 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); |
9110 | httpHeaders["X-SecondLife-Owner-Name"] = ownerName; | 9110 | httpHeaders["X-SecondLife-Owner-Name"] = ownerName; |
9111 | httpHeaders["X-SecondLife-Owner-Key"] = m_host.ObjectOwner.ToString(); | 9111 | httpHeaders["X-SecondLife-Owner-Key"] = m_host.OwnerID.ToString(); |
9112 | string userAgent = config.Configs["Network"].GetString("user_agent", null); | 9112 | string userAgent = config.Configs["Network"].GetString("user_agent", null); |
9113 | if (userAgent != null) | 9113 | if (userAgent != null) |
9114 | httpHeaders["User-Agent"] = userAgent; | 9114 | 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 | |||
1164 | ILandObject land | 1164 | ILandObject land |
1165 | = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); | 1165 | = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); |
1166 | 1166 | ||
1167 | if (land.LandData.OwnerID != m_host.ObjectOwner) | 1167 | if (land.LandData.OwnerID != m_host.OwnerID) |
1168 | return; | 1168 | return; |
1169 | 1169 | ||
1170 | land.SetMediaUrl(url); | 1170 | land.SetMediaUrl(url); |
@@ -1182,7 +1182,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1182 | ILandObject land | 1182 | ILandObject land |
1183 | = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); | 1183 | = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); |
1184 | 1184 | ||
1185 | if (land.LandData.OwnerID != m_host.ObjectOwner) | 1185 | if (land.LandData.OwnerID != m_host.OwnerID) |
1186 | { | 1186 | { |
1187 | OSSLError("osSetParcelSIPAddress: Sorry, you need to own the land to use this function"); | 1187 | OSSLError("osSetParcelSIPAddress: Sorry, you need to own the land to use this function"); |
1188 | return; | 1188 | return; |