diff options
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Client/MXP/ClientStack/MXPClientView.cs | 4 | ||||
-rw-r--r-- | OpenSim/Client/VWoHTTP/ClientStack/VWHClientView.cs | 4 | ||||
-rw-r--r-- | OpenSim/Framework/IClientAPI.cs | 44 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs | 428 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs | 106 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs | 2 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs | 14 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs | 288 | ||||
-rw-r--r-- | OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs | 12 | ||||
-rw-r--r-- | OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | 10 | ||||
-rw-r--r-- | OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 10 | ||||
-rw-r--r-- | OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs | 5 | ||||
-rw-r--r-- | OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs | 12 | ||||
-rw-r--r-- | OpenSim/Tests/Common/Mock/TestClient.cs | 11 |
14 files changed, 538 insertions, 412 deletions
diff --git a/OpenSim/Client/MXP/ClientStack/MXPClientView.cs b/OpenSim/Client/MXP/ClientStack/MXPClientView.cs index 429c548..eebb7eb 100644 --- a/OpenSim/Client/MXP/ClientStack/MXPClientView.cs +++ b/OpenSim/Client/MXP/ClientStack/MXPClientView.cs | |||
@@ -1352,12 +1352,12 @@ namespace OpenSim.Client.MXP.ClientStack | |||
1352 | // Need to translate to MXP somehow | 1352 | // Need to translate to MXP somehow |
1353 | } | 1353 | } |
1354 | 1354 | ||
1355 | public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, uint NextOwnerMask, int OwnershipCost, byte SaleType, int SalePrice, uint Category, UUID LastOwnerID, string ObjectName, string Description) | 1355 | public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags) |
1356 | { | 1356 | { |
1357 | //throw new System.NotImplementedException(); | 1357 | //throw new System.NotImplementedException(); |
1358 | } | 1358 | } |
1359 | 1359 | ||
1360 | public void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID, UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName, string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask, uint BaseMask, byte saleType, int salePrice) | 1360 | public void SendObjectPropertiesReply(ISceneEntity entity) |
1361 | { | 1361 | { |
1362 | //throw new System.NotImplementedException(); | 1362 | //throw new System.NotImplementedException(); |
1363 | } | 1363 | } |
diff --git a/OpenSim/Client/VWoHTTP/ClientStack/VWHClientView.cs b/OpenSim/Client/VWoHTTP/ClientStack/VWHClientView.cs index 6a9fbf3..67a79c3 100644 --- a/OpenSim/Client/VWoHTTP/ClientStack/VWHClientView.cs +++ b/OpenSim/Client/VWoHTTP/ClientStack/VWHClientView.cs | |||
@@ -890,12 +890,12 @@ namespace OpenSim.Client.VWoHTTP.ClientStack | |||
890 | throw new System.NotImplementedException(); | 890 | throw new System.NotImplementedException(); |
891 | } | 891 | } |
892 | 892 | ||
893 | public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, uint NextOwnerMask, int OwnershipCost, byte SaleType, int SalePrice, uint Category, UUID LastOwnerID, string ObjectName, string Description) | 893 | public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags) |
894 | { | 894 | { |
895 | throw new System.NotImplementedException(); | 895 | throw new System.NotImplementedException(); |
896 | } | 896 | } |
897 | 897 | ||
898 | public void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID, UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName, string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask, uint BaseMask, byte saleType, int salePrice) | 898 | public void SendObjectPropertiesReply(ISceneEntity entity) |
899 | { | 899 | { |
900 | throw new System.NotImplementedException(); | 900 | throw new System.NotImplementedException(); |
901 | } | 901 | } |
diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index 2f35a6c..eea9107 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs | |||
@@ -574,16 +574,35 @@ namespace OpenSim.Framework | |||
574 | public float dwell; | 574 | public float dwell; |
575 | } | 575 | } |
576 | 576 | ||
577 | public class EntityUpdate | 577 | public class IEntityUpdate |
578 | { | 578 | { |
579 | public ISceneEntity Entity; | 579 | public ISceneEntity Entity; |
580 | public PrimUpdateFlags Flags; | 580 | public uint Flags; |
581 | public float TimeDilation; | ||
582 | 581 | ||
583 | public EntityUpdate(ISceneEntity entity, PrimUpdateFlags flags, float timedilation) | 582 | public virtual void Update(IEntityUpdate update) |
583 | { | ||
584 | this.Flags |= update.Flags; | ||
585 | } | ||
586 | |||
587 | public IEntityUpdate(ISceneEntity entity, uint flags) | ||
584 | { | 588 | { |
585 | Entity = entity; | 589 | Entity = entity; |
586 | Flags = flags; | 590 | Flags = flags; |
591 | } | ||
592 | } | ||
593 | |||
594 | |||
595 | public class EntityUpdate : IEntityUpdate | ||
596 | { | ||
597 | // public ISceneEntity Entity; | ||
598 | // public PrimUpdateFlags Flags; | ||
599 | public float TimeDilation; | ||
600 | |||
601 | public EntityUpdate(ISceneEntity entity, PrimUpdateFlags flags, float timedilation) | ||
602 | : base(entity,(uint)flags) | ||
603 | { | ||
604 | //Entity = entity; | ||
605 | // Flags = flags; | ||
587 | TimeDilation = timedilation; | 606 | TimeDilation = timedilation; |
588 | } | 607 | } |
589 | } | 608 | } |
@@ -1217,20 +1236,9 @@ namespace OpenSim.Framework | |||
1217 | /// <param name="stats"></param> | 1236 | /// <param name="stats"></param> |
1218 | void SendSimStats(SimStats stats); | 1237 | void SendSimStats(SimStats stats); |
1219 | 1238 | ||
1220 | void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, | 1239 | void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags); |
1221 | uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, | 1240 | |
1222 | uint NextOwnerMask, int OwnershipCost, byte SaleType, int SalePrice, | 1241 | void SendObjectPropertiesReply(ISceneEntity Entity); |
1223 | uint Category, | ||
1224 | UUID LastOwnerID, string ObjectName, string Description); | ||
1225 | |||
1226 | void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, | ||
1227 | UUID FromTaskUUID, | ||
1228 | UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, | ||
1229 | UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, | ||
1230 | string ItemName, | ||
1231 | string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, | ||
1232 | uint EveryoneMask, | ||
1233 | uint BaseMask, byte saleType, int salePrice); | ||
1234 | 1242 | ||
1235 | void SendAgentOffline(UUID[] agentIDs); | 1243 | void SendAgentOffline(UUID[] agentIDs); |
1236 | 1244 | ||
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 1c3ecb2..803114f 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs | |||
@@ -301,77 +301,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
301 | /// <summary>Used to adjust Sun Orbit values so Linden based viewers properly position sun</summary> | 301 | /// <summary>Used to adjust Sun Orbit values so Linden based viewers properly position sun</summary> |
302 | private const float m_sunPainDaHalfOrbitalCutoff = 4.712388980384689858f; | 302 | private const float m_sunPainDaHalfOrbitalCutoff = 4.712388980384689858f; |
303 | 303 | ||
304 | // First log file or time has expired, start writing to a new log file | ||
305 | //<MIC> | ||
306 | // ----------------------------------------------------------------- | ||
307 | // ----------------------------------------------------------------- | ||
308 | // THIS IS DEBUGGING CODE & SHOULD BE REMOVED | ||
309 | // ----------------------------------------------------------------- | ||
310 | // ----------------------------------------------------------------- | ||
311 | public class QueueLogger | ||
312 | { | ||
313 | public Int32 start = 0; | ||
314 | public StreamWriter Log = null; | ||
315 | private Dictionary<UUID,int> m_idMap = new Dictionary<UUID,int>(); | ||
316 | |||
317 | public QueueLogger() | ||
318 | { | ||
319 | DateTime now = DateTime.Now; | ||
320 | String fname = String.Format("queue-{0}.log", now.ToString("yyyyMMddHHmmss")); | ||
321 | Log = new StreamWriter(fname); | ||
322 | |||
323 | start = Util.EnvironmentTickCount(); | ||
324 | } | ||
325 | |||
326 | public int LookupID(UUID uuid) | ||
327 | { | ||
328 | int localid; | ||
329 | if (! m_idMap.TryGetValue(uuid,out localid)) | ||
330 | { | ||
331 | localid = m_idMap.Count + 1; | ||
332 | m_idMap[uuid] = localid; | ||
333 | } | ||
334 | |||
335 | return localid; | ||
336 | } | ||
337 | } | ||
338 | |||
339 | public static QueueLogger QueueLog = null; | ||
340 | |||
341 | // ----------------------------------------------------------------- | ||
342 | public void LogAvatarUpdateEvent(UUID client, UUID avatar, Int32 timeinqueue) | ||
343 | { | ||
344 | if (QueueLog == null) | ||
345 | QueueLog = new QueueLogger(); | ||
346 | |||
347 | Int32 ticks = Util.EnvironmentTickCountSubtract(QueueLog.start); | ||
348 | lock(QueueLog) | ||
349 | { | ||
350 | int cid = QueueLog.LookupID(client); | ||
351 | int aid = QueueLog.LookupID(avatar); | ||
352 | QueueLog.Log.WriteLine("{0},AU,AV{1:D4},AV{2:D4},{3}",ticks,cid,aid,timeinqueue); | ||
353 | } | ||
354 | } | ||
355 | |||
356 | // ----------------------------------------------------------------- | ||
357 | public void LogQueueProcessEvent(UUID client, PriorityQueue queue, uint maxup) | ||
358 | { | ||
359 | if (QueueLog == null) | ||
360 | QueueLog = new QueueLogger(); | ||
361 | |||
362 | Int32 ticks = Util.EnvironmentTickCountSubtract(QueueLog.start); | ||
363 | lock(QueueLog) | ||
364 | { | ||
365 | int cid = QueueLog.LookupID(client); | ||
366 | QueueLog.Log.WriteLine("{0},PQ,AV{1:D4},{2},{3}",ticks,cid,maxup,queue.ToString()); | ||
367 | } | ||
368 | } | ||
369 | // ----------------------------------------------------------------- | ||
370 | // ----------------------------------------------------------------- | ||
371 | // ----------------------------------------------------------------- | ||
372 | // ----------------------------------------------------------------- | ||
373 | //</MIC> | ||
374 | |||
375 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 304 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
376 | protected static Dictionary<PacketType, PacketMethod> PacketHandlers = new Dictionary<PacketType, PacketMethod>(); //Global/static handlers for all clients | 305 | protected static Dictionary<PacketType, PacketMethod> PacketHandlers = new Dictionary<PacketType, PacketMethod>(); //Global/static handlers for all clients |
377 | 306 | ||
@@ -387,6 +316,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
387 | 316 | ||
388 | private int m_cachedTextureSerial; | 317 | private int m_cachedTextureSerial; |
389 | private PriorityQueue m_entityUpdates; | 318 | private PriorityQueue m_entityUpdates; |
319 | private PriorityQueue m_entityProps; | ||
390 | private Prioritizer m_prioritizer; | 320 | private Prioritizer m_prioritizer; |
391 | private bool m_disableFacelights = false; | 321 | private bool m_disableFacelights = false; |
392 | 322 | ||
@@ -435,9 +365,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
435 | protected IAssetService m_assetService; | 365 | protected IAssetService m_assetService; |
436 | private const bool m_checkPackets = true; | 366 | private const bool m_checkPackets = true; |
437 | 367 | ||
438 | private Timer m_propertiesPacketTimer; | ||
439 | private List<ObjectPropertiesPacket.ObjectDataBlock> m_propertiesBlocks = new List<ObjectPropertiesPacket.ObjectDataBlock>(); | ||
440 | |||
441 | #endregion Class Members | 368 | #endregion Class Members |
442 | 369 | ||
443 | #region Properties | 370 | #region Properties |
@@ -521,6 +448,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
521 | m_scene = scene; | 448 | m_scene = scene; |
522 | 449 | ||
523 | m_entityUpdates = new PriorityQueue(m_scene.Entities.Count); | 450 | m_entityUpdates = new PriorityQueue(m_scene.Entities.Count); |
451 | m_entityProps = new PriorityQueue(m_scene.Entities.Count); | ||
524 | m_fullUpdateDataBlocksBuilder = new List<ObjectUpdatePacket.ObjectDataBlock>(); | 452 | m_fullUpdateDataBlocksBuilder = new List<ObjectUpdatePacket.ObjectDataBlock>(); |
525 | m_killRecord = new HashSet<uint>(); | 453 | m_killRecord = new HashSet<uint>(); |
526 | // m_attachmentsSent = new HashSet<uint>(); | 454 | // m_attachmentsSent = new HashSet<uint>(); |
@@ -544,9 +472,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
544 | m_udpClient.OnQueueEmpty += HandleQueueEmpty; | 472 | m_udpClient.OnQueueEmpty += HandleQueueEmpty; |
545 | m_udpClient.OnPacketStats += PopulateStats; | 473 | m_udpClient.OnPacketStats += PopulateStats; |
546 | 474 | ||
547 | m_propertiesPacketTimer = new Timer(100); | ||
548 | m_propertiesPacketTimer.Elapsed += ProcessObjectPropertiesPacket; | ||
549 | |||
550 | m_prioritizer = new Prioritizer(m_scene); | 475 | m_prioritizer = new Prioritizer(m_scene); |
551 | 476 | ||
552 | RegisterLocalPacketHandlers(); | 477 | RegisterLocalPacketHandlers(); |
@@ -2468,7 +2393,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2468 | 2393 | ||
2469 | packet.Effect = effectBlocks; | 2394 | packet.Effect = effectBlocks; |
2470 | 2395 | ||
2471 | OutPacket(packet, ThrottleOutPacketType.State); | 2396 | // OutPacket(packet, ThrottleOutPacketType.State); |
2397 | OutPacket(packet, ThrottleOutPacketType.Task); | ||
2472 | } | 2398 | } |
2473 | 2399 | ||
2474 | public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] charterMember, | 2400 | public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] charterMember, |
@@ -3670,9 +3596,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3670 | m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation)); | 3596 | m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation)); |
3671 | } | 3597 | } |
3672 | 3598 | ||
3673 | private Int32 m_LastQueueFill = 0; | ||
3674 | private uint m_maxUpdates = 0; | ||
3675 | |||
3676 | private void ProcessEntityUpdates(int maxUpdates) | 3599 | private void ProcessEntityUpdates(int maxUpdates) |
3677 | { | 3600 | { |
3678 | OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>(); | 3601 | OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>(); |
@@ -3680,41 +3603,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3680 | OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>(); | 3603 | OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>(); |
3681 | OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>(); | 3604 | OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>(); |
3682 | 3605 | ||
3606 | // Check to see if this is a flush | ||
3683 | if (maxUpdates <= 0) | 3607 | if (maxUpdates <= 0) |
3684 | { | 3608 | { |
3685 | m_maxUpdates = Int32.MaxValue; | 3609 | maxUpdates = Int32.MaxValue; |
3686 | } | ||
3687 | else | ||
3688 | { | ||
3689 | if (m_maxUpdates == 0 || m_LastQueueFill == 0) | ||
3690 | { | ||
3691 | m_maxUpdates = (uint)maxUpdates; | ||
3692 | } | ||
3693 | else | ||
3694 | { | ||
3695 | if (Util.EnvironmentTickCountSubtract(m_LastQueueFill) < 200) | ||
3696 | m_maxUpdates += 5; | ||
3697 | else | ||
3698 | m_maxUpdates = m_maxUpdates >> 1; | ||
3699 | } | ||
3700 | m_maxUpdates = Util.Clamp<uint>(m_maxUpdates,10,500); | ||
3701 | } | 3610 | } |
3702 | m_LastQueueFill = Util.EnvironmentTickCount(); | 3611 | |
3703 | |||
3704 | int updatesThisCall = 0; | 3612 | int updatesThisCall = 0; |
3705 | 3613 | ||
3706 | // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race | 3614 | // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race |
3707 | // condition where a kill can be processed before an out-of-date update for the same object. | 3615 | // condition where a kill can be processed before an out-of-date update for the same object. |
3708 | float avgTimeDilation = 1.0f; | 3616 | float avgTimeDilation = 1.0f; |
3709 | 3617 | IEntityUpdate iupdate; | |
3710 | EntityUpdate update; | ||
3711 | Int32 timeinqueue; // this is just debugging code & can be dropped later | 3618 | Int32 timeinqueue; // this is just debugging code & can be dropped later |
3712 | 3619 | ||
3713 | while (updatesThisCall < m_maxUpdates) | 3620 | while (updatesThisCall < maxUpdates) |
3714 | { | 3621 | { |
3715 | lock (m_entityUpdates.SyncRoot) | 3622 | lock (m_entityUpdates.SyncRoot) |
3716 | if (!m_entityUpdates.TryDequeue(out update, out timeinqueue)) | 3623 | if (!m_entityUpdates.TryDequeue(out iupdate, out timeinqueue)) |
3717 | break; | 3624 | break; |
3625 | |||
3626 | EntityUpdate update = (EntityUpdate)iupdate; | ||
3627 | |||
3718 | avgTimeDilation += update.TimeDilation; | 3628 | avgTimeDilation += update.TimeDilation; |
3719 | avgTimeDilation *= 0.5f; | 3629 | avgTimeDilation *= 0.5f; |
3720 | 3630 | ||
@@ -3770,7 +3680,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3770 | if (!found) | 3680 | if (!found) |
3771 | continue; | 3681 | continue; |
3772 | } | 3682 | } |
3773 | |||
3774 | if (part.ParentGroup.IsAttachment && m_disableFacelights) | 3683 | if (part.ParentGroup.IsAttachment && m_disableFacelights) |
3775 | { | 3684 | { |
3776 | if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand && | 3685 | if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand && |
@@ -3785,7 +3694,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3785 | 3694 | ||
3786 | #region UpdateFlags to packet type conversion | 3695 | #region UpdateFlags to packet type conversion |
3787 | 3696 | ||
3788 | PrimUpdateFlags updateFlags = update.Flags; | 3697 | PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags; |
3789 | 3698 | ||
3790 | bool canUseCompressed = true; | 3699 | bool canUseCompressed = true; |
3791 | bool canUseImproved = true; | 3700 | bool canUseImproved = true; |
@@ -3960,12 +3869,36 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3960 | 3869 | ||
3961 | #endregion Primitive Packet/Data Sending Methods | 3870 | #endregion Primitive Packet/Data Sending Methods |
3962 | 3871 | ||
3872 | // These are used to implement an adaptive backoff in the number | ||
3873 | // of updates converted to packets. Since we don't want packets | ||
3874 | // to sit in the queue with old data, only convert enough updates | ||
3875 | // to packets that can be sent in 200ms. | ||
3876 | private Int32 m_LastQueueFill = 0; | ||
3877 | private Int32 m_maxUpdates = 0; | ||
3878 | |||
3963 | void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories) | 3879 | void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories) |
3964 | { | 3880 | { |
3965 | if ((categories & ThrottleOutPacketTypeFlags.Task) != 0) | 3881 | if ((categories & ThrottleOutPacketTypeFlags.Task) != 0) |
3966 | { | 3882 | { |
3883 | if (m_maxUpdates == 0 || m_LastQueueFill == 0) | ||
3884 | { | ||
3885 | m_maxUpdates = m_udpServer.PrimUpdatesPerCallback; | ||
3886 | } | ||
3887 | else | ||
3888 | { | ||
3889 | if (Util.EnvironmentTickCountSubtract(m_LastQueueFill) < 200) | ||
3890 | m_maxUpdates += 5; | ||
3891 | else | ||
3892 | m_maxUpdates = m_maxUpdates >> 1; | ||
3893 | } | ||
3894 | m_maxUpdates = Util.Clamp<Int32>(m_maxUpdates,10,500); | ||
3895 | m_LastQueueFill = Util.EnvironmentTickCount(); | ||
3896 | |||
3967 | if (m_entityUpdates.Count > 0) | 3897 | if (m_entityUpdates.Count > 0) |
3968 | ProcessEntityUpdates(m_udpServer.PrimUpdatesPerCallback); | 3898 | ProcessEntityUpdates(m_maxUpdates); |
3899 | |||
3900 | if (m_entityProps.Count > 0) | ||
3901 | ProcessEntityPropertyRequests(m_maxUpdates); | ||
3969 | } | 3902 | } |
3970 | 3903 | ||
3971 | if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0) | 3904 | if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0) |
@@ -4079,135 +4012,206 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4079 | OutPacket(pack, ThrottleOutPacketType.Task); | 4012 | OutPacket(pack, ThrottleOutPacketType.Task); |
4080 | } | 4013 | } |
4081 | 4014 | ||
4082 | public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, | 4015 | private class ObjectPropertyUpdate : IEntityUpdate |
4083 | uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, | ||
4084 | uint NextOwnerMask, int OwnershipCost, byte SaleType, int SalePrice, uint Category, | ||
4085 | UUID LastOwnerID, string ObjectName, string Description) | ||
4086 | { | 4016 | { |
4087 | ObjectPropertiesFamilyPacket objPropFamilyPack = (ObjectPropertiesFamilyPacket)PacketPool.Instance.GetPacket(PacketType.ObjectPropertiesFamily); | 4017 | internal bool SendFamilyProps; |
4088 | // TODO: don't create new blocks if recycling an old packet | 4018 | internal bool SendObjectProps; |
4089 | 4019 | ||
4090 | ObjectPropertiesFamilyPacket.ObjectDataBlock objPropDB = new ObjectPropertiesFamilyPacket.ObjectDataBlock(); | 4020 | public ObjectPropertyUpdate(ISceneEntity entity, uint flags, bool sendfam, bool sendobj) |
4091 | objPropDB.RequestFlags = RequestFlags; | 4021 | : base(entity,flags) |
4092 | objPropDB.ObjectID = ObjectUUID; | 4022 | { |
4093 | if (OwnerID == GroupID) | 4023 | SendFamilyProps = sendfam; |
4094 | objPropDB.OwnerID = UUID.Zero; | 4024 | SendObjectProps = sendobj; |
4095 | else | 4025 | } |
4096 | objPropDB.OwnerID = OwnerID; | 4026 | public void Update(ObjectPropertyUpdate update) |
4097 | objPropDB.GroupID = GroupID; | 4027 | { |
4098 | objPropDB.BaseMask = BaseMask; | 4028 | SendFamilyProps = SendFamilyProps || update.SendFamilyProps; |
4099 | objPropDB.OwnerMask = OwnerMask; | 4029 | SendObjectProps = SendObjectProps || update.SendObjectProps; |
4100 | objPropDB.GroupMask = GroupMask; | 4030 | Flags |= update.Flags; |
4101 | objPropDB.EveryoneMask = EveryoneMask; | 4031 | } |
4102 | objPropDB.NextOwnerMask = NextOwnerMask; | 4032 | } |
4103 | 4033 | ||
4104 | // TODO: More properties are needed in SceneObjectPart! | 4034 | public void SendObjectPropertiesFamilyData(ISceneEntity entity, uint requestFlags) |
4105 | objPropDB.OwnershipCost = OwnershipCost; | ||
4106 | objPropDB.SaleType = SaleType; | ||
4107 | objPropDB.SalePrice = SalePrice; | ||
4108 | objPropDB.Category = Category; | ||
4109 | objPropDB.LastOwnerID = LastOwnerID; | ||
4110 | objPropDB.Name = Util.StringToBytes256(ObjectName); | ||
4111 | objPropDB.Description = Util.StringToBytes256(Description); | ||
4112 | objPropFamilyPack.ObjectData = objPropDB; | ||
4113 | objPropFamilyPack.Header.Zerocoded = true; | ||
4114 | OutPacket(objPropFamilyPack, ThrottleOutPacketType.Task); | ||
4115 | } | ||
4116 | |||
4117 | public void SendObjectPropertiesReply( | ||
4118 | UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID, | ||
4119 | UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, | ||
4120 | UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName, | ||
4121 | string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask, | ||
4122 | uint BaseMask, byte saleType, int salePrice) | ||
4123 | { | 4035 | { |
4124 | //ObjectPropertiesPacket proper = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); | 4036 | uint priority = 0; // time based ordering only |
4125 | // TODO: don't create new blocks if recycling an old packet | 4037 | lock (m_entityProps.SyncRoot) |
4038 | m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,requestFlags,true,false)); | ||
4039 | } | ||
4126 | 4040 | ||
4127 | ObjectPropertiesPacket.ObjectDataBlock block = | 4041 | public void SendObjectPropertiesReply(ISceneEntity entity) |
4128 | new ObjectPropertiesPacket.ObjectDataBlock(); | 4042 | { |
4043 | uint priority = 0; // time based ordering only | ||
4044 | lock (m_entityProps.SyncRoot) | ||
4045 | m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,0,false,true)); | ||
4046 | } | ||
4129 | 4047 | ||
4130 | block.ItemID = ItemID; | 4048 | private void ProcessEntityPropertyRequests(int maxUpdates) |
4131 | block.CreationDate = CreationDate; | 4049 | { |
4132 | block.CreatorID = CreatorUUID; | 4050 | OpenSim.Framework.Lazy<List<ObjectPropertiesFamilyPacket.ObjectDataBlock>> objectFamilyBlocks = |
4133 | block.FolderID = FolderUUID; | 4051 | new OpenSim.Framework.Lazy<List<ObjectPropertiesFamilyPacket.ObjectDataBlock>>(); |
4134 | block.FromTaskID = FromTaskUUID; | ||
4135 | block.GroupID = GroupUUID; | ||
4136 | block.InventorySerial = InventorySerial; | ||
4137 | 4052 | ||
4138 | block.LastOwnerID = LastOwnerUUID; | 4053 | OpenSim.Framework.Lazy<List<ObjectPropertiesPacket.ObjectDataBlock>> objectPropertiesBlocks = |
4139 | // proper.ObjectData[0].LastOwnerID = UUID.Zero; | 4054 | new OpenSim.Framework.Lazy<List<ObjectPropertiesPacket.ObjectDataBlock>>(); |
4140 | 4055 | ||
4141 | block.ObjectID = ObjectUUID; | 4056 | IEntityUpdate iupdate; |
4142 | if (OwnerUUID == GroupUUID) | 4057 | Int32 timeinqueue; // this is just debugging code & can be dropped later |
4143 | block.OwnerID = UUID.Zero; | ||
4144 | else | ||
4145 | block.OwnerID = OwnerUUID; | ||
4146 | block.TouchName = Util.StringToBytes256(TouchTitle); | ||
4147 | block.TextureID = TextureID; | ||
4148 | block.SitName = Util.StringToBytes256(SitTitle); | ||
4149 | block.Name = Util.StringToBytes256(ItemName); | ||
4150 | block.Description = Util.StringToBytes256(ItemDescription); | ||
4151 | block.OwnerMask = OwnerMask; | ||
4152 | block.NextOwnerMask = NextOwnerMask; | ||
4153 | block.GroupMask = GroupMask; | ||
4154 | block.EveryoneMask = EveryoneMask; | ||
4155 | block.BaseMask = BaseMask; | ||
4156 | // proper.ObjectData[0].AggregatePerms = 53; | ||
4157 | // proper.ObjectData[0].AggregatePermTextures = 0; | ||
4158 | // proper.ObjectData[0].AggregatePermTexturesOwner = 0; | ||
4159 | block.SaleType = saleType; | ||
4160 | block.SalePrice = salePrice; | ||
4161 | 4058 | ||
4162 | lock (m_propertiesPacketTimer) | 4059 | int updatesThisCall = 0; |
4060 | while (updatesThisCall < m_maxUpdates) | ||
4163 | { | 4061 | { |
4164 | m_propertiesBlocks.Add(block); | 4062 | lock (m_entityProps.SyncRoot) |
4063 | if (!m_entityProps.TryDequeue(out iupdate, out timeinqueue)) | ||
4064 | break; | ||
4165 | 4065 | ||
4166 | int length = 0; | 4066 | ObjectPropertyUpdate update = (ObjectPropertyUpdate)iupdate; |
4167 | foreach (ObjectPropertiesPacket.ObjectDataBlock b in m_propertiesBlocks) | 4067 | if (update.SendFamilyProps) |
4168 | { | 4068 | { |
4169 | length += b.Length; | 4069 | if (update.Entity is SceneObjectPart) |
4070 | { | ||
4071 | SceneObjectPart sop = (SceneObjectPart)update.Entity; | ||
4072 | ObjectPropertiesFamilyPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesFamilyBlock(sop,update.Flags); | ||
4073 | objectFamilyBlocks.Value.Add(objPropDB); | ||
4074 | } | ||
4170 | } | 4075 | } |
4171 | if (length > 1100) // FIXME: use real MTU | 4076 | |
4077 | if (update.SendObjectProps) | ||
4172 | { | 4078 | { |
4173 | ProcessObjectPropertiesPacket(null, null); | 4079 | if (update.Entity is SceneObjectPart) |
4174 | m_propertiesPacketTimer.Stop(); | 4080 | { |
4175 | return; | 4081 | SceneObjectPart sop = (SceneObjectPart)update.Entity; |
4082 | ObjectPropertiesPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesBlock(sop); | ||
4083 | objectPropertiesBlocks.Value.Add(objPropDB); | ||
4084 | } | ||
4176 | } | 4085 | } |
4177 | 4086 | ||
4178 | m_propertiesPacketTimer.Stop(); | 4087 | updatesThisCall++; |
4179 | m_propertiesPacketTimer.Start(); | ||
4180 | } | 4088 | } |
4089 | |||
4181 | 4090 | ||
4182 | //proper.Header.Zerocoded = true; | 4091 | Int32 ppcnt = 0; |
4183 | //OutPacket(proper, ThrottleOutPacketType.Task); | 4092 | Int32 pbcnt = 0; |
4184 | } | 4093 | |
4094 | if (objectPropertiesBlocks.IsValueCreated) | ||
4095 | { | ||
4096 | List<ObjectPropertiesPacket.ObjectDataBlock> blocks = objectPropertiesBlocks.Value; | ||
4185 | 4097 | ||
4186 | private void ProcessObjectPropertiesPacket(Object sender, ElapsedEventArgs e) | 4098 | ObjectPropertiesPacket packet = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); |
4187 | { | 4099 | packet.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[blocks.Count]; |
4188 | ObjectPropertiesPacket proper = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); | 4100 | for (int i = 0; i < blocks.Count; i++) |
4101 | packet.ObjectData[i] = blocks[i]; | ||
4189 | 4102 | ||
4190 | lock (m_propertiesPacketTimer) | 4103 | packet.Header.Zerocoded = true; |
4104 | OutPacket(packet, ThrottleOutPacketType.Task, true); | ||
4105 | |||
4106 | pbcnt += blocks.Count; | ||
4107 | ppcnt++; | ||
4108 | } | ||
4109 | |||
4110 | Int32 fpcnt = 0; | ||
4111 | Int32 fbcnt = 0; | ||
4112 | |||
4113 | if (objectFamilyBlocks.IsValueCreated) | ||
4191 | { | 4114 | { |
4192 | m_propertiesPacketTimer.Stop(); | 4115 | List<ObjectPropertiesFamilyPacket.ObjectDataBlock> blocks = objectFamilyBlocks.Value; |
4193 | 4116 | ||
4194 | if (m_propertiesBlocks.Count == 0) | 4117 | // ObjectPropertiesFamilyPacket objPropFamilyPack = |
4195 | return; | 4118 | // (ObjectPropertiesFamilyPacket)PacketPool.Instance.GetPacket(PacketType.ObjectPropertiesFamily); |
4119 | // | ||
4120 | // objPropFamilyPack.ObjectData = new ObjectPropertiesFamilyPacket.ObjectDataBlock[blocks.Count]; | ||
4121 | // for (int i = 0; i < blocks.Count; i++) | ||
4122 | // objPropFamilyPack.ObjectData[i] = blocks[i]; | ||
4123 | // | ||
4124 | // OutPacket(objPropFamilyPack, ThrottleOutPacketType.Task, true); | ||
4196 | 4125 | ||
4197 | proper.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[m_propertiesBlocks.Count]; | 4126 | // one packet per object block... uggh... |
4127 | for (int i = 0; i < blocks.Count; i++) | ||
4128 | { | ||
4129 | ObjectPropertiesFamilyPacket packet = | ||
4130 | (ObjectPropertiesFamilyPacket)PacketPool.Instance.GetPacket(PacketType.ObjectPropertiesFamily); | ||
4198 | 4131 | ||
4199 | int index = 0; | 4132 | packet.ObjectData = blocks[i]; |
4133 | packet.Header.Zerocoded = true; | ||
4134 | OutPacket(packet, ThrottleOutPacketType.Task); | ||
4200 | 4135 | ||
4201 | foreach (ObjectPropertiesPacket.ObjectDataBlock b in m_propertiesBlocks) | 4136 | fpcnt++; |
4202 | { | 4137 | fbcnt++; |
4203 | proper.ObjectData[index++] = b; | ||
4204 | } | 4138 | } |
4205 | 4139 | ||
4206 | m_propertiesBlocks.Clear(); | ||
4207 | } | 4140 | } |
4141 | |||
4142 | // m_log.WarnFormat("[PACKETCOUNTS] queued {0} property packets with {1} blocks",ppcnt,pbcnt); | ||
4143 | // m_log.WarnFormat("[PACKETCOUNTS] queued {0} family property packets with {1} blocks",fpcnt,fbcnt); | ||
4144 | } | ||
4145 | |||
4146 | private ObjectPropertiesFamilyPacket.ObjectDataBlock CreateObjectPropertiesFamilyBlock(SceneObjectPart sop, uint requestFlags) | ||
4147 | { | ||
4148 | ObjectPropertiesFamilyPacket.ObjectDataBlock block = new ObjectPropertiesFamilyPacket.ObjectDataBlock(); | ||
4208 | 4149 | ||
4209 | proper.Header.Zerocoded = true; | 4150 | block.RequestFlags = requestFlags; |
4210 | OutPacket(proper, ThrottleOutPacketType.Task); | 4151 | block.ObjectID = sop.UUID; |
4152 | if (sop.OwnerID == sop.GroupID) | ||
4153 | block.OwnerID = UUID.Zero; | ||
4154 | else | ||
4155 | block.OwnerID = sop.OwnerID; | ||
4156 | block.GroupID = sop.GroupID; | ||
4157 | block.BaseMask = sop.BaseMask; | ||
4158 | block.OwnerMask = sop.OwnerMask; | ||
4159 | block.GroupMask = sop.GroupMask; | ||
4160 | block.EveryoneMask = sop.EveryoneMask; | ||
4161 | block.NextOwnerMask = sop.NextOwnerMask; | ||
4162 | |||
4163 | // TODO: More properties are needed in SceneObjectPart! | ||
4164 | block.OwnershipCost = sop.OwnershipCost; | ||
4165 | block.SaleType = sop.ObjectSaleType; | ||
4166 | block.SalePrice = sop.SalePrice; | ||
4167 | block.Category = sop.Category; | ||
4168 | block.LastOwnerID = sop.CreatorID; // copied from old SOG call... is this right? | ||
4169 | block.Name = Util.StringToBytes256(sop.Name); | ||
4170 | block.Description = Util.StringToBytes256(sop.Description); | ||
4171 | |||
4172 | return block; | ||
4173 | } | ||
4174 | |||
4175 | private ObjectPropertiesPacket.ObjectDataBlock CreateObjectPropertiesBlock(SceneObjectPart sop) | ||
4176 | { | ||
4177 | //ObjectPropertiesPacket proper = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); | ||
4178 | // TODO: don't create new blocks if recycling an old packet | ||
4179 | |||
4180 | ObjectPropertiesPacket.ObjectDataBlock block = | ||
4181 | new ObjectPropertiesPacket.ObjectDataBlock(); | ||
4182 | |||
4183 | block.ObjectID = sop.UUID; | ||
4184 | block.Name = Util.StringToBytes256(sop.Name); | ||
4185 | block.Description = Util.StringToBytes256(sop.Description); | ||
4186 | |||
4187 | block.CreationDate = (ulong)sop.CreationDate * 1000000; // viewer wants date in microseconds | ||
4188 | block.CreatorID = sop.CreatorID; | ||
4189 | block.GroupID = sop.GroupID; | ||
4190 | block.LastOwnerID = sop.LastOwnerID; | ||
4191 | if (sop.OwnerID == sop.GroupID) | ||
4192 | block.OwnerID = UUID.Zero; | ||
4193 | else | ||
4194 | block.OwnerID = sop.OwnerID; | ||
4195 | |||
4196 | block.ItemID = sop.FromUserInventoryItemID; | ||
4197 | block.FolderID = UUID.Zero; // sop.FromFolderID ?? | ||
4198 | block.FromTaskID = UUID.Zero; // ??? | ||
4199 | block.InventorySerial = (short)sop.InventorySerial; | ||
4200 | |||
4201 | SceneObjectPart root = sop.ParentGroup.RootPart; | ||
4202 | |||
4203 | block.TouchName = Util.StringToBytes256(root.TouchName); | ||
4204 | block.TextureID = new byte[0]; // TextureID ??? | ||
4205 | block.SitName = Util.StringToBytes256(root.SitName); | ||
4206 | block.OwnerMask = root.OwnerMask; | ||
4207 | block.NextOwnerMask = root.NextOwnerMask; | ||
4208 | block.GroupMask = root.GroupMask; | ||
4209 | block.EveryoneMask = root.EveryoneMask; | ||
4210 | block.BaseMask = root.BaseMask; | ||
4211 | block.SaleType = root.ObjectSaleType; | ||
4212 | block.SalePrice = root.SalePrice; | ||
4213 | |||
4214 | return block; | ||
4211 | } | 4215 | } |
4212 | 4216 | ||
4213 | #region Estate Data Sending Methods | 4217 | #region Estate Data Sending Methods |
@@ -4548,6 +4552,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4548 | 4552 | ||
4549 | public void SendForceClientSelectObjects(List<uint> ObjectIDs) | 4553 | public void SendForceClientSelectObjects(List<uint> ObjectIDs) |
4550 | { | 4554 | { |
4555 | m_log.WarnFormat("[LLCLIENTVIEW] sending select with {0} objects", ObjectIDs.Count); | ||
4556 | |||
4551 | bool firstCall = true; | 4557 | bool firstCall = true; |
4552 | const int MAX_OBJECTS_PER_PACKET = 251; | 4558 | const int MAX_OBJECTS_PER_PACKET = 251; |
4553 | ForceObjectSelectPacket pack = (ForceObjectSelectPacket)PacketPool.Instance.GetPacket(PacketType.ForceObjectSelect); | 4559 | ForceObjectSelectPacket pack = (ForceObjectSelectPacket)PacketPool.Instance.GetPacket(PacketType.ForceObjectSelect); |
@@ -11491,7 +11497,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11491 | if (logPacket) | 11497 | if (logPacket) |
11492 | m_log.DebugFormat("[CLIENT]: Packet OUT {0}", packet.Type); | 11498 | m_log.DebugFormat("[CLIENT]: Packet OUT {0}", packet.Type); |
11493 | } | 11499 | } |
11494 | 11500 | ||
11495 | m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting); | 11501 | m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting); |
11496 | } | 11502 | } |
11497 | 11503 | ||
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs index 0fa074d..01d7122 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs | |||
@@ -135,7 +135,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
135 | private int m_nextOnQueueEmpty = 1; | 135 | private int m_nextOnQueueEmpty = 1; |
136 | 136 | ||
137 | /// <summary>Throttle bucket for this agent's connection</summary> | 137 | /// <summary>Throttle bucket for this agent's connection</summary> |
138 | private readonly TokenBucket m_throttle; | 138 | private readonly TokenBucket m_throttleClient; |
139 | /// <summary>Throttle bucket for this agent's connection</summary> | ||
140 | private readonly TokenBucket m_throttleCategory; | ||
139 | /// <summary>Throttle buckets for each packet category</summary> | 141 | /// <summary>Throttle buckets for each packet category</summary> |
140 | private readonly TokenBucket[] m_throttleCategories; | 142 | private readonly TokenBucket[] m_throttleCategories; |
141 | /// <summary>Outgoing queues for throttled packets</summary> | 143 | /// <summary>Outgoing queues for throttled packets</summary> |
@@ -175,7 +177,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
175 | m_maxRTO = maxRTO; | 177 | m_maxRTO = maxRTO; |
176 | 178 | ||
177 | // Create a token bucket throttle for this client that has the scene token bucket as a parent | 179 | // Create a token bucket throttle for this client that has the scene token bucket as a parent |
178 | m_throttle = new TokenBucket(parentThrottle, rates.TotalLimit, rates.Total); | 180 | m_throttleClient = new TokenBucket(parentThrottle, rates.TotalLimit); |
181 | // Create a token bucket throttle for the total categary with the client bucket as a throttle | ||
182 | m_throttleCategory = new TokenBucket(m_throttleClient, rates.TotalLimit); | ||
179 | // Create an array of token buckets for this clients different throttle categories | 183 | // Create an array of token buckets for this clients different throttle categories |
180 | m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; | 184 | m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; |
181 | 185 | ||
@@ -186,7 +190,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
186 | // Initialize the packet outboxes, where packets sit while they are waiting for tokens | 190 | // Initialize the packet outboxes, where packets sit while they are waiting for tokens |
187 | m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>(); | 191 | m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>(); |
188 | // Initialize the token buckets that control the throttling for each category | 192 | // Initialize the token buckets that control the throttling for each category |
189 | m_throttleCategories[i] = new TokenBucket(m_throttle, rates.GetLimit(type), rates.GetRate(type)); | 193 | m_throttleCategories[i] = new TokenBucket(m_throttleCategory, rates.GetLimit(type)); |
190 | } | 194 | } |
191 | 195 | ||
192 | // Default the retransmission timeout to three seconds | 196 | // Default the retransmission timeout to three seconds |
@@ -207,6 +211,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
207 | m_packetOutboxes[i].Clear(); | 211 | m_packetOutboxes[i].Clear(); |
208 | m_nextPackets[i] = null; | 212 | m_nextPackets[i] = null; |
209 | } | 213 | } |
214 | |||
215 | // pull the throttle out of the scene throttle | ||
216 | m_throttleClient.Parent.UnregisterRequest(m_throttleClient); | ||
210 | OnPacketStats = null; | 217 | OnPacketStats = null; |
211 | OnQueueEmpty = null; | 218 | OnQueueEmpty = null; |
212 | } | 219 | } |
@@ -217,6 +224,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
217 | /// <returns>Information about the client connection</returns> | 224 | /// <returns>Information about the client connection</returns> |
218 | public ClientInfo GetClientInfo() | 225 | public ClientInfo GetClientInfo() |
219 | { | 226 | { |
227 | ///<mic> | ||
228 | TokenBucket tb; | ||
229 | |||
230 | tb = m_throttleClient.Parent; | ||
231 | m_log.WarnFormat("[TOKENS] {3}: Actual={0},Request={1},TotalRequest={2}",tb.DripRate,tb.RequestedDripRate,tb.TotalDripRequest,"ROOT"); | ||
232 | |||
233 | tb = m_throttleClient; | ||
234 | m_log.WarnFormat("[TOKENS] {3}: Actual={0},Request={1},TotalRequest={2}",tb.DripRate,tb.RequestedDripRate,tb.TotalDripRequest," CLIENT"); | ||
235 | |||
236 | tb = m_throttleCategory; | ||
237 | m_log.WarnFormat("[TOKENS] {3}: Actual={0},Request={1},TotalRequest={2}",tb.DripRate,tb.RequestedDripRate,tb.TotalDripRequest," CATEGORY"); | ||
238 | |||
239 | for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) | ||
240 | { | ||
241 | tb = m_throttleCategories[i]; | ||
242 | m_log.WarnFormat("[TOKENS] {4} <{0}:{1}>: Actual={2},Requested={3}",AgentID,i,tb.DripRate,tb.RequestedDripRate," BUCKET"); | ||
243 | } | ||
244 | |||
245 | ///</mic> | ||
246 | |||
220 | // TODO: This data structure is wrong in so many ways. Locking and copying the entire lists | 247 | // TODO: This data structure is wrong in so many ways. Locking and copying the entire lists |
221 | // of pending and needed ACKs for every client every time some method wants information about | 248 | // of pending and needed ACKs for every client every time some method wants information about |
222 | // this connection is a recipe for poor performance | 249 | // this connection is a recipe for poor performance |
@@ -224,13 +251,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
224 | info.pendingAcks = new Dictionary<uint, uint>(); | 251 | info.pendingAcks = new Dictionary<uint, uint>(); |
225 | info.needAck = new Dictionary<uint, byte[]>(); | 252 | info.needAck = new Dictionary<uint, byte[]>(); |
226 | 253 | ||
227 | info.resendThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate; | 254 | info.resendThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate; |
228 | info.landThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; | 255 | info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; |
229 | info.windThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; | 256 | info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; |
230 | info.cloudThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; | 257 | info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; |
231 | info.taskThrottle = m_throttleCategories[(int)ThrottleOutPacketType.State].DripRate + m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; | 258 | // info.taskThrottle = m_throttleCategories[(int)ThrottleOutPacketType.State].DripRate + m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; |
232 | info.assetThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; | 259 | info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; |
233 | info.textureThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; | 260 | info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; |
261 | info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; | ||
234 | info.totalThrottle = info.resendThrottle + info.landThrottle + info.windThrottle + info.cloudThrottle + | 262 | info.totalThrottle = info.resendThrottle + info.landThrottle + info.windThrottle + info.cloudThrottle + |
235 | info.taskThrottle + info.assetThrottle + info.textureThrottle; | 263 | info.taskThrottle + info.assetThrottle + info.textureThrottle; |
236 | 264 | ||
@@ -318,8 +346,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
318 | int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; | 346 | int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; |
319 | int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); | 347 | int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); |
320 | // State is a subcategory of task that we allocate a percentage to | 348 | // State is a subcategory of task that we allocate a percentage to |
321 | int state = (int)((float)task * STATE_TASK_PERCENTAGE); | 349 | int state = 0; |
322 | task -= state; | 350 | // int state = (int)((float)task * STATE_TASK_PERCENTAGE); |
351 | // task -= state; | ||
323 | 352 | ||
324 | // Make sure none of the throttles are set below our packet MTU, | 353 | // Make sure none of the throttles are set below our packet MTU, |
325 | // otherwise a throttle could become permanently clogged | 354 | // otherwise a throttle could become permanently clogged |
@@ -340,40 +369,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
340 | // Update the token buckets with new throttle values | 369 | // Update the token buckets with new throttle values |
341 | TokenBucket bucket; | 370 | TokenBucket bucket; |
342 | 371 | ||
343 | bucket = m_throttle; | 372 | bucket = m_throttleCategory; |
344 | bucket.MaxBurst = total; | 373 | bucket.RequestedDripRate = total; |
345 | 374 | ||
346 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend]; | 375 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend]; |
347 | bucket.DripRate = resend; | 376 | bucket.RequestedDripRate = resend; |
348 | bucket.MaxBurst = resend; | ||
349 | 377 | ||
350 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land]; | 378 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land]; |
351 | bucket.DripRate = land; | 379 | bucket.RequestedDripRate = land; |
352 | bucket.MaxBurst = land; | ||
353 | 380 | ||
354 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind]; | 381 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind]; |
355 | bucket.DripRate = wind; | 382 | bucket.RequestedDripRate = wind; |
356 | bucket.MaxBurst = wind; | ||
357 | 383 | ||
358 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud]; | 384 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud]; |
359 | bucket.DripRate = cloud; | 385 | bucket.RequestedDripRate = cloud; |
360 | bucket.MaxBurst = cloud; | ||
361 | 386 | ||
362 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset]; | 387 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset]; |
363 | bucket.DripRate = asset; | 388 | bucket.RequestedDripRate = asset; |
364 | bucket.MaxBurst = asset; | ||
365 | 389 | ||
366 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task]; | 390 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task]; |
367 | bucket.DripRate = task + state; | 391 | bucket.RequestedDripRate = task; |
368 | bucket.MaxBurst = task + state; | ||
369 | 392 | ||
370 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.State]; | 393 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.State]; |
371 | bucket.DripRate = state; | 394 | bucket.RequestedDripRate = state; |
372 | bucket.MaxBurst = state; | ||
373 | 395 | ||
374 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture]; | 396 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture]; |
375 | bucket.DripRate = texture; | 397 | bucket.RequestedDripRate = texture; |
376 | bucket.MaxBurst = texture; | ||
377 | 398 | ||
378 | // Reset the packed throttles cached data | 399 | // Reset the packed throttles cached data |
379 | m_packedThrottles = null; | 400 | m_packedThrottles = null; |
@@ -388,14 +409,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
388 | data = new byte[7 * 4]; | 409 | data = new byte[7 * 4]; |
389 | int i = 0; | 410 | int i = 0; |
390 | 411 | ||
391 | Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate), 0, data, i, 4); i += 4; | 412 | Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].RequestedDripRate), 0, data, i, 4); i += 4; |
392 | Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate), 0, data, i, 4); i += 4; | 413 | Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Land].RequestedDripRate), 0, data, i, 4); i += 4; |
393 | Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate), 0, data, i, 4); i += 4; | 414 | Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].RequestedDripRate), 0, data, i, 4); i += 4; |
394 | Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate), 0, data, i, 4); i += 4; | 415 | Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].RequestedDripRate), 0, data, i, 4); i += 4; |
395 | Buffer.BlockCopy(Utils.FloatToBytes((float)(m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate) + | 416 | Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Task].RequestedDripRate), 0, data, i, 4); i += 4; |
396 | m_throttleCategories[(int)ThrottleOutPacketType.State].DripRate), 0, data, i, 4); i += 4; | 417 | Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].RequestedDripRate), 0, data, i, 4); i += 4; |
397 | Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate), 0, data, i, 4); i += 4; | 418 | Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].RequestedDripRate), 0, data, i, 4); i += 4; |
398 | Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate), 0, data, i, 4); i += 4; | ||
399 | 419 | ||
400 | m_packedThrottles = data; | 420 | m_packedThrottles = data; |
401 | } | 421 | } |
@@ -428,6 +448,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
428 | 448 | ||
429 | TokenBucket bucket = m_throttleCategories[category]; | 449 | TokenBucket bucket = m_throttleCategories[category]; |
430 | 450 | ||
451 | // Don't send this packet if there is already a packet waiting in the queue | ||
452 | // even if we have the tokens to send it, tokens should go to the already | ||
453 | // queued packets | ||
454 | if (queue.Count > 0) | ||
455 | { | ||
456 | queue.Enqueue(packet); | ||
457 | return true; | ||
458 | } | ||
459 | |||
460 | |||
431 | if (!forceQueue && bucket.RemoveTokens(packet.Buffer.DataLength)) | 461 | if (!forceQueue && bucket.RemoveTokens(packet.Buffer.DataLength)) |
432 | { | 462 | { |
433 | // Enough tokens were removed from the bucket, the packet will not be queued | 463 | // Enough tokens were removed from the bucket, the packet will not be queued |
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index c865c0f..6decc7b 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs | |||
@@ -228,7 +228,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
228 | } | 228 | } |
229 | #endregion BinaryStats | 229 | #endregion BinaryStats |
230 | 230 | ||
231 | m_throttle = new TokenBucket(null, sceneThrottleBps, sceneThrottleBps); | 231 | m_throttle = new TokenBucket(null, sceneThrottleBps); |
232 | ThrottleRates = new ThrottleRates(configSource); | 232 | ThrottleRates = new ThrottleRates(configSource); |
233 | } | 233 | } |
234 | 234 | ||
diff --git a/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs b/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs index 364ce4b..b62ec07 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs | |||
@@ -78,7 +78,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
78 | } | 78 | } |
79 | } | 79 | } |
80 | 80 | ||
81 | public bool Enqueue(uint pqueue, EntityUpdate value) | 81 | public bool Enqueue(uint pqueue, IEntityUpdate value) |
82 | { | 82 | { |
83 | LookupItem lookup; | 83 | LookupItem lookup; |
84 | 84 | ||
@@ -87,7 +87,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
87 | if (m_lookupTable.TryGetValue(localid, out lookup)) | 87 | if (m_lookupTable.TryGetValue(localid, out lookup)) |
88 | { | 88 | { |
89 | entry = lookup.Heap[lookup.Handle].EntryOrder; | 89 | entry = lookup.Heap[lookup.Handle].EntryOrder; |
90 | value.Flags |= lookup.Heap[lookup.Handle].Value.Flags; | 90 | value.Update(lookup.Heap[lookup.Handle].Value); |
91 | lookup.Heap.Remove(lookup.Handle); | 91 | lookup.Heap.Remove(lookup.Handle); |
92 | } | 92 | } |
93 | 93 | ||
@@ -99,7 +99,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
99 | return true; | 99 | return true; |
100 | } | 100 | } |
101 | 101 | ||
102 | internal bool TryDequeue(out EntityUpdate value, out Int32 timeinqueue) | 102 | internal bool TryDequeue(out IEntityUpdate value, out Int32 timeinqueue) |
103 | { | 103 | { |
104 | for (int i = 0; i < m_numberOfQueues; ++i) | 104 | for (int i = 0; i < m_numberOfQueues; ++i) |
105 | { | 105 | { |
@@ -122,7 +122,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
122 | } | 122 | } |
123 | 123 | ||
124 | timeinqueue = 0; | 124 | timeinqueue = 0; |
125 | value = default(EntityUpdate); | 125 | value = default(IEntityUpdate); |
126 | return false; | 126 | return false; |
127 | } | 127 | } |
128 | 128 | ||
@@ -175,8 +175,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
175 | #region MinHeapItem | 175 | #region MinHeapItem |
176 | private struct MinHeapItem : IComparable<MinHeapItem> | 176 | private struct MinHeapItem : IComparable<MinHeapItem> |
177 | { | 177 | { |
178 | private EntityUpdate value; | 178 | private IEntityUpdate value; |
179 | internal EntityUpdate Value { | 179 | internal IEntityUpdate Value { |
180 | get { | 180 | get { |
181 | return this.value; | 181 | return this.value; |
182 | } | 182 | } |
@@ -212,7 +212,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
212 | this.pqueue = pqueue; | 212 | this.pqueue = pqueue; |
213 | } | 213 | } |
214 | 214 | ||
215 | internal MinHeapItem(uint pqueue, UInt64 entryorder, EntityUpdate value) | 215 | internal MinHeapItem(uint pqueue, UInt64 entryorder, IEntityUpdate value) |
216 | { | 216 | { |
217 | this.entrytime = Util.EnvironmentTickCount(); | 217 | this.entrytime = Util.EnvironmentTickCount(); |
218 | this.entryorder = entryorder; | 218 | this.entryorder = entryorder; |
diff --git a/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs b/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs index 91e3d20..07b0a1d 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs | |||
@@ -26,6 +26,10 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.Reflection; | ||
32 | using log4net; | ||
29 | 33 | ||
30 | namespace OpenSim.Region.ClientStack.LindenUDP | 34 | namespace OpenSim.Region.ClientStack.LindenUDP |
31 | { | 35 | { |
@@ -35,89 +39,126 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
35 | /// </summary> | 39 | /// </summary> |
36 | public class TokenBucket | 40 | public class TokenBucket |
37 | { | 41 | { |
38 | /// <summary>Parent bucket to this bucket, or null if this is a root | 42 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
39 | /// bucket</summary> | 43 | private static Int32 m_counter = 0; |
40 | TokenBucket parent; | 44 | |
41 | /// <summary>Size of the bucket in bytes. If zero, the bucket has | 45 | private Int32 m_identifier; |
42 | /// infinite capacity</summary> | 46 | |
43 | int maxBurst; | 47 | /// <summary> |
44 | /// <summary>Rate that the bucket fills, in bytes per millisecond. If | 48 | /// Number of ticks (ms) per quantum, drip rate and max burst |
45 | /// zero, the bucket always remains full</summary> | 49 | /// are defined over this interval. |
46 | int tokensPerMS; | 50 | /// </summary> |
47 | /// <summary>Number of tokens currently in the bucket</summary> | 51 | private const Int32 m_ticksPerQuantum = 1000; |
48 | int content; | 52 | |
53 | /// <summary> | ||
54 | /// This is the number of quantums worth of packets that can | ||
55 | /// be accommodated during a burst | ||
56 | /// </summary> | ||
57 | private const Double m_quantumsPerBurst = 1.5; | ||
58 | |||
59 | /// <summary> | ||
60 | /// </summary> | ||
61 | private const Int32 m_minimumDripRate = 1400; | ||
62 | |||
49 | /// <summary>Time of the last drip, in system ticks</summary> | 63 | /// <summary>Time of the last drip, in system ticks</summary> |
50 | int lastDrip; | 64 | private Int32 m_lastDrip; |
65 | |||
66 | /// <summary> | ||
67 | /// The number of bytes that can be sent at this moment. This is the | ||
68 | /// current number of tokens in the bucket | ||
69 | /// </summary> | ||
70 | private Int64 m_tokenCount; | ||
51 | 71 | ||
52 | #region Properties | 72 | /// <summary> |
73 | /// Map of children buckets and their requested maximum burst rate | ||
74 | /// </summary> | ||
75 | private Dictionary<TokenBucket,Int64> m_children = new Dictionary<TokenBucket,Int64>(); | ||
76 | |||
77 | #region Properties | ||
53 | 78 | ||
54 | /// <summary> | 79 | /// <summary> |
55 | /// The parent bucket of this bucket, or null if this bucket has no | 80 | /// The parent bucket of this bucket, or null if this bucket has no |
56 | /// parent. The parent bucket will limit the aggregate bandwidth of all | 81 | /// parent. The parent bucket will limit the aggregate bandwidth of all |
57 | /// of its children buckets | 82 | /// of its children buckets |
58 | /// </summary> | 83 | /// </summary> |
84 | private TokenBucket m_parent; | ||
59 | public TokenBucket Parent | 85 | public TokenBucket Parent |
60 | { | 86 | { |
61 | get { return parent; } | 87 | get { return m_parent; } |
88 | set { m_parent = value; } | ||
62 | } | 89 | } |
63 | 90 | ||
64 | /// <summary> | 91 | /// <summary> |
65 | /// Maximum burst rate in bytes per second. This is the maximum number | 92 | /// Maximum burst rate in bytes per second. This is the maximum number |
66 | /// of tokens that can accumulate in the bucket at any one time | 93 | /// of tokens that can accumulate in the bucket at any one time. This |
94 | /// also sets the total request for leaf nodes | ||
67 | /// </summary> | 95 | /// </summary> |
68 | public int MaxBurst | 96 | private Int64 m_burstRate; |
97 | public Int64 RequestedBurstRate | ||
69 | { | 98 | { |
70 | get { return maxBurst; } | 99 | get { return m_burstRate; } |
71 | set { maxBurst = (value >= 0 ? value : 0); } | 100 | set { m_burstRate = (value < 0 ? 0 : value); } |
72 | } | 101 | } |
73 | 102 | ||
103 | public Int64 BurstRate | ||
104 | { | ||
105 | get { | ||
106 | double rate = RequestedBurstRate * BurstRateModifier(); | ||
107 | if (rate < m_minimumDripRate * m_quantumsPerBurst) | ||
108 | rate = m_minimumDripRate * m_quantumsPerBurst; | ||
109 | |||
110 | return (Int64) rate; | ||
111 | } | ||
112 | } | ||
113 | |||
74 | /// <summary> | 114 | /// <summary> |
75 | /// The speed limit of this bucket in bytes per second. This is the | 115 | /// The speed limit of this bucket in bytes per second. This is the |
76 | /// number of tokens that are added to the bucket per second | 116 | /// number of tokens that are added to the bucket per quantum |
77 | /// </summary> | 117 | /// </summary> |
78 | /// <remarks>Tokens are added to the bucket any time | 118 | /// <remarks>Tokens are added to the bucket any time |
79 | /// <seealso cref="RemoveTokens"/> is called, at the granularity of | 119 | /// <seealso cref="RemoveTokens"/> is called, at the granularity of |
80 | /// the system tick interval (typically around 15-22ms)</remarks> | 120 | /// the system tick interval (typically around 15-22ms)</remarks> |
81 | public int DripRate | 121 | private Int64 m_dripRate; |
122 | public Int64 RequestedDripRate | ||
82 | { | 123 | { |
83 | get { return tokensPerMS * 1000; } | 124 | get { return (m_dripRate == 0 ? m_totalDripRequest : m_dripRate); } |
84 | set | 125 | set { |
85 | { | 126 | m_dripRate = (value < 0 ? 0 : value); |
86 | if (value == 0) | 127 | m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst); |
87 | tokensPerMS = 0; | 128 | m_totalDripRequest = m_dripRate; |
88 | else | 129 | if (m_parent != null) |
89 | { | 130 | m_parent.RegisterRequest(this,m_dripRate); |
90 | int bpms = (int)((float)value / 1000.0f); | ||
91 | |||
92 | if (bpms <= 0) | ||
93 | tokensPerMS = 1; // 1 byte/ms is the minimum granularity | ||
94 | else | ||
95 | tokensPerMS = bpms; | ||
96 | } | ||
97 | } | 131 | } |
98 | } | 132 | } |
99 | 133 | ||
100 | /// <summary> | 134 | public Int64 DripRate |
101 | /// The speed limit of this bucket in bytes per millisecond | ||
102 | /// </summary> | ||
103 | public int DripPerMS | ||
104 | { | 135 | { |
105 | get { return tokensPerMS; } | 136 | get { |
137 | if (m_parent == null) | ||
138 | return Math.Min(RequestedDripRate,TotalDripRequest); | ||
139 | |||
140 | double rate = (double)RequestedDripRate * m_parent.DripRateModifier(); | ||
141 | if (rate < m_minimumDripRate) | ||
142 | rate = m_minimumDripRate; | ||
143 | |||
144 | return (Int64)rate; | ||
145 | } | ||
106 | } | 146 | } |
107 | 147 | ||
108 | /// <summary> | 148 | /// <summary> |
109 | /// The number of bytes that can be sent at this moment. This is the | 149 | /// The current total of the requested maximum burst rates of |
110 | /// current number of tokens in the bucket | 150 | /// this bucket's children buckets. |
111 | /// <remarks>If this bucket has a parent bucket that does not have | ||
112 | /// enough tokens for a request, <seealso cref="RemoveTokens"/> will | ||
113 | /// return false regardless of the content of this bucket</remarks> | ||
114 | /// </summary> | 151 | /// </summary> |
115 | public int Content | 152 | private Int64 m_totalDripRequest; |
116 | { | 153 | public Int64 TotalDripRequest |
117 | get { return content; } | 154 | { |
118 | } | 155 | get { return m_totalDripRequest; } |
156 | set { m_totalDripRequest = value; } | ||
157 | } | ||
158 | |||
159 | #endregion Properties | ||
119 | 160 | ||
120 | #endregion Properties | 161 | #region Constructor |
121 | 162 | ||
122 | /// <summary> | 163 | /// <summary> |
123 | /// Default constructor | 164 | /// Default constructor |
@@ -128,46 +169,114 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
128 | /// zero if this bucket has no maximum capacity</param> | 169 | /// zero if this bucket has no maximum capacity</param> |
129 | /// <param name="dripRate">Rate that the bucket fills, in bytes per | 170 | /// <param name="dripRate">Rate that the bucket fills, in bytes per |
130 | /// second. If zero, the bucket always remains full</param> | 171 | /// second. If zero, the bucket always remains full</param> |
131 | public TokenBucket(TokenBucket parent, int maxBurst, int dripRate) | 172 | public TokenBucket(TokenBucket parent, Int64 dripRate) |
173 | { | ||
174 | m_identifier = m_counter++; | ||
175 | |||
176 | Parent = parent; | ||
177 | RequestedDripRate = dripRate; | ||
178 | // TotalDripRequest = dripRate; // this will be overwritten when a child node registers | ||
179 | // MaxBurst = (Int64)((double)dripRate * m_quantumsPerBurst); | ||
180 | m_lastDrip = Environment.TickCount & Int32.MaxValue; | ||
181 | } | ||
182 | |||
183 | #endregion Constructor | ||
184 | |||
185 | /// <summary> | ||
186 | /// Compute a modifier for the MaxBurst rate. This is 1.0, meaning | ||
187 | /// no modification if the requested bandwidth is less than the | ||
188 | /// max burst bandwidth all the way to the root of the throttle | ||
189 | /// hierarchy. However, if any of the parents is over-booked, then | ||
190 | /// the modifier will be less than 1. | ||
191 | /// </summary> | ||
192 | private double DripRateModifier() | ||
193 | { | ||
194 | Int64 driprate = DripRate; | ||
195 | return driprate >= TotalDripRequest ? 1.0 : (double)driprate / (double)TotalDripRequest; | ||
196 | } | ||
197 | |||
198 | /// <summary> | ||
199 | /// </summary> | ||
200 | private double BurstRateModifier() | ||
201 | { | ||
202 | // for now... burst rate is always m_quantumsPerBurst (constant) | ||
203 | // larger than drip rate so the ratio of burst requests is the | ||
204 | // same as the drip ratio | ||
205 | return DripRateModifier(); | ||
206 | } | ||
207 | |||
208 | /// <summary> | ||
209 | /// Register drip rate requested by a child of this throttle. Pass the | ||
210 | /// changes up the hierarchy. | ||
211 | /// </summary> | ||
212 | public void RegisterRequest(TokenBucket child, Int64 request) | ||
132 | { | 213 | { |
133 | this.parent = parent; | 214 | m_children[child] = request; |
134 | MaxBurst = maxBurst; | 215 | // m_totalDripRequest = m_children.Values.Sum(); |
135 | DripRate = dripRate; | 216 | |
136 | lastDrip = Environment.TickCount; | 217 | m_totalDripRequest = 0; |
218 | foreach (KeyValuePair<TokenBucket, Int64> cref in m_children) | ||
219 | m_totalDripRequest += cref.Value; | ||
220 | |||
221 | // Pass the new values up to the parent | ||
222 | if (m_parent != null) | ||
223 | m_parent.RegisterRequest(this,Math.Min(RequestedDripRate, TotalDripRequest)); | ||
137 | } | 224 | } |
138 | 225 | ||
139 | /// <summary> | 226 | /// <summary> |
227 | /// Remove the rate requested by a child of this throttle. Pass the | ||
228 | /// changes up the hierarchy. | ||
229 | /// </summary> | ||
230 | public void UnregisterRequest(TokenBucket child) | ||
231 | { | ||
232 | m_children.Remove(child); | ||
233 | // m_totalDripRequest = m_children.Values.Sum(); | ||
234 | |||
235 | m_totalDripRequest = 0; | ||
236 | foreach (KeyValuePair<TokenBucket, Int64> cref in m_children) | ||
237 | m_totalDripRequest += cref.Value; | ||
238 | |||
239 | // Pass the new values up to the parent | ||
240 | if (m_parent != null) | ||
241 | m_parent.RegisterRequest(this,Math.Min(RequestedDripRate, TotalDripRequest)); | ||
242 | } | ||
243 | |||
244 | /// <summary> | ||
140 | /// Remove a given number of tokens from the bucket | 245 | /// Remove a given number of tokens from the bucket |
141 | /// </summary> | 246 | /// </summary> |
142 | /// <param name="amount">Number of tokens to remove from the bucket</param> | 247 | /// <param name="amount">Number of tokens to remove from the bucket</param> |
143 | /// <returns>True if the requested number of tokens were removed from | 248 | /// <returns>True if the requested number of tokens were removed from |
144 | /// the bucket, otherwise false</returns> | 249 | /// the bucket, otherwise false</returns> |
145 | public bool RemoveTokens(int amount) | 250 | public bool RemoveTokens(Int64 amount) |
146 | { | 251 | { |
147 | if (maxBurst == 0) | 252 | // Deposit tokens for this interval |
148 | { | ||
149 | return true; | ||
150 | } | ||
151 | |||
152 | if (amount > maxBurst) | ||
153 | { | ||
154 | throw new Exception("amount " + amount + " exceeds maxBurst " + maxBurst); | ||
155 | } | ||
156 | |||
157 | Drip(); | 253 | Drip(); |
158 | 254 | ||
159 | if (content < amount) | 255 | // If we have enough tokens then remove them and return |
256 | if (m_tokenCount - amount >= 0) | ||
160 | { | 257 | { |
161 | return false; | 258 | // we don't have to remove from the parent, the drip rate is already |
259 | // reflective of the drip rate limits in the parent | ||
260 | m_tokenCount -= amount; | ||
261 | return true; | ||
162 | } | 262 | } |
163 | 263 | ||
164 | if (parent != null && !parent.RemoveTokens(amount)) | 264 | return false; |
165 | { | 265 | } |
166 | return false; | ||
167 | } | ||
168 | 266 | ||
169 | content -= amount; | 267 | /// <summary> |
170 | return true; | 268 | /// Deposit tokens into the bucket from a child bucket that did |
269 | /// not use all of its available tokens | ||
270 | /// </summary> | ||
271 | private void Deposit(Int64 count) | ||
272 | { | ||
273 | m_tokenCount += count; | ||
274 | |||
275 | // Deposit the overflow in the parent bucket, this is how we share | ||
276 | // unused bandwidth | ||
277 | Int64 burstrate = BurstRate; | ||
278 | if (m_tokenCount > burstrate) | ||
279 | m_tokenCount = burstrate; | ||
171 | } | 280 | } |
172 | 281 | ||
173 | /// <summary> | 282 | /// <summary> |
@@ -176,30 +285,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
176 | /// call to Drip | 285 | /// call to Drip |
177 | /// </summary> | 286 | /// </summary> |
178 | /// <returns>True if tokens were added to the bucket, otherwise false</returns> | 287 | /// <returns>True if tokens were added to the bucket, otherwise false</returns> |
179 | public bool Drip() | 288 | private void Drip() |
180 | { | 289 | { |
181 | if (tokensPerMS == 0) | 290 | // This should never happen... means we are a leaf node and were created |
291 | // with no drip rate... | ||
292 | if (DripRate == 0) | ||
182 | { | 293 | { |
183 | content = maxBurst; | 294 | m_log.WarnFormat("[TOKENBUCKET] something odd is happening and drip rate is 0"); |
184 | return true; | 295 | return; |
185 | } | 296 | } |
297 | |||
298 | // Determine the interval over which we are adding tokens, never add | ||
299 | // more than a single quantum of tokens | ||
300 | Int32 now = Environment.TickCount & Int32.MaxValue; | ||
301 | Int32 deltaMS = Math.Min(now - m_lastDrip, m_ticksPerQuantum); | ||
186 | 302 | ||
187 | int now = Environment.TickCount; | 303 | m_lastDrip = now; |
188 | int deltaMS = now - lastDrip; | ||
189 | lastDrip = now; | ||
190 | 304 | ||
305 | // This can be 0 in the very unusual case that the timer wrapped | ||
306 | // It can be 0 if we try add tokens at a sub-tick rate | ||
191 | if (deltaMS <= 0) | 307 | if (deltaMS <= 0) |
192 | { | 308 | return; |
193 | return false; | ||
194 | } | ||
195 | 309 | ||
196 | long dripAmount = (long)deltaMS * (long)tokensPerMS + (long)content; | 310 | Deposit(deltaMS * DripRate / m_ticksPerQuantum); |
197 | if (dripAmount > maxBurst) | ||
198 | { | ||
199 | dripAmount = maxBurst; | ||
200 | } | ||
201 | content = (int)dripAmount; | ||
202 | return true; | ||
203 | } | 311 | } |
204 | } | 312 | } |
205 | } | 313 | } |
diff --git a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs index 4332900..b3bdff3 100644 --- a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs +++ b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs | |||
@@ -702,18 +702,12 @@ namespace OpenSim.Region.Examples.SimpleModule | |||
702 | { | 702 | { |
703 | } | 703 | } |
704 | 704 | ||
705 | public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, | 705 | public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags) |
706 | uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, | ||
707 | uint NextOwnerMask, int OwnershipCost, byte SaleType,int SalePrice, uint Category, | ||
708 | UUID LastOwnerID, string ObjectName, string Description) | ||
709 | { | 706 | { |
707 | |||
710 | } | 708 | } |
711 | 709 | ||
712 | public void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID, | 710 | public void SendObjectPropertiesReply(ISceneEntity entity) |
713 | UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, | ||
714 | UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName, | ||
715 | string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask, | ||
716 | uint BaseMask, byte saleType, int salePrice) | ||
717 | { | 711 | { |
718 | } | 712 | } |
719 | 713 | ||
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 69bfb9a..b100b39 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | |||
@@ -2111,10 +2111,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
2111 | /// <param name="part"></param> | 2111 | /// <param name="part"></param> |
2112 | public void ServiceObjectPropertiesFamilyRequest(IClientAPI remoteClient, UUID AgentID, uint RequestFlags) | 2112 | public void ServiceObjectPropertiesFamilyRequest(IClientAPI remoteClient, UUID AgentID, uint RequestFlags) |
2113 | { | 2113 | { |
2114 | remoteClient.SendObjectPropertiesFamilyData(RequestFlags, RootPart.UUID, RootPart.OwnerID, RootPart.GroupID, RootPart.BaseMask, | 2114 | remoteClient.SendObjectPropertiesFamilyData(RootPart, RequestFlags); |
2115 | RootPart.OwnerMask, RootPart.GroupMask, RootPart.EveryoneMask, RootPart.NextOwnerMask, | 2115 | |
2116 | RootPart.OwnershipCost, RootPart.ObjectSaleType, RootPart.SalePrice, RootPart.Category, | 2116 | // remoteClient.SendObjectPropertiesFamilyData(RequestFlags, RootPart.UUID, RootPart.OwnerID, RootPart.GroupID, RootPart.BaseMask, |
2117 | RootPart.CreatorID, RootPart.Name, RootPart.Description); | 2117 | // RootPart.OwnerMask, RootPart.GroupMask, RootPart.EveryoneMask, RootPart.NextOwnerMask, |
2118 | // RootPart.OwnershipCost, RootPart.ObjectSaleType, RootPart.SalePrice, RootPart.Category, | ||
2119 | // RootPart.CreatorID, RootPart.Name, RootPart.Description); | ||
2118 | } | 2120 | } |
2119 | 2121 | ||
2120 | public void SetPartOwner(SceneObjectPart part, UUID cAgentID, UUID cGroupID) | 2122 | public void SetPartOwner(SceneObjectPart part, UUID cAgentID, UUID cGroupID) |
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 9b9f280..e7e3014 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | |||
@@ -2093,15 +2093,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2093 | 2093 | ||
2094 | public void GetProperties(IClientAPI client) | 2094 | public void GetProperties(IClientAPI client) |
2095 | { | 2095 | { |
2096 | //Viewer wants date in microseconds so multiply it by 1,000,000. | 2096 | client.SendObjectPropertiesReply(this); |
2097 | client.SendObjectPropertiesReply( | ||
2098 | m_fromUserInventoryItemID, (ulong)_creationDate*(ulong)1e6, _creatorID, UUID.Zero, UUID.Zero, | ||
2099 | _groupID, (short)InventorySerial, _lastOwnerID, UUID, _ownerID, | ||
2100 | ParentGroup.RootPart.TouchName, new byte[0], ParentGroup.RootPart.SitName, Name, Description, | ||
2101 | ParentGroup.RootPart._ownerMask, ParentGroup.RootPart._nextOwnerMask, ParentGroup.RootPart._groupMask, ParentGroup.RootPart._everyoneMask, | ||
2102 | ParentGroup.RootPart._baseMask, | ||
2103 | ParentGroup.RootPart.ObjectSaleType, | ||
2104 | ParentGroup.RootPart.SalePrice); | ||
2105 | } | 2097 | } |
2106 | 2098 | ||
2107 | public UUID GetRootPartUUID() | 2099 | public UUID GetRootPartUUID() |
diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs index 6c266bb..07af201 100644 --- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs +++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs | |||
@@ -1338,14 +1338,13 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server | |||
1338 | 1338 | ||
1339 | } | 1339 | } |
1340 | 1340 | ||
1341 | public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, uint NextOwnerMask, int OwnershipCost, byte SaleType, int SalePrice, uint Category, UUID LastOwnerID, string ObjectName, string Description) | 1341 | public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags) |
1342 | { | 1342 | { |
1343 | 1343 | ||
1344 | } | 1344 | } |
1345 | 1345 | ||
1346 | public void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID, UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName, string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask, uint BaseMask, byte saleType, int salePrice) | 1346 | public void SendObjectPropertiesReply(ISceneEntity entity) |
1347 | { | 1347 | { |
1348 | |||
1349 | } | 1348 | } |
1350 | 1349 | ||
1351 | public void SendAgentOffline(UUID[] agentIDs) | 1350 | public void SendAgentOffline(UUID[] agentIDs) |
diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs index 1b67b7d..d895438 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs | |||
@@ -786,18 +786,12 @@ namespace OpenSim.Region.OptionalModules.World.NPC | |||
786 | { | 786 | { |
787 | } | 787 | } |
788 | 788 | ||
789 | public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, | 789 | public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags) |
790 | uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, | ||
791 | uint NextOwnerMask, int OwnershipCost, byte SaleType, int SalePrice, uint Category, | ||
792 | UUID LastOwnerID, string ObjectName, string Description) | ||
793 | { | 790 | { |
791 | |||
794 | } | 792 | } |
795 | 793 | ||
796 | public void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID, | 794 | public void SendObjectPropertiesReply(ISceneEntity entity) |
797 | UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, | ||
798 | UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName, | ||
799 | string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask, | ||
800 | uint BaseMask, byte saleType, int salePrice) | ||
801 | { | 795 | { |
802 | } | 796 | } |
803 | 797 | ||
diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs index 592009d..7f0eaa7 100644 --- a/OpenSim/Tests/Common/Mock/TestClient.cs +++ b/OpenSim/Tests/Common/Mock/TestClient.cs | |||
@@ -816,18 +816,11 @@ namespace OpenSim.Tests.Common.Mock | |||
816 | { | 816 | { |
817 | } | 817 | } |
818 | 818 | ||
819 | public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, | 819 | public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags) |
820 | uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, | ||
821 | uint NextOwnerMask, int OwnershipCost, byte SaleType,int SalePrice, uint Category, | ||
822 | UUID LastOwnerID, string ObjectName, string Description) | ||
823 | { | 820 | { |
824 | } | 821 | } |
825 | 822 | ||
826 | public void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID, | 823 | public void SendObjectPropertiesReply(ISceneEntity entity) |
827 | UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, | ||
828 | UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName, | ||
829 | string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask, | ||
830 | uint BaseMask, byte saleType, int salePrice) | ||
831 | { | 824 | { |
832 | } | 825 | } |
833 | 826 | ||