Merge branch 'master' into careminster-presence-refactor
commit
d1913f2429
|
@ -1352,12 +1352,12 @@ namespace OpenSim.Client.MXP.ClientStack
|
|||
// Need to translate to MXP somehow
|
||||
}
|
||||
|
||||
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)
|
||||
public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags)
|
||||
{
|
||||
//throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
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)
|
||||
public void SendObjectPropertiesReply(ISceneEntity entity)
|
||||
{
|
||||
//throw new System.NotImplementedException();
|
||||
}
|
||||
|
|
|
@ -890,12 +890,12 @@ namespace OpenSim.Client.VWoHTTP.ClientStack
|
|||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
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)
|
||||
public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
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)
|
||||
public void SendObjectPropertiesReply(ISceneEntity entity)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
|
|
@ -574,16 +574,35 @@ namespace OpenSim.Framework
|
|||
public float dwell;
|
||||
}
|
||||
|
||||
public class EntityUpdate
|
||||
public class IEntityUpdate
|
||||
{
|
||||
public ISceneEntity Entity;
|
||||
public PrimUpdateFlags Flags;
|
||||
public float TimeDilation;
|
||||
public uint Flags;
|
||||
|
||||
public EntityUpdate(ISceneEntity entity, PrimUpdateFlags flags, float timedilation)
|
||||
public virtual void Update(IEntityUpdate update)
|
||||
{
|
||||
this.Flags |= update.Flags;
|
||||
}
|
||||
|
||||
public IEntityUpdate(ISceneEntity entity, uint flags)
|
||||
{
|
||||
Entity = entity;
|
||||
Flags = flags;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class EntityUpdate : IEntityUpdate
|
||||
{
|
||||
// public ISceneEntity Entity;
|
||||
// public PrimUpdateFlags Flags;
|
||||
public float TimeDilation;
|
||||
|
||||
public EntityUpdate(ISceneEntity entity, PrimUpdateFlags flags, float timedilation)
|
||||
: base(entity,(uint)flags)
|
||||
{
|
||||
//Entity = entity;
|
||||
// Flags = flags;
|
||||
TimeDilation = timedilation;
|
||||
}
|
||||
}
|
||||
|
@ -1217,20 +1236,9 @@ namespace OpenSim.Framework
|
|||
/// <param name="stats"></param>
|
||||
void SendSimStats(SimStats stats);
|
||||
|
||||
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);
|
||||
void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags);
|
||||
|
||||
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);
|
||||
void SendObjectPropertiesReply(ISceneEntity Entity);
|
||||
|
||||
void SendAgentOffline(UUID[] agentIDs);
|
||||
|
||||
|
|
|
@ -301,77 +301,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
|||
/// <summary>Used to adjust Sun Orbit values so Linden based viewers properly position sun</summary>
|
||||
private const float m_sunPainDaHalfOrbitalCutoff = 4.712388980384689858f;
|
||||
|
||||
// First log file or time has expired, start writing to a new log file
|
||||
//<MIC>
|
||||
// -----------------------------------------------------------------
|
||||
// -----------------------------------------------------------------
|
||||
// THIS IS DEBUGGING CODE & SHOULD BE REMOVED
|
||||
// -----------------------------------------------------------------
|
||||
// -----------------------------------------------------------------
|
||||
public class QueueLogger
|
||||
{
|
||||
public Int32 start = 0;
|
||||
public StreamWriter Log = null;
|
||||
private Dictionary<UUID,int> m_idMap = new Dictionary<UUID,int>();
|
||||
|
||||
public QueueLogger()
|
||||
{
|
||||
DateTime now = DateTime.Now;
|
||||
String fname = String.Format("queue-{0}.log", now.ToString("yyyyMMddHHmmss"));
|
||||
Log = new StreamWriter(fname);
|
||||
|
||||
start = Util.EnvironmentTickCount();
|
||||
}
|
||||
|
||||
public int LookupID(UUID uuid)
|
||||
{
|
||||
int localid;
|
||||
if (! m_idMap.TryGetValue(uuid,out localid))
|
||||
{
|
||||
localid = m_idMap.Count + 1;
|
||||
m_idMap[uuid] = localid;
|
||||
}
|
||||
|
||||
return localid;
|
||||
}
|
||||
}
|
||||
|
||||
public static QueueLogger QueueLog = null;
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
public void LogAvatarUpdateEvent(UUID client, UUID avatar, Int32 timeinqueue)
|
||||
{
|
||||
if (QueueLog == null)
|
||||
QueueLog = new QueueLogger();
|
||||
|
||||
Int32 ticks = Util.EnvironmentTickCountSubtract(QueueLog.start);
|
||||
lock(QueueLog)
|
||||
{
|
||||
int cid = QueueLog.LookupID(client);
|
||||
int aid = QueueLog.LookupID(avatar);
|
||||
QueueLog.Log.WriteLine("{0},AU,AV{1:D4},AV{2:D4},{3}",ticks,cid,aid,timeinqueue);
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
public void LogQueueProcessEvent(UUID client, PriorityQueue queue, uint maxup)
|
||||
{
|
||||
if (QueueLog == null)
|
||||
QueueLog = new QueueLogger();
|
||||
|
||||
Int32 ticks = Util.EnvironmentTickCountSubtract(QueueLog.start);
|
||||
lock(QueueLog)
|
||||
{
|
||||
int cid = QueueLog.LookupID(client);
|
||||
QueueLog.Log.WriteLine("{0},PQ,AV{1:D4},{2},{3}",ticks,cid,maxup,queue.ToString());
|
||||
}
|
||||
}
|
||||
// -----------------------------------------------------------------
|
||||
// -----------------------------------------------------------------
|
||||
// -----------------------------------------------------------------
|
||||
// -----------------------------------------------------------------
|
||||
//</MIC>
|
||||
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
protected static Dictionary<PacketType, PacketMethod> PacketHandlers = new Dictionary<PacketType, PacketMethod>(); //Global/static handlers for all clients
|
||||
|
||||
|
@ -387,6 +316,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
|||
|
||||
private int m_cachedTextureSerial;
|
||||
private PriorityQueue m_entityUpdates;
|
||||
private PriorityQueue m_entityProps;
|
||||
private Prioritizer m_prioritizer;
|
||||
private bool m_disableFacelights = false;
|
||||
|
||||
|
@ -435,9 +365,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
|||
protected IAssetService m_assetService;
|
||||
private const bool m_checkPackets = true;
|
||||
|
||||
private Timer m_propertiesPacketTimer;
|
||||
private List<ObjectPropertiesPacket.ObjectDataBlock> m_propertiesBlocks = new List<ObjectPropertiesPacket.ObjectDataBlock>();
|
||||
|
||||
#endregion Class Members
|
||||
|
||||
#region Properties
|
||||
|
@ -521,6 +448,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
|||
m_scene = scene;
|
||||
|
||||
m_entityUpdates = new PriorityQueue(m_scene.Entities.Count);
|
||||
m_entityProps = new PriorityQueue(m_scene.Entities.Count);
|
||||
m_fullUpdateDataBlocksBuilder = new List<ObjectUpdatePacket.ObjectDataBlock>();
|
||||
m_killRecord = new HashSet<uint>();
|
||||
// m_attachmentsSent = new HashSet<uint>();
|
||||
|
@ -544,9 +472,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
|||
m_udpClient.OnQueueEmpty += HandleQueueEmpty;
|
||||
m_udpClient.OnPacketStats += PopulateStats;
|
||||
|
||||
m_propertiesPacketTimer = new Timer(100);
|
||||
m_propertiesPacketTimer.Elapsed += ProcessObjectPropertiesPacket;
|
||||
|
||||
m_prioritizer = new Prioritizer(m_scene);
|
||||
|
||||
RegisterLocalPacketHandlers();
|
||||
|
@ -2468,7 +2393,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
|||
|
||||
packet.Effect = effectBlocks;
|
||||
|
||||
OutPacket(packet, ThrottleOutPacketType.State);
|
||||
// OutPacket(packet, ThrottleOutPacketType.State);
|
||||
OutPacket(packet, ThrottleOutPacketType.Task);
|
||||
}
|
||||
|
||||
public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] charterMember,
|
||||
|
@ -3670,9 +3596,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
|||
m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation));
|
||||
}
|
||||
|
||||
private Int32 m_LastQueueFill = 0;
|
||||
private uint m_maxUpdates = 0;
|
||||
|
||||
private void ProcessEntityUpdates(int maxUpdates)
|
||||
{
|
||||
OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>();
|
||||
|
@ -3680,41 +3603,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
|||
OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>();
|
||||
OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>();
|
||||
|
||||
// Check to see if this is a flush
|
||||
if (maxUpdates <= 0)
|
||||
{
|
||||
m_maxUpdates = Int32.MaxValue;
|
||||
maxUpdates = Int32.MaxValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_maxUpdates == 0 || m_LastQueueFill == 0)
|
||||
{
|
||||
m_maxUpdates = (uint)maxUpdates;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Util.EnvironmentTickCountSubtract(m_LastQueueFill) < 200)
|
||||
m_maxUpdates += 5;
|
||||
else
|
||||
m_maxUpdates = m_maxUpdates >> 1;
|
||||
}
|
||||
m_maxUpdates = Util.Clamp<uint>(m_maxUpdates,10,500);
|
||||
}
|
||||
m_LastQueueFill = Util.EnvironmentTickCount();
|
||||
|
||||
int updatesThisCall = 0;
|
||||
|
||||
// We must lock for both manipulating the kill record and sending the packet, in order to avoid a race
|
||||
// condition where a kill can be processed before an out-of-date update for the same object.
|
||||
float avgTimeDilation = 1.0f;
|
||||
|
||||
EntityUpdate update;
|
||||
IEntityUpdate iupdate;
|
||||
Int32 timeinqueue; // this is just debugging code & can be dropped later
|
||||
|
||||
while (updatesThisCall < m_maxUpdates)
|
||||
while (updatesThisCall < maxUpdates)
|
||||
{
|
||||
lock (m_entityUpdates.SyncRoot)
|
||||
if (!m_entityUpdates.TryDequeue(out update, out timeinqueue))
|
||||
if (!m_entityUpdates.TryDequeue(out iupdate, out timeinqueue))
|
||||
break;
|
||||
|
||||
EntityUpdate update = (EntityUpdate)iupdate;
|
||||
|
||||
avgTimeDilation += update.TimeDilation;
|
||||
avgTimeDilation *= 0.5f;
|
||||
|
||||
|
@ -3770,7 +3680,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
|||
if (!found)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (part.ParentGroup.IsAttachment && m_disableFacelights)
|
||||
{
|
||||
if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand &&
|
||||
|
@ -3785,7 +3694,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
|||
|
||||
#region UpdateFlags to packet type conversion
|
||||
|
||||
PrimUpdateFlags updateFlags = update.Flags;
|
||||
PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags;
|
||||
|
||||
bool canUseCompressed = true;
|
||||
bool canUseImproved = true;
|
||||
|
@ -3960,12 +3869,36 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
|||
|
||||
#endregion Primitive Packet/Data Sending Methods
|
||||
|
||||
// These are used to implement an adaptive backoff in the number
|
||||
// of updates converted to packets. Since we don't want packets
|
||||
// to sit in the queue with old data, only convert enough updates
|
||||
// to packets that can be sent in 200ms.
|
||||
private Int32 m_LastQueueFill = 0;
|
||||
private Int32 m_maxUpdates = 0;
|
||||
|
||||
void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories)
|
||||
{
|
||||
if ((categories & ThrottleOutPacketTypeFlags.Task) != 0)
|
||||
{
|
||||
if (m_maxUpdates == 0 || m_LastQueueFill == 0)
|
||||
{
|
||||
m_maxUpdates = m_udpServer.PrimUpdatesPerCallback;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Util.EnvironmentTickCountSubtract(m_LastQueueFill) < 200)
|
||||
m_maxUpdates += 5;
|
||||
else
|
||||
m_maxUpdates = m_maxUpdates >> 1;
|
||||
}
|
||||
m_maxUpdates = Util.Clamp<Int32>(m_maxUpdates,10,500);
|
||||
m_LastQueueFill = Util.EnvironmentTickCount();
|
||||
|
||||
if (m_entityUpdates.Count > 0)
|
||||
ProcessEntityUpdates(m_udpServer.PrimUpdatesPerCallback);
|
||||
ProcessEntityUpdates(m_maxUpdates);
|
||||
|
||||
if (m_entityProps.Count > 0)
|
||||
ProcessEntityPropertyRequests(m_maxUpdates);
|
||||
}
|
||||
|
||||
if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0)
|
||||
|
@ -4079,47 +4012,167 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
|||
OutPacket(pack, ThrottleOutPacketType.Task);
|
||||
}
|
||||
|
||||
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)
|
||||
private class ObjectPropertyUpdate : IEntityUpdate
|
||||
{
|
||||
ObjectPropertiesFamilyPacket objPropFamilyPack = (ObjectPropertiesFamilyPacket)PacketPool.Instance.GetPacket(PacketType.ObjectPropertiesFamily);
|
||||
// TODO: don't create new blocks if recycling an old packet
|
||||
internal bool SendFamilyProps;
|
||||
internal bool SendObjectProps;
|
||||
|
||||
ObjectPropertiesFamilyPacket.ObjectDataBlock objPropDB = new ObjectPropertiesFamilyPacket.ObjectDataBlock();
|
||||
objPropDB.RequestFlags = RequestFlags;
|
||||
objPropDB.ObjectID = ObjectUUID;
|
||||
if (OwnerID == GroupID)
|
||||
objPropDB.OwnerID = UUID.Zero;
|
||||
else
|
||||
objPropDB.OwnerID = OwnerID;
|
||||
objPropDB.GroupID = GroupID;
|
||||
objPropDB.BaseMask = BaseMask;
|
||||
objPropDB.OwnerMask = OwnerMask;
|
||||
objPropDB.GroupMask = GroupMask;
|
||||
objPropDB.EveryoneMask = EveryoneMask;
|
||||
objPropDB.NextOwnerMask = NextOwnerMask;
|
||||
|
||||
// TODO: More properties are needed in SceneObjectPart!
|
||||
objPropDB.OwnershipCost = OwnershipCost;
|
||||
objPropDB.SaleType = SaleType;
|
||||
objPropDB.SalePrice = SalePrice;
|
||||
objPropDB.Category = Category;
|
||||
objPropDB.LastOwnerID = LastOwnerID;
|
||||
objPropDB.Name = Util.StringToBytes256(ObjectName);
|
||||
objPropDB.Description = Util.StringToBytes256(Description);
|
||||
objPropFamilyPack.ObjectData = objPropDB;
|
||||
objPropFamilyPack.Header.Zerocoded = true;
|
||||
OutPacket(objPropFamilyPack, ThrottleOutPacketType.Task);
|
||||
public ObjectPropertyUpdate(ISceneEntity entity, uint flags, bool sendfam, bool sendobj)
|
||||
: base(entity,flags)
|
||||
{
|
||||
SendFamilyProps = sendfam;
|
||||
SendObjectProps = sendobj;
|
||||
}
|
||||
public void Update(ObjectPropertyUpdate update)
|
||||
{
|
||||
SendFamilyProps = SendFamilyProps || update.SendFamilyProps;
|
||||
SendObjectProps = SendObjectProps || update.SendObjectProps;
|
||||
Flags |= update.Flags;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
public void SendObjectPropertiesFamilyData(ISceneEntity entity, uint requestFlags)
|
||||
{
|
||||
uint priority = 0; // time based ordering only
|
||||
lock (m_entityProps.SyncRoot)
|
||||
m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,requestFlags,true,false));
|
||||
}
|
||||
|
||||
public void SendObjectPropertiesReply(ISceneEntity entity)
|
||||
{
|
||||
uint priority = 0; // time based ordering only
|
||||
lock (m_entityProps.SyncRoot)
|
||||
m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,0,false,true));
|
||||
}
|
||||
|
||||
private void ProcessEntityPropertyRequests(int maxUpdates)
|
||||
{
|
||||
OpenSim.Framework.Lazy<List<ObjectPropertiesFamilyPacket.ObjectDataBlock>> objectFamilyBlocks =
|
||||
new OpenSim.Framework.Lazy<List<ObjectPropertiesFamilyPacket.ObjectDataBlock>>();
|
||||
|
||||
OpenSim.Framework.Lazy<List<ObjectPropertiesPacket.ObjectDataBlock>> objectPropertiesBlocks =
|
||||
new OpenSim.Framework.Lazy<List<ObjectPropertiesPacket.ObjectDataBlock>>();
|
||||
|
||||
IEntityUpdate iupdate;
|
||||
Int32 timeinqueue; // this is just debugging code & can be dropped later
|
||||
|
||||
int updatesThisCall = 0;
|
||||
while (updatesThisCall < m_maxUpdates)
|
||||
{
|
||||
lock (m_entityProps.SyncRoot)
|
||||
if (!m_entityProps.TryDequeue(out iupdate, out timeinqueue))
|
||||
break;
|
||||
|
||||
ObjectPropertyUpdate update = (ObjectPropertyUpdate)iupdate;
|
||||
if (update.SendFamilyProps)
|
||||
{
|
||||
if (update.Entity is SceneObjectPart)
|
||||
{
|
||||
SceneObjectPart sop = (SceneObjectPart)update.Entity;
|
||||
ObjectPropertiesFamilyPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesFamilyBlock(sop,update.Flags);
|
||||
objectFamilyBlocks.Value.Add(objPropDB);
|
||||
}
|
||||
}
|
||||
|
||||
if (update.SendObjectProps)
|
||||
{
|
||||
if (update.Entity is SceneObjectPart)
|
||||
{
|
||||
SceneObjectPart sop = (SceneObjectPart)update.Entity;
|
||||
ObjectPropertiesPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesBlock(sop);
|
||||
objectPropertiesBlocks.Value.Add(objPropDB);
|
||||
}
|
||||
}
|
||||
|
||||
updatesThisCall++;
|
||||
}
|
||||
|
||||
|
||||
Int32 ppcnt = 0;
|
||||
Int32 pbcnt = 0;
|
||||
|
||||
if (objectPropertiesBlocks.IsValueCreated)
|
||||
{
|
||||
List<ObjectPropertiesPacket.ObjectDataBlock> blocks = objectPropertiesBlocks.Value;
|
||||
|
||||
ObjectPropertiesPacket packet = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties);
|
||||
packet.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[blocks.Count];
|
||||
for (int i = 0; i < blocks.Count; i++)
|
||||
packet.ObjectData[i] = blocks[i];
|
||||
|
||||
packet.Header.Zerocoded = true;
|
||||
OutPacket(packet, ThrottleOutPacketType.Task, true);
|
||||
|
||||
pbcnt += blocks.Count;
|
||||
ppcnt++;
|
||||
}
|
||||
|
||||
Int32 fpcnt = 0;
|
||||
Int32 fbcnt = 0;
|
||||
|
||||
if (objectFamilyBlocks.IsValueCreated)
|
||||
{
|
||||
List<ObjectPropertiesFamilyPacket.ObjectDataBlock> blocks = objectFamilyBlocks.Value;
|
||||
|
||||
// ObjectPropertiesFamilyPacket objPropFamilyPack =
|
||||
// (ObjectPropertiesFamilyPacket)PacketPool.Instance.GetPacket(PacketType.ObjectPropertiesFamily);
|
||||
//
|
||||
// objPropFamilyPack.ObjectData = new ObjectPropertiesFamilyPacket.ObjectDataBlock[blocks.Count];
|
||||
// for (int i = 0; i < blocks.Count; i++)
|
||||
// objPropFamilyPack.ObjectData[i] = blocks[i];
|
||||
//
|
||||
// OutPacket(objPropFamilyPack, ThrottleOutPacketType.Task, true);
|
||||
|
||||
// one packet per object block... uggh...
|
||||
for (int i = 0; i < blocks.Count; i++)
|
||||
{
|
||||
ObjectPropertiesFamilyPacket packet =
|
||||
(ObjectPropertiesFamilyPacket)PacketPool.Instance.GetPacket(PacketType.ObjectPropertiesFamily);
|
||||
|
||||
packet.ObjectData = blocks[i];
|
||||
packet.Header.Zerocoded = true;
|
||||
OutPacket(packet, ThrottleOutPacketType.Task);
|
||||
|
||||
fpcnt++;
|
||||
fbcnt++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// m_log.WarnFormat("[PACKETCOUNTS] queued {0} property packets with {1} blocks",ppcnt,pbcnt);
|
||||
// m_log.WarnFormat("[PACKETCOUNTS] queued {0} family property packets with {1} blocks",fpcnt,fbcnt);
|
||||
}
|
||||
|
||||
private ObjectPropertiesFamilyPacket.ObjectDataBlock CreateObjectPropertiesFamilyBlock(SceneObjectPart sop, uint requestFlags)
|
||||
{
|
||||
ObjectPropertiesFamilyPacket.ObjectDataBlock block = new ObjectPropertiesFamilyPacket.ObjectDataBlock();
|
||||
|
||||
block.RequestFlags = requestFlags;
|
||||
block.ObjectID = sop.UUID;
|
||||
if (sop.OwnerID == sop.GroupID)
|
||||
block.OwnerID = UUID.Zero;
|
||||
else
|
||||
block.OwnerID = sop.OwnerID;
|
||||
block.GroupID = sop.GroupID;
|
||||
block.BaseMask = sop.BaseMask;
|
||||
block.OwnerMask = sop.OwnerMask;
|
||||
block.GroupMask = sop.GroupMask;
|
||||
block.EveryoneMask = sop.EveryoneMask;
|
||||
block.NextOwnerMask = sop.NextOwnerMask;
|
||||
|
||||
// TODO: More properties are needed in SceneObjectPart!
|
||||
block.OwnershipCost = sop.OwnershipCost;
|
||||
block.SaleType = sop.ObjectSaleType;
|
||||
block.SalePrice = sop.SalePrice;
|
||||
block.Category = sop.Category;
|
||||
block.LastOwnerID = sop.CreatorID; // copied from old SOG call... is this right?
|
||||
block.Name = Util.StringToBytes256(sop.Name);
|
||||
block.Description = Util.StringToBytes256(sop.Description);
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
private ObjectPropertiesPacket.ObjectDataBlock CreateObjectPropertiesBlock(SceneObjectPart sop)
|
||||
{
|
||||
//ObjectPropertiesPacket proper = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties);
|
||||
// TODO: don't create new blocks if recycling an old packet
|
||||
|
@ -4127,87 +4180,38 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
|||
ObjectPropertiesPacket.ObjectDataBlock block =
|
||||
new ObjectPropertiesPacket.ObjectDataBlock();
|
||||
|
||||
block.ItemID = ItemID;
|
||||
block.CreationDate = CreationDate;
|
||||
block.CreatorID = CreatorUUID;
|
||||
block.FolderID = FolderUUID;
|
||||
block.FromTaskID = FromTaskUUID;
|
||||
block.GroupID = GroupUUID;
|
||||
block.InventorySerial = InventorySerial;
|
||||
block.ObjectID = sop.UUID;
|
||||
block.Name = Util.StringToBytes256(sop.Name);
|
||||
block.Description = Util.StringToBytes256(sop.Description);
|
||||
|
||||
block.LastOwnerID = LastOwnerUUID;
|
||||
// proper.ObjectData[0].LastOwnerID = UUID.Zero;
|
||||
|
||||
block.ObjectID = ObjectUUID;
|
||||
if (OwnerUUID == GroupUUID)
|
||||
block.CreationDate = (ulong)sop.CreationDate * 1000000; // viewer wants date in microseconds
|
||||
block.CreatorID = sop.CreatorID;
|
||||
block.GroupID = sop.GroupID;
|
||||
block.LastOwnerID = sop.LastOwnerID;
|
||||
if (sop.OwnerID == sop.GroupID)
|
||||
block.OwnerID = UUID.Zero;
|
||||
else
|
||||
block.OwnerID = OwnerUUID;
|
||||
block.TouchName = Util.StringToBytes256(TouchTitle);
|
||||
block.TextureID = TextureID;
|
||||
block.SitName = Util.StringToBytes256(SitTitle);
|
||||
block.Name = Util.StringToBytes256(ItemName);
|
||||
block.Description = Util.StringToBytes256(ItemDescription);
|
||||
block.OwnerMask = OwnerMask;
|
||||
block.NextOwnerMask = NextOwnerMask;
|
||||
block.GroupMask = GroupMask;
|
||||
block.EveryoneMask = EveryoneMask;
|
||||
block.BaseMask = BaseMask;
|
||||
// proper.ObjectData[0].AggregatePerms = 53;
|
||||
// proper.ObjectData[0].AggregatePermTextures = 0;
|
||||
// proper.ObjectData[0].AggregatePermTexturesOwner = 0;
|
||||
block.SaleType = saleType;
|
||||
block.SalePrice = salePrice;
|
||||
block.OwnerID = sop.OwnerID;
|
||||
|
||||
lock (m_propertiesPacketTimer)
|
||||
{
|
||||
m_propertiesBlocks.Add(block);
|
||||
block.ItemID = sop.FromUserInventoryItemID;
|
||||
block.FolderID = UUID.Zero; // sop.FromFolderID ??
|
||||
block.FromTaskID = UUID.Zero; // ???
|
||||
block.InventorySerial = (short)sop.InventorySerial;
|
||||
|
||||
int length = 0;
|
||||
foreach (ObjectPropertiesPacket.ObjectDataBlock b in m_propertiesBlocks)
|
||||
{
|
||||
length += b.Length;
|
||||
}
|
||||
if (length > 1100) // FIXME: use real MTU
|
||||
{
|
||||
ProcessObjectPropertiesPacket(null, null);
|
||||
m_propertiesPacketTimer.Stop();
|
||||
return;
|
||||
}
|
||||
SceneObjectPart root = sop.ParentGroup.RootPart;
|
||||
|
||||
m_propertiesPacketTimer.Stop();
|
||||
m_propertiesPacketTimer.Start();
|
||||
}
|
||||
block.TouchName = Util.StringToBytes256(root.TouchName);
|
||||
block.TextureID = new byte[0]; // TextureID ???
|
||||
block.SitName = Util.StringToBytes256(root.SitName);
|
||||
block.OwnerMask = root.OwnerMask;
|
||||
block.NextOwnerMask = root.NextOwnerMask;
|
||||
block.GroupMask = root.GroupMask;
|
||||
block.EveryoneMask = root.EveryoneMask;
|
||||
block.BaseMask = root.BaseMask;
|
||||
block.SaleType = root.ObjectSaleType;
|
||||
block.SalePrice = root.SalePrice;
|
||||
|
||||
//proper.Header.Zerocoded = true;
|
||||
//OutPacket(proper, ThrottleOutPacketType.Task);
|
||||
}
|
||||
|
||||
private void ProcessObjectPropertiesPacket(Object sender, ElapsedEventArgs e)
|
||||
{
|
||||
ObjectPropertiesPacket proper = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties);
|
||||
|
||||
lock (m_propertiesPacketTimer)
|
||||
{
|
||||
m_propertiesPacketTimer.Stop();
|
||||
|
||||
if (m_propertiesBlocks.Count == 0)
|
||||
return;
|
||||
|
||||
proper.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[m_propertiesBlocks.Count];
|
||||
|
||||
int index = 0;
|
||||
|
||||
foreach (ObjectPropertiesPacket.ObjectDataBlock b in m_propertiesBlocks)
|
||||
{
|
||||
proper.ObjectData[index++] = b;
|
||||
}
|
||||
|
||||
m_propertiesBlocks.Clear();
|
||||
}
|
||||
|
||||
proper.Header.Zerocoded = true;
|
||||
OutPacket(proper, ThrottleOutPacketType.Task);
|
||||
return block;
|
||||
}
|
||||
|
||||
#region Estate Data Sending Methods
|
||||
|
@ -4548,6 +4552,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
|||
|
||||
public void SendForceClientSelectObjects(List<uint> ObjectIDs)
|
||||
{
|
||||
m_log.WarnFormat("[LLCLIENTVIEW] sending select with {0} objects", ObjectIDs.Count);
|
||||
|
||||
bool firstCall = true;
|
||||
const int MAX_OBJECTS_PER_PACKET = 251;
|
||||
ForceObjectSelectPacket pack = (ForceObjectSelectPacket)PacketPool.Instance.GetPacket(PacketType.ForceObjectSelect);
|
||||
|
|
|
@ -135,7 +135,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
|||
private int m_nextOnQueueEmpty = 1;
|
||||
|
||||
/// <summary>Throttle bucket for this agent's connection</summary>
|
||||
private readonly TokenBucket m_throttle;
|
||||
private readonly TokenBucket m_throttleClient;
|
||||
/// <summary>Throttle bucket for this agent's connection</summary>
|
||||
private readonly TokenBucket m_throttleCategory;
|
||||
/// <summary>Throttle buckets for each packet category</summary>
|
||||
private readonly TokenBucket[] m_throttleCategories;
|
||||
/// <summary>Outgoing queues for throttled packets</summary>
|
||||
|
@ -175,7 +177,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
|||
m_maxRTO = maxRTO;
|
||||
|
||||
// Create a token bucket throttle for this client that has the scene token bucket as a parent
|
||||
m_throttle = new TokenBucket(parentThrottle, rates.TotalLimit, rates.Total);
|
||||
m_throttleClient = new TokenBucket(parentThrottle, rates.TotalLimit);
|
||||
// Create a token bucket throttle for the total categary with the client bucket as a throttle
|
||||
m_throttleCategory = new TokenBucket(m_throttleClient, rates.TotalLimit);
|
||||
// Create an array of token buckets for this clients different throttle categories
|
||||
m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT];
|
||||
|
||||
|
@ -186,7 +190,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
|||
// Initialize the packet outboxes, where packets sit while they are waiting for tokens
|
||||
m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>();
|
||||
// Initialize the token buckets that control the throttling for each category
|
||||
m_throttleCategories[i] = new TokenBucket(m_throttle, rates.GetLimit(type), rates.GetRate(type));
|
||||
m_throttleCategories[i] = new TokenBucket(m_throttleCategory, rates.GetLimit(type));
|
||||
}
|
||||
|
||||
// Default the retransmission timeout to three seconds
|
||||
|
@ -207,6 +211,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
|||
m_packetOutboxes[i].Clear();
|
||||
m_nextPackets[i] = null;
|
||||
}
|
||||
|
||||
// pull the throttle out of the scene throttle
|
||||
m_throttleClient.Parent.UnregisterRequest(m_throttleClient);
|
||||
OnPacketStats = null;
|
||||
OnQueueEmpty = null;
|
||||
}
|
||||
|
@ -217,6 +224,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
|||
/// <returns>Information about the client connection</returns>
|
||||
public ClientInfo GetClientInfo()
|
||||
{
|
||||
///<mic>
|
||||
TokenBucket tb;
|
||||
|
||||
tb = m_throttleClient.Parent;
|
||||
m_log.WarnFormat("[TOKENS] {3}: Actual={0},Request={1},TotalRequest={2}",tb.DripRate,tb.RequestedDripRate,tb.TotalDripRequest,"ROOT");
|
||||
|
||||
tb = m_throttleClient;
|
||||
m_log.WarnFormat("[TOKENS] {3}: Actual={0},Request={1},TotalRequest={2}",tb.DripRate,tb.RequestedDripRate,tb.TotalDripRequest," CLIENT");
|
||||
|
||||
tb = m_throttleCategory;
|
||||
m_log.WarnFormat("[TOKENS] {3}: Actual={0},Request={1},TotalRequest={2}",tb.DripRate,tb.RequestedDripRate,tb.TotalDripRequest," CATEGORY");
|
||||
|
||||
for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
|
||||
{
|
||||
tb = m_throttleCategories[i];
|
||||
m_log.WarnFormat("[TOKENS] {4} <{0}:{1}>: Actual={2},Requested={3}",AgentID,i,tb.DripRate,tb.RequestedDripRate," BUCKET");
|
||||
}
|
||||
|
||||
///</mic>
|
||||
|
||||
// TODO: This data structure is wrong in so many ways. Locking and copying the entire lists
|
||||
// of pending and needed ACKs for every client every time some method wants information about
|
||||
// this connection is a recipe for poor performance
|
||||
|
@ -224,13 +251,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
|||
info.pendingAcks = new Dictionary<uint, uint>();
|
||||
info.needAck = new Dictionary<uint, byte[]>();
|
||||
|
||||
info.resendThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate;
|
||||
info.landThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate;
|
||||
info.windThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate;
|
||||
info.cloudThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate;
|
||||
info.taskThrottle = m_throttleCategories[(int)ThrottleOutPacketType.State].DripRate + m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate;
|
||||
info.assetThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate;
|
||||
info.textureThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate;
|
||||
info.resendThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate;
|
||||
info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate;
|
||||
info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate;
|
||||
info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate;
|
||||
// info.taskThrottle = m_throttleCategories[(int)ThrottleOutPacketType.State].DripRate + m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate;
|
||||
info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate;
|
||||
info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate;
|
||||
info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate;
|
||||
info.totalThrottle = info.resendThrottle + info.landThrottle + info.windThrottle + info.cloudThrottle +
|
||||
info.taskThrottle + info.assetThrottle + info.textureThrottle;
|
||||
|
||||
|
@ -318,8 +346,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
|||
int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
|
||||
int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
|
||||
// State is a subcategory of task that we allocate a percentage to
|
||||
int state = (int)((float)task * STATE_TASK_PERCENTAGE);
|
||||
task -= state;
|
||||
int state = 0;
|
||||
// int state = (int)((float)task * STATE_TASK_PERCENTAGE);
|
||||
// task -= state;
|
||||
|
||||
// Make sure none of the throttles are set below our packet MTU,
|
||||
// otherwise a throttle could become permanently clogged
|
||||
|
@ -340,40 +369,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
|||
// Update the token buckets with new throttle values
|
||||
TokenBucket bucket;
|
||||
|
||||
bucket = m_throttle;
|
||||
bucket.MaxBurst = total;
|
||||
bucket = m_throttleCategory;
|
||||
bucket.RequestedDripRate = total;
|
||||
|
||||
bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend];
|
||||
bucket.DripRate = resend;
|
||||
bucket.MaxBurst = resend;
|
||||
bucket.RequestedDripRate = resend;
|
||||
|
||||
bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land];
|
||||
bucket.DripRate = land;
|
||||
bucket.MaxBurst = land;
|
||||
bucket.RequestedDripRate = land;
|
||||
|
||||
bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind];
|
||||
bucket.DripRate = wind;
|
||||
bucket.MaxBurst = wind;
|
||||
bucket.RequestedDripRate = wind;
|
||||
|
||||
bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud];
|
||||
bucket.DripRate = cloud;
|
||||
bucket.MaxBurst = cloud;
|
||||
bucket.RequestedDripRate = cloud;
|
||||
|
||||
bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset];
|
||||
bucket.DripRate = asset;
|
||||
bucket.MaxBurst = asset;
|
||||
bucket.RequestedDripRate = asset;
|
||||
|
||||
bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task];
|
||||
bucket.DripRate = task + state;
|
||||
bucket.MaxBurst = task + state;
|
||||
bucket.RequestedDripRate = task;
|
||||
|
||||
bucket = m_throttleCategories[(int)ThrottleOutPacketType.State];
|
||||
bucket.DripRate = state;
|
||||
bucket.MaxBurst = state;
|
||||
bucket.RequestedDripRate = state;
|
||||
|
||||
bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture];
|
||||
bucket.DripRate = texture;
|
||||
bucket.MaxBurst = texture;
|
||||
bucket.RequestedDripRate = texture;
|
||||
|
||||
// Reset the packed throttles cached data
|
||||
m_packedThrottles = null;
|
||||
|
@ -388,14 +409,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
|||
data = new byte[7 * 4];
|
||||
int i = 0;
|
||||
|
||||
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate), 0, data, i, 4); i += 4;
|
||||
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate), 0, data, i, 4); i += 4;
|
||||
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate), 0, data, i, 4); i += 4;
|
||||
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate), 0, data, i, 4); i += 4;
|
||||
Buffer.BlockCopy(Utils.FloatToBytes((float)(m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate) +
|
||||
m_throttleCategories[(int)ThrottleOutPacketType.State].DripRate), 0, data, i, 4); i += 4;
|
||||
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate), 0, data, i, 4); i += 4;
|
||||
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate), 0, data, i, 4); i += 4;
|
||||
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].RequestedDripRate), 0, data, i, 4); i += 4;
|
||||
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Land].RequestedDripRate), 0, data, i, 4); i += 4;
|
||||
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].RequestedDripRate), 0, data, i, 4); i += 4;
|
||||
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].RequestedDripRate), 0, data, i, 4); i += 4;
|
||||
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Task].RequestedDripRate), 0, data, i, 4); i += 4;
|
||||
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].RequestedDripRate), 0, data, i, 4); i += 4;
|
||||
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].RequestedDripRate), 0, data, i, 4); i += 4;
|
||||
|
||||
m_packedThrottles = data;
|
||||
}
|
||||
|
@ -428,6 +448,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
|||
|
||||
TokenBucket bucket = m_throttleCategories[category];
|
||||
|
||||
// Don't send this packet if there is already a packet waiting in the queue
|
||||
// even if we have the tokens to send it, tokens should go to the already
|
||||
// queued packets
|
||||
if (queue.Count > 0)
|
||||
{
|
||||
queue.Enqueue(packet);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if (!forceQueue && bucket.RemoveTokens(packet.Buffer.DataLength))
|
||||
{
|
||||
// Enough tokens were removed from the bucket, the packet will not be queued
|
||||
|
|
|
@ -228,7 +228,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
|||
}
|
||||
#endregion BinaryStats
|
||||
|
||||
m_throttle = new TokenBucket(null, sceneThrottleBps, sceneThrottleBps);
|
||||
m_throttle = new TokenBucket(null, sceneThrottleBps);
|
||||
ThrottleRates = new ThrottleRates(configSource);
|
||||
}
|
||||
|
||||
|
|
|
@ -78,7 +78,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
|||
}
|
||||
}
|
||||
|
||||
public bool Enqueue(uint pqueue, EntityUpdate value)
|
||||
public bool Enqueue(uint pqueue, IEntityUpdate value)
|
||||
{
|
||||
LookupItem lookup;
|
||||
|
||||
|
@ -87,7 +87,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
|||
if (m_lookupTable.TryGetValue(localid, out lookup))
|
||||
{
|
||||
entry = lookup.Heap[lookup.Handle].EntryOrder;
|
||||
value.Flags |= lookup.Heap[lookup.Handle].Value.Flags;
|
||||
value.Update(lookup.Heap[lookup.Handle].Value);
|
||||
lookup.Heap.Remove(lookup.Handle);
|
||||
}
|
||||
|
||||
|
@ -99,7 +99,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
|||
return true;
|
||||
}
|
||||
|
||||
internal bool TryDequeue(out EntityUpdate value, out Int32 timeinqueue)
|
||||
internal bool TryDequeue(out IEntityUpdate value, out Int32 timeinqueue)
|
||||
{
|
||||
for (int i = 0; i < m_numberOfQueues; ++i)
|
||||
{
|
||||
|
@ -122,7 +122,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
|||
}
|
||||
|
||||
timeinqueue = 0;
|
||||
value = default(EntityUpdate);
|
||||
value = default(IEntityUpdate);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -175,8 +175,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
|||
#region MinHeapItem
|
||||
private struct MinHeapItem : IComparable<MinHeapItem>
|
||||
{
|
||||
private EntityUpdate value;
|
||||
internal EntityUpdate Value {
|
||||
private IEntityUpdate value;
|
||||
internal IEntityUpdate Value {
|
||||
get {
|
||||
return this.value;
|
||||
}
|
||||
|
@ -212,7 +212,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
|||
this.pqueue = pqueue;
|
||||
}
|
||||
|
||||
internal MinHeapItem(uint pqueue, UInt64 entryorder, EntityUpdate value)
|
||||
internal MinHeapItem(uint pqueue, UInt64 entryorder, IEntityUpdate value)
|
||||
{
|
||||
this.entrytime = Util.EnvironmentTickCount();
|
||||
this.entryorder = entryorder;
|
||||
|
|
|
@ -26,6 +26,10 @@
|
|||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using log4net;
|
||||
|
||||
namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
{
|
||||
|
@ -35,19 +39,40 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
|||
/// </summary>
|
||||
public class TokenBucket
|
||||
{
|
||||
/// <summary>Parent bucket to this bucket, or null if this is a root
|
||||
/// bucket</summary>
|
||||
TokenBucket parent;
|
||||
/// <summary>Size of the bucket in bytes. If zero, the bucket has
|
||||
/// infinite capacity</summary>
|
||||
int maxBurst;
|
||||
/// <summary>Rate that the bucket fills, in bytes per millisecond. If
|
||||
/// zero, the bucket always remains full</summary>
|
||||
int tokensPerMS;
|
||||
/// <summary>Number of tokens currently in the bucket</summary>
|
||||
int content;
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
private static Int32 m_counter = 0;
|
||||
|
||||
private Int32 m_identifier;
|
||||
|
||||
/// <summary>
|
||||
/// Number of ticks (ms) per quantum, drip rate and max burst
|
||||
/// are defined over this interval.
|
||||
/// </summary>
|
||||
private const Int32 m_ticksPerQuantum = 1000;
|
||||
|
||||
/// <summary>
|
||||
/// This is the number of quantums worth of packets that can
|
||||
/// be accommodated during a burst
|
||||
/// </summary>
|
||||
private const Double m_quantumsPerBurst = 1.5;
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
private const Int32 m_minimumDripRate = 1400;
|
||||
|
||||
/// <summary>Time of the last drip, in system ticks</summary>
|
||||
int lastDrip;
|
||||
private Int32 m_lastDrip;
|
||||
|
||||
/// <summary>
|
||||
/// The number of bytes that can be sent at this moment. This is the
|
||||
/// current number of tokens in the bucket
|
||||
/// </summary>
|
||||
private Int64 m_tokenCount;
|
||||
|
||||
/// <summary>
|
||||
/// Map of children buckets and their requested maximum burst rate
|
||||
/// </summary>
|
||||
private Dictionary<TokenBucket,Int64> m_children = new Dictionary<TokenBucket,Int64>();
|
||||
|
||||
#region Properties
|
||||
|
||||
|
@ -56,69 +81,85 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
|||
/// parent. The parent bucket will limit the aggregate bandwidth of all
|
||||
/// of its children buckets
|
||||
/// </summary>
|
||||
private TokenBucket m_parent;
|
||||
public TokenBucket Parent
|
||||
{
|
||||
get { return parent; }
|
||||
get { return m_parent; }
|
||||
set { m_parent = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maximum burst rate in bytes per second. This is the maximum number
|
||||
/// of tokens that can accumulate in the bucket at any one time
|
||||
/// of tokens that can accumulate in the bucket at any one time. This
|
||||
/// also sets the total request for leaf nodes
|
||||
/// </summary>
|
||||
public int MaxBurst
|
||||
private Int64 m_burstRate;
|
||||
public Int64 RequestedBurstRate
|
||||
{
|
||||
get { return maxBurst; }
|
||||
set { maxBurst = (value >= 0 ? value : 0); }
|
||||
get { return m_burstRate; }
|
||||
set { m_burstRate = (value < 0 ? 0 : value); }
|
||||
}
|
||||
|
||||
public Int64 BurstRate
|
||||
{
|
||||
get {
|
||||
double rate = RequestedBurstRate * BurstRateModifier();
|
||||
if (rate < m_minimumDripRate * m_quantumsPerBurst)
|
||||
rate = m_minimumDripRate * m_quantumsPerBurst;
|
||||
|
||||
return (Int64) rate;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The speed limit of this bucket in bytes per second. This is the
|
||||
/// number of tokens that are added to the bucket per second
|
||||
/// number of tokens that are added to the bucket per quantum
|
||||
/// </summary>
|
||||
/// <remarks>Tokens are added to the bucket any time
|
||||
/// <seealso cref="RemoveTokens"/> is called, at the granularity of
|
||||
/// the system tick interval (typically around 15-22ms)</remarks>
|
||||
public int DripRate
|
||||
private Int64 m_dripRate;
|
||||
public Int64 RequestedDripRate
|
||||
{
|
||||
get { return tokensPerMS * 1000; }
|
||||
set
|
||||
{
|
||||
if (value == 0)
|
||||
tokensPerMS = 0;
|
||||
else
|
||||
{
|
||||
int bpms = (int)((float)value / 1000.0f);
|
||||
|
||||
if (bpms <= 0)
|
||||
tokensPerMS = 1; // 1 byte/ms is the minimum granularity
|
||||
else
|
||||
tokensPerMS = bpms;
|
||||
get { return (m_dripRate == 0 ? m_totalDripRequest : m_dripRate); }
|
||||
set {
|
||||
m_dripRate = (value < 0 ? 0 : value);
|
||||
m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst);
|
||||
m_totalDripRequest = m_dripRate;
|
||||
if (m_parent != null)
|
||||
m_parent.RegisterRequest(this,m_dripRate);
|
||||
}
|
||||
}
|
||||
|
||||
public Int64 DripRate
|
||||
{
|
||||
get {
|
||||
if (m_parent == null)
|
||||
return Math.Min(RequestedDripRate,TotalDripRequest);
|
||||
|
||||
double rate = (double)RequestedDripRate * m_parent.DripRateModifier();
|
||||
if (rate < m_minimumDripRate)
|
||||
rate = m_minimumDripRate;
|
||||
|
||||
return (Int64)rate;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The speed limit of this bucket in bytes per millisecond
|
||||
/// The current total of the requested maximum burst rates of
|
||||
/// this bucket's children buckets.
|
||||
/// </summary>
|
||||
public int DripPerMS
|
||||
private Int64 m_totalDripRequest;
|
||||
public Int64 TotalDripRequest
|
||||
{
|
||||
get { return tokensPerMS; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The number of bytes that can be sent at this moment. This is the
|
||||
/// current number of tokens in the bucket
|
||||
/// <remarks>If this bucket has a parent bucket that does not have
|
||||
/// enough tokens for a request, <seealso cref="RemoveTokens"/> will
|
||||
/// return false regardless of the content of this bucket</remarks>
|
||||
/// </summary>
|
||||
public int Content
|
||||
{
|
||||
get { return content; }
|
||||
get { return m_totalDripRequest; }
|
||||
set { m_totalDripRequest = value; }
|
||||
}
|
||||
|
||||
#endregion Properties
|
||||
|
||||
#region Constructor
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
|
@ -128,12 +169,76 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
|||
/// zero if this bucket has no maximum capacity</param>
|
||||
/// <param name="dripRate">Rate that the bucket fills, in bytes per
|
||||
/// second. If zero, the bucket always remains full</param>
|
||||
public TokenBucket(TokenBucket parent, int maxBurst, int dripRate)
|
||||
public TokenBucket(TokenBucket parent, Int64 dripRate)
|
||||
{
|
||||
this.parent = parent;
|
||||
MaxBurst = maxBurst;
|
||||
DripRate = dripRate;
|
||||
lastDrip = Environment.TickCount;
|
||||
m_identifier = m_counter++;
|
||||
|
||||
Parent = parent;
|
||||
RequestedDripRate = dripRate;
|
||||
// TotalDripRequest = dripRate; // this will be overwritten when a child node registers
|
||||
// MaxBurst = (Int64)((double)dripRate * m_quantumsPerBurst);
|
||||
m_lastDrip = Environment.TickCount & Int32.MaxValue;
|
||||
}
|
||||
|
||||
#endregion Constructor
|
||||
|
||||
/// <summary>
|
||||
/// Compute a modifier for the MaxBurst rate. This is 1.0, meaning
|
||||
/// no modification if the requested bandwidth is less than the
|
||||
/// max burst bandwidth all the way to the root of the throttle
|
||||
/// hierarchy. However, if any of the parents is over-booked, then
|
||||
/// the modifier will be less than 1.
|
||||
/// </summary>
|
||||
private double DripRateModifier()
|
||||
{
|
||||
Int64 driprate = DripRate;
|
||||
return driprate >= TotalDripRequest ? 1.0 : (double)driprate / (double)TotalDripRequest;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
private double BurstRateModifier()
|
||||
{
|
||||
// for now... burst rate is always m_quantumsPerBurst (constant)
|
||||
// larger than drip rate so the ratio of burst requests is the
|
||||
// same as the drip ratio
|
||||
return DripRateModifier();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register drip rate requested by a child of this throttle. Pass the
|
||||
/// changes up the hierarchy.
|
||||
/// </summary>
|
||||
public void RegisterRequest(TokenBucket child, Int64 request)
|
||||
{
|
||||
m_children[child] = request;
|
||||
// m_totalDripRequest = m_children.Values.Sum();
|
||||
|
||||
m_totalDripRequest = 0;
|
||||
foreach (KeyValuePair<TokenBucket, Int64> cref in m_children)
|
||||
m_totalDripRequest += cref.Value;
|
||||
|
||||
// Pass the new values up to the parent
|
||||
if (m_parent != null)
|
||||
m_parent.RegisterRequest(this,Math.Min(RequestedDripRate, TotalDripRequest));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove the rate requested by a child of this throttle. Pass the
|
||||
/// changes up the hierarchy.
|
||||
/// </summary>
|
||||
public void UnregisterRequest(TokenBucket child)
|
||||
{
|
||||
m_children.Remove(child);
|
||||
// m_totalDripRequest = m_children.Values.Sum();
|
||||
|
||||
m_totalDripRequest = 0;
|
||||
foreach (KeyValuePair<TokenBucket, Int64> cref in m_children)
|
||||
m_totalDripRequest += cref.Value;
|
||||
|
||||
// Pass the new values up to the parent
|
||||
if (m_parent != null)
|
||||
m_parent.RegisterRequest(this,Math.Min(RequestedDripRate, TotalDripRequest));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -142,64 +247,67 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
|||
/// <param name="amount">Number of tokens to remove from the bucket</param>
|
||||
/// <returns>True if the requested number of tokens were removed from
|
||||
/// the bucket, otherwise false</returns>
|
||||
public bool RemoveTokens(int amount)
|
||||
public bool RemoveTokens(Int64 amount)
|
||||
{
|
||||
if (maxBurst == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (amount > maxBurst)
|
||||
{
|
||||
throw new Exception("amount " + amount + " exceeds maxBurst " + maxBurst);
|
||||
}
|
||||
|
||||
// Deposit tokens for this interval
|
||||
Drip();
|
||||
|
||||
if (content < amount)
|
||||
// If we have enough tokens then remove them and return
|
||||
if (m_tokenCount - amount >= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (parent != null && !parent.RemoveTokens(amount))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
content -= amount;
|
||||
// we don't have to remove from the parent, the drip rate is already
|
||||
// reflective of the drip rate limits in the parent
|
||||
m_tokenCount -= amount;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deposit tokens into the bucket from a child bucket that did
|
||||
/// not use all of its available tokens
|
||||
/// </summary>
|
||||
private void Deposit(Int64 count)
|
||||
{
|
||||
m_tokenCount += count;
|
||||
|
||||
// Deposit the overflow in the parent bucket, this is how we share
|
||||
// unused bandwidth
|
||||
Int64 burstrate = BurstRate;
|
||||
if (m_tokenCount > burstrate)
|
||||
m_tokenCount = burstrate;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add tokens to the bucket over time. The number of tokens added each
|
||||
/// call depends on the length of time that has passed since the last
|
||||
/// call to Drip
|
||||
/// </summary>
|
||||
/// <returns>True if tokens were added to the bucket, otherwise false</returns>
|
||||
public bool Drip()
|
||||
private void Drip()
|
||||
{
|
||||
if (tokensPerMS == 0)
|
||||
// This should never happen... means we are a leaf node and were created
|
||||
// with no drip rate...
|
||||
if (DripRate == 0)
|
||||
{
|
||||
content = maxBurst;
|
||||
return true;
|
||||
m_log.WarnFormat("[TOKENBUCKET] something odd is happening and drip rate is 0");
|
||||
return;
|
||||
}
|
||||
|
||||
int now = Environment.TickCount;
|
||||
int deltaMS = now - lastDrip;
|
||||
lastDrip = now;
|
||||
// Determine the interval over which we are adding tokens, never add
|
||||
// more than a single quantum of tokens
|
||||
Int32 now = Environment.TickCount & Int32.MaxValue;
|
||||
Int32 deltaMS = Math.Min(now - m_lastDrip, m_ticksPerQuantum);
|
||||
|
||||
m_lastDrip = now;
|
||||
|
||||
// This can be 0 in the very unusual case that the timer wrapped
|
||||
// It can be 0 if we try add tokens at a sub-tick rate
|
||||
if (deltaMS <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return;
|
||||
|
||||
long dripAmount = (long)deltaMS * (long)tokensPerMS + (long)content;
|
||||
if (dripAmount > maxBurst)
|
||||
{
|
||||
dripAmount = maxBurst;
|
||||
}
|
||||
content = (int)dripAmount;
|
||||
return true;
|
||||
Deposit(deltaMS * DripRate / m_ticksPerQuantum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -702,18 +702,12 @@ namespace OpenSim.Region.Examples.SimpleModule
|
|||
{
|
||||
}
|
||||
|
||||
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)
|
||||
public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
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)
|
||||
public void SendObjectPropertiesReply(ISceneEntity entity)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -2111,10 +2111,12 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
/// <param name="part"></param>
|
||||
public void ServiceObjectPropertiesFamilyRequest(IClientAPI remoteClient, UUID AgentID, uint RequestFlags)
|
||||
{
|
||||
remoteClient.SendObjectPropertiesFamilyData(RequestFlags, RootPart.UUID, RootPart.OwnerID, RootPart.GroupID, RootPart.BaseMask,
|
||||
RootPart.OwnerMask, RootPart.GroupMask, RootPart.EveryoneMask, RootPart.NextOwnerMask,
|
||||
RootPart.OwnershipCost, RootPart.ObjectSaleType, RootPart.SalePrice, RootPart.Category,
|
||||
RootPart.CreatorID, RootPart.Name, RootPart.Description);
|
||||
remoteClient.SendObjectPropertiesFamilyData(RootPart, RequestFlags);
|
||||
|
||||
// remoteClient.SendObjectPropertiesFamilyData(RequestFlags, RootPart.UUID, RootPart.OwnerID, RootPart.GroupID, RootPart.BaseMask,
|
||||
// RootPart.OwnerMask, RootPart.GroupMask, RootPart.EveryoneMask, RootPart.NextOwnerMask,
|
||||
// RootPart.OwnershipCost, RootPart.ObjectSaleType, RootPart.SalePrice, RootPart.Category,
|
||||
// RootPart.CreatorID, RootPart.Name, RootPart.Description);
|
||||
}
|
||||
|
||||
public void SetPartOwner(SceneObjectPart part, UUID cAgentID, UUID cGroupID)
|
||||
|
|
|
@ -2093,15 +2093,7 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
|
||||
public void GetProperties(IClientAPI client)
|
||||
{
|
||||
//Viewer wants date in microseconds so multiply it by 1,000,000.
|
||||
client.SendObjectPropertiesReply(
|
||||
m_fromUserInventoryItemID, (ulong)_creationDate*(ulong)1e6, _creatorID, UUID.Zero, UUID.Zero,
|
||||
_groupID, (short)InventorySerial, _lastOwnerID, UUID, _ownerID,
|
||||
ParentGroup.RootPart.TouchName, new byte[0], ParentGroup.RootPart.SitName, Name, Description,
|
||||
ParentGroup.RootPart._ownerMask, ParentGroup.RootPart._nextOwnerMask, ParentGroup.RootPart._groupMask, ParentGroup.RootPart._everyoneMask,
|
||||
ParentGroup.RootPart._baseMask,
|
||||
ParentGroup.RootPart.ObjectSaleType,
|
||||
ParentGroup.RootPart.SalePrice);
|
||||
client.SendObjectPropertiesReply(this);
|
||||
}
|
||||
|
||||
public UUID GetRootPartUUID()
|
||||
|
|
|
@ -1338,14 +1338,13 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
|
|||
|
||||
}
|
||||
|
||||
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)
|
||||
public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
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)
|
||||
public void SendObjectPropertiesReply(ISceneEntity entity)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void SendAgentOffline(UUID[] agentIDs)
|
||||
|
|
|
@ -786,18 +786,12 @@ namespace OpenSim.Region.OptionalModules.World.NPC
|
|||
{
|
||||
}
|
||||
|
||||
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)
|
||||
public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
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)
|
||||
public void SendObjectPropertiesReply(ISceneEntity entity)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -816,18 +816,11 @@ namespace OpenSim.Tests.Common.Mock
|
|||
{
|
||||
}
|
||||
|
||||
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)
|
||||
public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags)
|
||||
{
|
||||
}
|
||||
|
||||
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)
|
||||
public void SendObjectPropertiesReply(ISceneEntity entity)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue