mirror of
https://github.com/opensim/opensim.git
synced 2026-08-01 06:06:06 +08:00
Merge branch 'master' into careminster-presence-refactor
This commit is contained in:
@@ -50,43 +50,17 @@ using Nini.Config;
|
||||
|
||||
namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
{
|
||||
#region Enums
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the fields that have been changed when sending a prim or
|
||||
/// avatar update
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum PrimUpdateFlags : uint
|
||||
public class EntityUpdate
|
||||
{
|
||||
None = 0,
|
||||
AttachmentPoint = 1 << 0,
|
||||
Material = 1 << 1,
|
||||
ClickAction = 1 << 2,
|
||||
Scale = 1 << 3,
|
||||
ParentID = 1 << 4,
|
||||
PrimFlags = 1 << 5,
|
||||
PrimData = 1 << 6,
|
||||
MediaURL = 1 << 7,
|
||||
ScratchPad = 1 << 8,
|
||||
Textures = 1 << 9,
|
||||
TextureAnim = 1 << 10,
|
||||
NameValue = 1 << 11,
|
||||
Position = 1 << 12,
|
||||
Rotation = 1 << 13,
|
||||
Velocity = 1 << 14,
|
||||
Acceleration = 1 << 15,
|
||||
AngularVelocity = 1 << 16,
|
||||
CollisionPlane = 1 << 17,
|
||||
Text = 1 << 18,
|
||||
Particles = 1 << 19,
|
||||
ExtraData = 1 << 20,
|
||||
Sound = 1 << 21,
|
||||
Joint = 1 << 22,
|
||||
FullUpdate = UInt32.MaxValue
|
||||
}
|
||||
public ISceneEntity Entity;
|
||||
public PrimUpdateFlags Flags;
|
||||
|
||||
#endregion Enums
|
||||
public EntityUpdate(ISceneEntity entity, PrimUpdateFlags flags)
|
||||
{
|
||||
Entity = entity;
|
||||
Flags = flags;
|
||||
}
|
||||
}
|
||||
|
||||
public delegate bool PacketMethod(IClientAPI simClient, Packet packet);
|
||||
|
||||
@@ -350,9 +324,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
private readonly IGroupsModule m_GroupsModule;
|
||||
|
||||
private int m_cachedTextureSerial;
|
||||
protected PriorityQueue<double, ImprovedTerseObjectUpdatePacket.ObjectDataBlock> m_avatarTerseUpdates;
|
||||
private PriorityQueue<double, ImprovedTerseObjectUpdatePacket.ObjectDataBlock> m_primTerseUpdates;
|
||||
private PriorityQueue<double, ObjectUpdatePacket.ObjectDataBlock> m_primFullUpdates;
|
||||
private PriorityQueue<double, EntityUpdate> m_entityUpdates;
|
||||
|
||||
/// <value>
|
||||
/// List used in construction of data blocks for an object update packet. This is to stop us having to
|
||||
@@ -466,9 +438,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
|
||||
m_scene = scene;
|
||||
|
||||
m_avatarTerseUpdates = new PriorityQueue<double, ImprovedTerseObjectUpdatePacket.ObjectDataBlock>();
|
||||
m_primTerseUpdates = new PriorityQueue<double, ImprovedTerseObjectUpdatePacket.ObjectDataBlock>();
|
||||
m_primFullUpdates = new PriorityQueue<double, ObjectUpdatePacket.ObjectDataBlock>(m_scene.Entities.Count);
|
||||
m_entityUpdates = new PriorityQueue<double, EntityUpdate>(m_scene.Entities.Count);
|
||||
m_fullUpdateDataBlocksBuilder = new List<ObjectUpdatePacket.ObjectDataBlock>();
|
||||
m_killRecord = new HashSet<uint>();
|
||||
|
||||
@@ -1519,7 +1489,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
kill.Header.Reliable = true;
|
||||
kill.Header.Zerocoded = true;
|
||||
|
||||
lock (m_primFullUpdates.SyncRoot)
|
||||
lock (m_entityUpdates.SyncRoot)
|
||||
{
|
||||
m_killRecord.Add(localID);
|
||||
OutPacket(kill, ThrottleOutPacketType.State);
|
||||
@@ -3419,69 +3389,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
/// <summary>
|
||||
/// Send an ObjectUpdate packet with information about an avatar
|
||||
/// </summary>
|
||||
public void SendAvatarData(SendAvatarData data)
|
||||
public void SendAvatarDataImmediate(ISceneEntity avatar)
|
||||
{
|
||||
ScenePresence presence = avatar as ScenePresence;
|
||||
if (presence == null)
|
||||
return;
|
||||
|
||||
ObjectUpdatePacket objupdate = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
|
||||
objupdate.Header.Zerocoded = true;
|
||||
|
||||
objupdate.RegionData.RegionHandle = data.RegionHandle;
|
||||
objupdate.RegionData.RegionHandle = presence.RegionHandle;
|
||||
objupdate.RegionData.TimeDilation = ushort.MaxValue;
|
||||
|
||||
objupdate.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1];
|
||||
objupdate.ObjectData[0] = CreateAvatarUpdateBlock(data);
|
||||
objupdate.ObjectData[0] = CreateAvatarUpdateBlock(presence);
|
||||
|
||||
OutPacket(objupdate, ThrottleOutPacketType.Task);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send a terse positional/rotation/velocity update about an avatar
|
||||
/// to the client. This avatar can be that of the client itself.
|
||||
/// </summary>
|
||||
public virtual void SendAvatarTerseUpdate(SendAvatarTerseData data)
|
||||
{
|
||||
if (data.Priority == double.NaN)
|
||||
{
|
||||
m_log.Error("[LLClientView] SendAvatarTerseUpdate received a NaN priority, dropping update");
|
||||
return;
|
||||
}
|
||||
|
||||
Quaternion rotation = data.Rotation;
|
||||
if (rotation.W == 0.0f && rotation.X == 0.0f && rotation.Y == 0.0f && rotation.Z == 0.0f)
|
||||
rotation = Quaternion.Identity;
|
||||
|
||||
ImprovedTerseObjectUpdatePacket.ObjectDataBlock terseBlock = CreateImprovedTerseBlock(data);
|
||||
|
||||
lock (m_avatarTerseUpdates.SyncRoot)
|
||||
m_avatarTerseUpdates.Enqueue(data.Priority, terseBlock, data.LocalID);
|
||||
|
||||
// If we received an update about our own avatar, process the avatar update priority queue immediately
|
||||
if (data.AgentID == m_agentId)
|
||||
ProcessAvatarTerseUpdates();
|
||||
}
|
||||
|
||||
protected void ProcessAvatarTerseUpdates()
|
||||
{
|
||||
ImprovedTerseObjectUpdatePacket terse = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate);
|
||||
terse.Header.Reliable = false;
|
||||
terse.Header.Zerocoded = true;
|
||||
|
||||
//terse.RegionData = new ImprovedTerseObjectUpdatePacket.RegionDataBlock();
|
||||
terse.RegionData.RegionHandle = Scene.RegionInfo.RegionHandle;
|
||||
terse.RegionData.TimeDilation = (ushort)(Scene.TimeDilation * ushort.MaxValue);
|
||||
|
||||
lock (m_avatarTerseUpdates.SyncRoot)
|
||||
{
|
||||
int count = Math.Min(m_avatarTerseUpdates.Count, m_udpServer.AvatarTerseUpdatesPerPacket);
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
terse.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[count];
|
||||
for (int i = 0; i < count; i++)
|
||||
terse.ObjectData[i] = m_avatarTerseUpdates.Dequeue();
|
||||
}
|
||||
|
||||
OutPacket(terse, ThrottleOutPacketType.State);
|
||||
}
|
||||
|
||||
public void SendCoarseLocationUpdate(List<UUID> users, List<Vector3> CoarseLocations)
|
||||
{
|
||||
if (!IsActive) return; // We don't need to update inactive clients.
|
||||
@@ -3526,172 +3451,187 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
|
||||
#region Primitive Packet/Data Sending Methods
|
||||
|
||||
public void SendPrimitiveToClient(SendPrimitiveData data)
|
||||
/// <summary>
|
||||
/// Generate one of the object update packets based on PrimUpdateFlags
|
||||
/// and broadcast the packet to clients
|
||||
/// </summary>
|
||||
public void SendPrimUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags)
|
||||
{
|
||||
// string text = data.text;
|
||||
// if (text.IndexOf("\n") >= 0)
|
||||
// text = text.Remove(text.IndexOf("\n"));
|
||||
// m_log.DebugFormat(
|
||||
// "[CLIENT]: Placing request to send full info about prim {0} text {1} to client {2}",
|
||||
// data.localID, text, Name);
|
||||
|
||||
if (data.priority == double.NaN)
|
||||
{
|
||||
m_log.Error("[LLClientView] SendPrimitiveToClient received a NaN priority, dropping update");
|
||||
return;
|
||||
}
|
||||
double priority;
|
||||
|
||||
Quaternion rotation = data.rotation;
|
||||
if (rotation.W == 0.0f && rotation.X == 0.0f && rotation.Y == 0.0f && rotation.Z == 0.0f)
|
||||
rotation = Quaternion.Identity;
|
||||
if (entity is SceneObjectPart)
|
||||
priority = ((SceneObjectPart)entity).ParentGroup.GetUpdatePriority(this);
|
||||
else if (entity is ScenePresence)
|
||||
priority = ((ScenePresence)entity).GetUpdatePriority(this);
|
||||
else
|
||||
priority = 0.0d;
|
||||
|
||||
if (data.AttachPoint > 30 && data.ownerID != AgentId) // Someone else's HUD
|
||||
return;
|
||||
if (data.primShape.State != 0 && data.parentID == 0 && data.primShape.PCode == 9)
|
||||
return;
|
||||
|
||||
ObjectUpdatePacket.ObjectDataBlock objectData = CreatePrimUpdateBlock(data);
|
||||
|
||||
lock (m_primFullUpdates.SyncRoot)
|
||||
m_primFullUpdates.Enqueue(data.priority, objectData, data.localID);
|
||||
lock (m_entityUpdates.SyncRoot)
|
||||
m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags), entity.LocalId);
|
||||
}
|
||||
|
||||
void ProcessPrimFullUpdates()
|
||||
private void ProcessEntityUpdates(int maxUpdates)
|
||||
{
|
||||
ObjectUpdatePacket outPacket = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
|
||||
outPacket.Header.Zerocoded = true;
|
||||
Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>();
|
||||
Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>> compressedUpdateBlocks = new Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>>();
|
||||
Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseUpdateBlocks = new Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>();
|
||||
|
||||
outPacket.RegionData.RegionHandle = Scene.RegionInfo.RegionHandle;
|
||||
outPacket.RegionData.TimeDilation = (ushort)(Scene.TimeDilation * ushort.MaxValue);
|
||||
if (maxUpdates <= 0) maxUpdates = Int32.MaxValue;
|
||||
int updatesThisCall = 0;
|
||||
|
||||
lock (m_primFullUpdates.SyncRoot)
|
||||
lock (m_entityUpdates.SyncRoot)
|
||||
{
|
||||
int count = Math.Min(m_primFullUpdates.Count, m_udpServer.PrimFullUpdatesPerPacket);
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
m_fullUpdateDataBlocksBuilder.Clear();
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
EntityUpdate update;
|
||||
while (updatesThisCall < maxUpdates && m_entityUpdates.TryDequeue(out update))
|
||||
{
|
||||
ObjectUpdatePacket.ObjectDataBlock block = m_primFullUpdates.Dequeue();
|
||||
++updatesThisCall;
|
||||
|
||||
if (!m_killRecord.Contains(block.ID))
|
||||
#region UpdateFlags to packet type conversion
|
||||
|
||||
PrimUpdateFlags updateFlags = update.Flags;
|
||||
|
||||
bool canUseCompressed = true;
|
||||
bool canUseImproved = true;
|
||||
|
||||
// Compressed object updates only make sense for LL primitives
|
||||
if (!(update.Entity is SceneObjectPart))
|
||||
canUseCompressed = false;
|
||||
|
||||
if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate))
|
||||
{
|
||||
m_fullUpdateDataBlocksBuilder.Add(block);
|
||||
|
||||
// string text = Util.FieldToString(outPacket.ObjectData[i].Text);
|
||||
// if (text.IndexOf("\n") >= 0)
|
||||
// text = text.Remove(text.IndexOf("\n"));
|
||||
// m_log.DebugFormat(
|
||||
// "[CLIENT]: Sending full info about prim {0} text {1} to client {2}",
|
||||
// outPacket.ObjectData[i].ID, text, Name);
|
||||
canUseCompressed = false;
|
||||
canUseImproved = false;
|
||||
}
|
||||
// else
|
||||
// {
|
||||
// m_log.WarnFormat(
|
||||
// "[CLIENT]: Preventing full update for {0} after kill to {1}", block.ID, Name);
|
||||
// }
|
||||
else
|
||||
{
|
||||
if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) ||
|
||||
updateFlags.HasFlag(PrimUpdateFlags.Acceleration) ||
|
||||
updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) ||
|
||||
updateFlags.HasFlag(PrimUpdateFlags.Joint))
|
||||
{
|
||||
canUseCompressed = false;
|
||||
}
|
||||
|
||||
if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) ||
|
||||
updateFlags.HasFlag(PrimUpdateFlags.ParentID) ||
|
||||
updateFlags.HasFlag(PrimUpdateFlags.Scale) ||
|
||||
updateFlags.HasFlag(PrimUpdateFlags.PrimData) ||
|
||||
updateFlags.HasFlag(PrimUpdateFlags.Text) ||
|
||||
updateFlags.HasFlag(PrimUpdateFlags.NameValue) ||
|
||||
updateFlags.HasFlag(PrimUpdateFlags.ExtraData) ||
|
||||
updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) ||
|
||||
updateFlags.HasFlag(PrimUpdateFlags.Sound) ||
|
||||
updateFlags.HasFlag(PrimUpdateFlags.Particles) ||
|
||||
updateFlags.HasFlag(PrimUpdateFlags.Material) ||
|
||||
updateFlags.HasFlag(PrimUpdateFlags.ClickAction) ||
|
||||
updateFlags.HasFlag(PrimUpdateFlags.MediaURL) ||
|
||||
updateFlags.HasFlag(PrimUpdateFlags.Joint))
|
||||
{
|
||||
canUseImproved = false;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion UpdateFlags to packet type conversion
|
||||
|
||||
#region Block Construction
|
||||
|
||||
// TODO: Remove this once we can build compressed updates
|
||||
canUseCompressed = false;
|
||||
|
||||
if (!canUseImproved && !canUseCompressed)
|
||||
{
|
||||
if (update.Entity is ScenePresence)
|
||||
objectUpdateBlocks.Value.Add(CreateAvatarUpdateBlock((ScenePresence)update.Entity));
|
||||
else
|
||||
objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId));
|
||||
}
|
||||
else if (!canUseImproved)
|
||||
{
|
||||
compressedUpdateBlocks.Value.Add(CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags));
|
||||
}
|
||||
else
|
||||
{
|
||||
terseUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
|
||||
}
|
||||
|
||||
#endregion Block Construction
|
||||
}
|
||||
|
||||
outPacket.ObjectData = m_fullUpdateDataBlocksBuilder.ToArray();
|
||||
|
||||
OutPacket(outPacket, ThrottleOutPacketType.State);
|
||||
}
|
||||
}
|
||||
|
||||
public void SendPrimTerseUpdate(SendPrimitiveTerseData data)
|
||||
{
|
||||
if (data.Priority == double.NaN)
|
||||
{
|
||||
m_log.Error("[LLClientView] SendPrimTerseUpdate received a NaN priority, dropping update");
|
||||
return;
|
||||
}
|
||||
|
||||
Quaternion rotation = data.Rotation;
|
||||
if (rotation.W == 0.0f && rotation.X == 0.0f && rotation.Y == 0.0f && rotation.Z == 0.0f)
|
||||
rotation = Quaternion.Identity;
|
||||
#region Packet Sending
|
||||
|
||||
if (data.AttachPoint > 30 && data.OwnerID != AgentId) // Someone else's HUD
|
||||
return;
|
||||
const float TIME_DILATION = 1.0f;
|
||||
ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f);
|
||||
|
||||
ImprovedTerseObjectUpdatePacket.ObjectDataBlock objectData = CreateImprovedTerseBlock(data);
|
||||
|
||||
lock (m_primTerseUpdates.SyncRoot)
|
||||
m_primTerseUpdates.Enqueue(data.Priority, objectData, data.LocalID);
|
||||
}
|
||||
|
||||
void ProcessPrimTerseUpdates()
|
||||
{
|
||||
ImprovedTerseObjectUpdatePacket outPacket = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate);
|
||||
outPacket.Header.Reliable = false;
|
||||
outPacket.Header.Zerocoded = true;
|
||||
|
||||
outPacket.RegionData.RegionHandle = Scene.RegionInfo.RegionHandle;
|
||||
outPacket.RegionData.TimeDilation = (ushort)(Scene.TimeDilation * ushort.MaxValue);
|
||||
|
||||
lock (m_primTerseUpdates.SyncRoot)
|
||||
if (objectUpdateBlocks.IsValueCreated)
|
||||
{
|
||||
int count = Math.Min(m_primTerseUpdates.Count, m_udpServer.PrimTerseUpdatesPerPacket);
|
||||
if (count == 0)
|
||||
return;
|
||||
List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value;
|
||||
|
||||
outPacket.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[count];
|
||||
for (int i = 0; i < count; i++)
|
||||
outPacket.ObjectData[i] = m_primTerseUpdates.Dequeue();
|
||||
ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
|
||||
packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
|
||||
packet.RegionData.TimeDilation = timeDilation;
|
||||
packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count];
|
||||
|
||||
for (int i = 0; i < blocks.Count; i++)
|
||||
packet.ObjectData[i] = blocks[i];
|
||||
|
||||
OutPacket(packet, ThrottleOutPacketType.Task, true);
|
||||
}
|
||||
|
||||
OutPacket(outPacket, ThrottleOutPacketType.State);
|
||||
if (compressedUpdateBlocks.IsValueCreated)
|
||||
{
|
||||
List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value;
|
||||
|
||||
ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed);
|
||||
packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
|
||||
packet.RegionData.TimeDilation = timeDilation;
|
||||
packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count];
|
||||
|
||||
for (int i = 0; i < blocks.Count; i++)
|
||||
packet.ObjectData[i] = blocks[i];
|
||||
|
||||
OutPacket(packet, ThrottleOutPacketType.Task, true);
|
||||
}
|
||||
|
||||
if (terseUpdateBlocks.IsValueCreated)
|
||||
{
|
||||
List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
|
||||
|
||||
ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
|
||||
packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
|
||||
packet.RegionData.TimeDilation = timeDilation;
|
||||
packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
|
||||
|
||||
for (int i = 0; i < blocks.Count; i++)
|
||||
packet.ObjectData[i] = blocks[i];
|
||||
|
||||
OutPacket(packet, ThrottleOutPacketType.Task, true);
|
||||
}
|
||||
|
||||
#endregion Packet Sending
|
||||
}
|
||||
|
||||
public void ReprioritizeUpdates(StateUpdateTypes type, UpdatePriorityHandler handler)
|
||||
public void ReprioritizeUpdates(UpdatePriorityHandler handler)
|
||||
{
|
||||
PriorityQueue<double, ImprovedTerseObjectUpdatePacket.ObjectDataBlock>.UpdatePriorityHandler terse_update_priority_handler =
|
||||
delegate(ref double priority, uint local_id)
|
||||
{
|
||||
priority = handler(new UpdatePriorityData(priority, local_id));
|
||||
return priority != double.NaN;
|
||||
};
|
||||
PriorityQueue<double, ObjectUpdatePacket.ObjectDataBlock>.UpdatePriorityHandler update_priority_handler =
|
||||
//m_log.Debug("[CLIENT]: Reprioritizing prim updates for " + m_firstName + " " + m_lastName);
|
||||
|
||||
PriorityQueue<double, EntityUpdate>.UpdatePriorityHandler update_priority_handler =
|
||||
delegate(ref double priority, uint local_id)
|
||||
{
|
||||
priority = handler(new UpdatePriorityData(priority, local_id));
|
||||
return priority != double.NaN;
|
||||
};
|
||||
|
||||
if ((type & StateUpdateTypes.AvatarTerse) != 0)
|
||||
{
|
||||
lock (m_avatarTerseUpdates.SyncRoot)
|
||||
m_avatarTerseUpdates.Reprioritize(terse_update_priority_handler);
|
||||
}
|
||||
|
||||
if ((type & StateUpdateTypes.PrimitiveFull) != 0)
|
||||
{
|
||||
lock (m_primFullUpdates.SyncRoot)
|
||||
m_primFullUpdates.Reprioritize(update_priority_handler);
|
||||
}
|
||||
|
||||
if ((type & StateUpdateTypes.PrimitiveTerse) != 0)
|
||||
{
|
||||
lock (m_primTerseUpdates.SyncRoot)
|
||||
m_primTerseUpdates.Reprioritize(terse_update_priority_handler);
|
||||
}
|
||||
lock (m_entityUpdates.SyncRoot)
|
||||
m_entityUpdates.Reprioritize(update_priority_handler);
|
||||
}
|
||||
|
||||
public void FlushPrimUpdates()
|
||||
{
|
||||
while (m_primFullUpdates.Count > 0)
|
||||
{
|
||||
ProcessPrimFullUpdates();
|
||||
}
|
||||
while (m_primTerseUpdates.Count > 0)
|
||||
{
|
||||
ProcessPrimTerseUpdates();
|
||||
}
|
||||
while (m_avatarTerseUpdates.Count > 0)
|
||||
{
|
||||
ProcessAvatarTerseUpdates();
|
||||
}
|
||||
m_log.Debug("[CLIENT]: Flushing prim updates to " + m_firstName + " " + m_lastName);
|
||||
|
||||
while (m_entityUpdates.Count > 0)
|
||||
ProcessEntityUpdates(-1);
|
||||
}
|
||||
|
||||
#endregion Primitive Packet/Data Sending Methods
|
||||
@@ -3724,26 +3664,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
{
|
||||
if ((categories & ThrottleOutPacketTypeFlags.Task) != 0)
|
||||
{
|
||||
lock (m_avatarTerseUpdates.SyncRoot)
|
||||
{
|
||||
if (m_avatarTerseUpdates.Count > 0)
|
||||
ProcessAvatarTerseUpdates();
|
||||
}
|
||||
}
|
||||
|
||||
if ((categories & ThrottleOutPacketTypeFlags.State) != 0)
|
||||
{
|
||||
lock (m_primFullUpdates.SyncRoot)
|
||||
{
|
||||
if (m_primFullUpdates.Count > 0)
|
||||
ProcessPrimFullUpdates();
|
||||
}
|
||||
|
||||
lock (m_primTerseUpdates.SyncRoot)
|
||||
{
|
||||
if (m_primTerseUpdates.Count > 0)
|
||||
ProcessPrimTerseUpdates();
|
||||
}
|
||||
if (m_entityUpdates.Count > 0)
|
||||
ProcessEntityUpdates(m_udpServer.PrimUpdatesPerCallback);
|
||||
}
|
||||
|
||||
if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0)
|
||||
@@ -4404,22 +4326,55 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
|
||||
#region Helper Methods
|
||||
|
||||
protected ImprovedTerseObjectUpdatePacket.ObjectDataBlock CreateImprovedTerseBlock(SendAvatarTerseData data)
|
||||
protected ImprovedTerseObjectUpdatePacket.ObjectDataBlock CreateImprovedTerseBlock(ISceneEntity entity, bool sendTexture)
|
||||
{
|
||||
return CreateImprovedTerseBlock(true, data.LocalID, 0, data.CollisionPlane, data.Position, data.Velocity,
|
||||
data.Acceleration, data.Rotation, Vector3.Zero, data.TextureEntry);
|
||||
}
|
||||
#region ScenePresence/SOP Handling
|
||||
|
||||
protected ImprovedTerseObjectUpdatePacket.ObjectDataBlock CreateImprovedTerseBlock(SendPrimitiveTerseData data)
|
||||
{
|
||||
return CreateImprovedTerseBlock(false, data.LocalID, data.AttachPoint, Vector4.Zero, data.Position, data.Velocity,
|
||||
data.Acceleration, data.Rotation, data.AngularVelocity, data.TextureEntry);
|
||||
}
|
||||
bool avatar = (entity is ScenePresence);
|
||||
uint localID = entity.LocalId;
|
||||
uint attachPoint;
|
||||
Vector4 collisionPlane;
|
||||
Vector3 position, velocity, acceleration, angularVelocity;
|
||||
Quaternion rotation;
|
||||
byte[] textureEntry;
|
||||
|
||||
if (entity is ScenePresence)
|
||||
{
|
||||
ScenePresence presence = (ScenePresence)entity;
|
||||
|
||||
attachPoint = 0;
|
||||
collisionPlane = presence.CollisionPlane;
|
||||
position = presence.OffsetPosition;
|
||||
velocity = presence.Velocity;
|
||||
acceleration = Vector3.Zero;
|
||||
angularVelocity = Vector3.Zero;
|
||||
rotation = presence.Rotation;
|
||||
|
||||
if (sendTexture)
|
||||
textureEntry = presence.Appearance.Texture.GetBytes();
|
||||
else
|
||||
textureEntry = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
SceneObjectPart part = (SceneObjectPart)entity;
|
||||
|
||||
attachPoint = part.AttachmentPoint;
|
||||
collisionPlane = Vector4.Zero;
|
||||
position = part.RelativePosition;
|
||||
velocity = part.Velocity;
|
||||
acceleration = part.Acceleration;
|
||||
angularVelocity = part.AngularVelocity;
|
||||
rotation = part.RotationOffset;
|
||||
|
||||
if (sendTexture)
|
||||
textureEntry = part.Shape.TextureEntry;
|
||||
else
|
||||
textureEntry = null;
|
||||
}
|
||||
|
||||
#endregion ScenePresence/SOP Handling
|
||||
|
||||
protected ImprovedTerseObjectUpdatePacket.ObjectDataBlock CreateImprovedTerseBlock(bool avatar, uint localID, int attachPoint,
|
||||
Vector4 collisionPlane, Vector3 position, Vector3 velocity, Vector3 acceleration, Quaternion rotation,
|
||||
Vector3 angularVelocity, byte[] textureEntry)
|
||||
{
|
||||
int pos = 0;
|
||||
byte[] data = new byte[(avatar ? 60 : 44)];
|
||||
|
||||
@@ -4491,12 +4446,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
return block;
|
||||
}
|
||||
|
||||
protected ObjectUpdatePacket.ObjectDataBlock CreateAvatarUpdateBlock(SendAvatarData data)
|
||||
protected ObjectUpdatePacket.ObjectDataBlock CreateAvatarUpdateBlock(ScenePresence data)
|
||||
{
|
||||
byte[] objectData = new byte[76];
|
||||
|
||||
Vector4.UnitW.ToBytes(objectData, 0); // TODO: Collision plane support
|
||||
data.Position.ToBytes(objectData, 16);
|
||||
data.CollisionPlane.ToBytes(objectData, 0);
|
||||
data.OffsetPosition.ToBytes(objectData, 16);
|
||||
//data.Velocity.ToBytes(objectData, 28);
|
||||
//data.Acceleration.ToBytes(objectData, 40);
|
||||
data.Rotation.ToBytes(objectData, 52);
|
||||
@@ -4506,12 +4461,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
|
||||
update.Data = Utils.EmptyBytes;
|
||||
update.ExtraParams = new byte[1];
|
||||
update.FullID = data.AvatarID;
|
||||
update.ID = data.AvatarLocalID;
|
||||
update.FullID = data.UUID;
|
||||
update.ID = data.LocalId;
|
||||
update.Material = (byte)Material.Flesh;
|
||||
update.MediaURL = Utils.EmptyBytes;
|
||||
update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.FirstName + "\nLastName STRING RW SV " +
|
||||
data.LastName + "\nTitle STRING RW SV " + data.GroupTitle);
|
||||
update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.Firstname + "\nLastName STRING RW SV " +
|
||||
data.Lastname + "\nTitle STRING RW SV " + data.Grouptitle);
|
||||
update.ObjectData = objectData;
|
||||
update.ParentID = data.ParentID;
|
||||
update.PathCurve = 16;
|
||||
@@ -4520,102 +4475,116 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
update.PCode = (byte)PCode.Avatar;
|
||||
update.ProfileCurve = 1;
|
||||
update.PSBlock = Utils.EmptyBytes;
|
||||
update.Scale = new Vector3(0.45f,0.6f,1.9f);
|
||||
update.Scale = new Vector3(0.45f, 0.6f, 1.9f);
|
||||
update.Text = Utils.EmptyBytes;
|
||||
update.TextColor = new byte[4];
|
||||
update.TextureAnim = Utils.EmptyBytes;
|
||||
update.TextureEntry = data.TextureEntry ?? Utils.EmptyBytes;
|
||||
update.UpdateFlags = (uint)(PrimFlags.Physics | PrimFlags.ObjectModify | PrimFlags.ObjectCopy | PrimFlags.ObjectAnyOwner | PrimFlags.ObjectYouOwner | PrimFlags.ObjectMove | PrimFlags.InventoryEmpty | PrimFlags.ObjectTransfer | PrimFlags.ObjectOwnerModify);//61 + (9 << 8) + (130 << 16) + (16 << 24); // TODO: Replace these numbers with PrimFlags
|
||||
update.TextureEntry = (data.Appearance.Texture != null) ? data.Appearance.Texture.GetBytes() : Utils.EmptyBytes;
|
||||
update.UpdateFlags = (uint)(
|
||||
PrimFlags.Physics | PrimFlags.ObjectModify | PrimFlags.ObjectCopy | PrimFlags.ObjectAnyOwner |
|
||||
PrimFlags.ObjectYouOwner | PrimFlags.ObjectMove | PrimFlags.InventoryEmpty | PrimFlags.ObjectTransfer |
|
||||
PrimFlags.ObjectOwnerModify);
|
||||
|
||||
return update;
|
||||
}
|
||||
|
||||
protected ObjectUpdatePacket.ObjectDataBlock CreatePrimUpdateBlock(SendPrimitiveData data)
|
||||
protected ObjectUpdatePacket.ObjectDataBlock CreatePrimUpdateBlock(SceneObjectPart data, UUID recipientID)
|
||||
{
|
||||
byte[] objectData = new byte[60];
|
||||
data.pos.ToBytes(objectData, 0);
|
||||
data.vel.ToBytes(objectData, 12);
|
||||
data.acc.ToBytes(objectData, 24);
|
||||
data.rotation.ToBytes(objectData, 36);
|
||||
data.rvel.ToBytes(objectData, 48);
|
||||
data.RelativePosition.ToBytes(objectData, 0);
|
||||
data.Velocity.ToBytes(objectData, 12);
|
||||
data.Acceleration.ToBytes(objectData, 24);
|
||||
data.RotationOffset.ToBytes(objectData, 36);
|
||||
data.AngularVelocity.ToBytes(objectData, 48);
|
||||
|
||||
ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock();
|
||||
update.ClickAction = (byte)data.clickAction;
|
||||
update.ClickAction = (byte)data.ClickAction;
|
||||
update.CRC = 0;
|
||||
update.ExtraParams = data.primShape.ExtraParams ?? Utils.EmptyBytes;
|
||||
update.FullID = data.objectID;
|
||||
update.ID = data.localID;
|
||||
update.ExtraParams = data.Shape.ExtraParams ?? Utils.EmptyBytes;
|
||||
update.FullID = data.UUID;
|
||||
update.ID = data.LocalId;
|
||||
//update.JointAxisOrAnchor = Vector3.Zero; // These are deprecated
|
||||
//update.JointPivot = Vector3.Zero;
|
||||
//update.JointType = 0;
|
||||
update.Material = data.material;
|
||||
update.Material = data.Material;
|
||||
update.MediaURL = Utils.EmptyBytes; // FIXME: Support this in OpenSim
|
||||
if (data.attachment)
|
||||
if (data.IsAttachment)
|
||||
{
|
||||
update.NameValue = Util.StringToBytes256("AttachItemID STRING RW SV " + data.AssetId);
|
||||
update.State = (byte)((data.AttachPoint % 16) * 16 + (data.AttachPoint / 16));
|
||||
update.NameValue = Util.StringToBytes256("AttachItemID STRING RW SV " + data.FromItemID);
|
||||
update.State = (byte)((data.AttachmentPoint % 16) * 16 + (data.AttachmentPoint / 16));
|
||||
}
|
||||
else
|
||||
{
|
||||
update.NameValue = Utils.EmptyBytes;
|
||||
update.State = data.primShape.State;
|
||||
update.State = data.Shape.State;
|
||||
}
|
||||
update.ObjectData = objectData;
|
||||
update.ParentID = data.parentID;
|
||||
update.PathBegin = data.primShape.PathBegin;
|
||||
update.PathCurve = data.primShape.PathCurve;
|
||||
update.PathEnd = data.primShape.PathEnd;
|
||||
update.PathRadiusOffset = data.primShape.PathRadiusOffset;
|
||||
update.PathRevolutions = data.primShape.PathRevolutions;
|
||||
update.PathScaleX = data.primShape.PathScaleX;
|
||||
update.PathScaleY = data.primShape.PathScaleY;
|
||||
update.PathShearX = data.primShape.PathShearX;
|
||||
update.PathShearY = data.primShape.PathShearY;
|
||||
update.PathSkew = data.primShape.PathSkew;
|
||||
update.PathTaperX = data.primShape.PathTaperX;
|
||||
update.PathTaperY = data.primShape.PathTaperY;
|
||||
update.PathTwist = data.primShape.PathTwist;
|
||||
update.PathTwistBegin = data.primShape.PathTwistBegin;
|
||||
update.PCode = data.primShape.PCode;
|
||||
update.ProfileBegin = data.primShape.ProfileBegin;
|
||||
update.ProfileCurve = data.primShape.ProfileCurve;
|
||||
update.ProfileEnd = data.primShape.ProfileEnd;
|
||||
update.ProfileHollow = data.primShape.ProfileHollow;
|
||||
update.PSBlock = data.particleSystem ?? Utils.EmptyBytes;
|
||||
update.TextColor = data.color ?? Color4.Black.GetBytes(true);
|
||||
update.TextureAnim = data.textureanim ?? Utils.EmptyBytes;
|
||||
update.TextureEntry = data.primShape.TextureEntry ?? Utils.EmptyBytes;
|
||||
update.Scale = data.primShape.Scale;
|
||||
update.Text = Util.StringToBytes256(data.text);
|
||||
update.UpdateFlags = (uint)data.flags;
|
||||
|
||||
if (data.SoundId != UUID.Zero)
|
||||
update.ObjectData = objectData;
|
||||
update.ParentID = data.ParentID;
|
||||
update.PathBegin = data.Shape.PathBegin;
|
||||
update.PathCurve = data.Shape.PathCurve;
|
||||
update.PathEnd = data.Shape.PathEnd;
|
||||
update.PathRadiusOffset = data.Shape.PathRadiusOffset;
|
||||
update.PathRevolutions = data.Shape.PathRevolutions;
|
||||
update.PathScaleX = data.Shape.PathScaleX;
|
||||
update.PathScaleY = data.Shape.PathScaleY;
|
||||
update.PathShearX = data.Shape.PathShearX;
|
||||
update.PathShearY = data.Shape.PathShearY;
|
||||
update.PathSkew = data.Shape.PathSkew;
|
||||
update.PathTaperX = data.Shape.PathTaperX;
|
||||
update.PathTaperY = data.Shape.PathTaperY;
|
||||
update.PathTwist = data.Shape.PathTwist;
|
||||
update.PathTwistBegin = data.Shape.PathTwistBegin;
|
||||
update.PCode = data.Shape.PCode;
|
||||
update.ProfileBegin = data.Shape.ProfileBegin;
|
||||
update.ProfileCurve = data.Shape.ProfileCurve;
|
||||
update.ProfileEnd = data.Shape.ProfileEnd;
|
||||
update.ProfileHollow = data.Shape.ProfileHollow;
|
||||
update.PSBlock = data.ParticleSystem ?? Utils.EmptyBytes;
|
||||
update.TextColor = data.GetTextColor().GetBytes(false);
|
||||
update.TextureAnim = data.TextureAnimation ?? Utils.EmptyBytes;
|
||||
update.TextureEntry = data.Shape.TextureEntry ?? Utils.EmptyBytes;
|
||||
update.Scale = data.Shape.Scale;
|
||||
update.Text = Util.StringToBytes256(data.Text);
|
||||
|
||||
#region PrimFlags
|
||||
|
||||
PrimFlags flags = (PrimFlags)m_scene.Permissions.GenerateClientFlags(recipientID, data.UUID);
|
||||
|
||||
// Don't send the CreateSelected flag to everyone
|
||||
flags &= ~PrimFlags.CreateSelected;
|
||||
|
||||
if (recipientID == data.OwnerID)
|
||||
{
|
||||
update.Sound = data.SoundId;
|
||||
update.OwnerID = data.ownerID;
|
||||
update.Gain = (float)data.SoundVolume;
|
||||
if ((data.Flags & PrimFlags.CreateSelected) != 0)
|
||||
{
|
||||
// Only send this flag once, then unset it
|
||||
flags |= PrimFlags.CreateSelected;
|
||||
data.Flags &= ~PrimFlags.CreateSelected;
|
||||
}
|
||||
}
|
||||
|
||||
update.UpdateFlags = (uint)flags;
|
||||
|
||||
#endregion PrimFlags
|
||||
|
||||
if (data.Sound != UUID.Zero)
|
||||
{
|
||||
update.Sound = data.Sound;
|
||||
update.OwnerID = data.OwnerID;
|
||||
update.Gain = (float)data.SoundGain;
|
||||
update.Radius = (float)data.SoundRadius;
|
||||
update.Flags = data.SoundFlags;
|
||||
}
|
||||
|
||||
switch ((PCode)data.primShape.PCode)
|
||||
switch ((PCode)data.Shape.PCode)
|
||||
{
|
||||
case PCode.Grass:
|
||||
case PCode.Tree:
|
||||
case PCode.NewTree:
|
||||
update.Data = new byte[] { data.primShape.State };
|
||||
update.Data = new byte[] { data.Shape.State };
|
||||
break;
|
||||
default:
|
||||
// TODO: Support ScratchPad
|
||||
//if (prim.ScratchPad != null)
|
||||
//{
|
||||
// update.Data = new byte[prim.ScratchPad.Length];
|
||||
// Buffer.BlockCopy(prim.ScratchPad, 0, update.Data, 0, update.Data.Length);
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// update.Data = Utils.EmptyBytes;
|
||||
//}
|
||||
update.Data = Utils.EmptyBytes;
|
||||
break;
|
||||
}
|
||||
@@ -4623,6 +4592,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
return update;
|
||||
}
|
||||
|
||||
protected ObjectUpdateCompressedPacket.ObjectDataBlock CreateCompressedUpdateBlock(SceneObjectPart part, PrimUpdateFlags updateFlags)
|
||||
{
|
||||
// TODO: Implement this
|
||||
return null;
|
||||
}
|
||||
|
||||
public void SendNameReply(UUID profileId, string firstname, string lastname)
|
||||
{
|
||||
UUIDNameReplyPacket packet = (UUIDNameReplyPacket)PacketPool.Instance.GetPacket(PacketType.UUIDNameReply);
|
||||
@@ -11672,7 +11647,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
throw new InvalidOperationException(string.Format("The {0} is empty", this.GetType().ToString()));
|
||||
}
|
||||
|
||||
internal TValue Dequeue()
|
||||
internal bool TryDequeue(out TValue value)
|
||||
{
|
||||
for (int i = 0; i < m_heaps.Length; ++i)
|
||||
{
|
||||
@@ -11680,10 +11655,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
{
|
||||
MinHeapItem item = m_heaps[i].RemoveMin();
|
||||
m_lookupTable.Remove(item.LocalID);
|
||||
return item.Value;
|
||||
value = item.Value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
throw new InvalidOperationException(string.Format("The {0} is empty", this.GetType().ToString()));
|
||||
|
||||
value = default(TValue);
|
||||
return false;
|
||||
}
|
||||
|
||||
internal void Reprioritize(UpdatePriorityHandler handler)
|
||||
|
||||
@@ -99,15 +99,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
|
||||
/// <summary>The measured resolution of Environment.TickCount</summary>
|
||||
public readonly float TickCountResolution;
|
||||
/// <summary>Number of terse prim updates to put on the queue each time the
|
||||
/// <summary>Number of prim updates to put on the queue each time the
|
||||
/// OnQueueEmpty event is triggered for updates</summary>
|
||||
public readonly int PrimTerseUpdatesPerPacket;
|
||||
/// <summary>Number of terse avatar updates to put on the queue each time the
|
||||
/// OnQueueEmpty event is triggered for updates</summary>
|
||||
public readonly int AvatarTerseUpdatesPerPacket;
|
||||
/// <summary>Number of full prim updates to put on the queue each time the
|
||||
/// OnQueueEmpty event is triggered for updates</summary>
|
||||
public readonly int PrimFullUpdatesPerPacket;
|
||||
public readonly int PrimUpdatesPerCallback;
|
||||
/// <summary>Number of texture packets to put on the queue each time the
|
||||
/// OnQueueEmpty event is triggered for textures</summary>
|
||||
public readonly int TextureSendLimit;
|
||||
@@ -191,9 +185,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
m_recvBufferSize = config.GetInt("client_socket_rcvbuf_size", 0);
|
||||
sceneThrottleBps = config.GetInt("scene_throttle_max_bps", 0);
|
||||
|
||||
PrimTerseUpdatesPerPacket = config.GetInt("PrimTerseUpdatesPerPacket", 25);
|
||||
AvatarTerseUpdatesPerPacket = config.GetInt("AvatarTerseUpdatesPerPacket", 10);
|
||||
PrimFullUpdatesPerPacket = config.GetInt("PrimFullUpdatesPerPacket", 100);
|
||||
PrimUpdatesPerCallback = config.GetInt("PrimUpdatesPerCallback", 100);
|
||||
TextureSendLimit = config.GetInt("TextureSendLimit", 20);
|
||||
|
||||
m_defaultRTO = config.GetInt("DefaultRTO", 0);
|
||||
@@ -201,9 +193,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
}
|
||||
else
|
||||
{
|
||||
PrimTerseUpdatesPerPacket = 25;
|
||||
AvatarTerseUpdatesPerPacket = 10;
|
||||
PrimFullUpdatesPerPacket = 100;
|
||||
PrimUpdatesPerCallback = 100;
|
||||
TextureSendLimit = 20;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user