mirror of
https://github.com/opensim/opensim.git
synced 2026-08-01 06:06:06 +08:00
Merge branch 'master' into careminster
Conflicts: OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs OpenSim/Region/Framework/Scenes/ScenePresence.cs OpenSim/Region/Physics/Manager/PhysicsActor.cs OpenSim/Region/Physics/Manager/PhysicsScene.cs
This commit is contained in:
@@ -96,6 +96,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
public event Action<IClientAPI, bool> OnCompleteMovementToRegion;
|
||||
public event UpdateAgent OnPreAgentUpdate;
|
||||
public event UpdateAgent OnAgentUpdate;
|
||||
public event UpdateAgent OnAgentCameraUpdate;
|
||||
public event AgentRequestSit OnAgentRequestSit;
|
||||
public event AgentSit OnAgentSit;
|
||||
public event AvatarPickerRequest OnAvatarPickerRequest;
|
||||
@@ -368,7 +369,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
/// This does mean that agent updates must be processed synchronously, at least for each client, and called methods
|
||||
/// cannot retain a reference to it outside of that method.
|
||||
/// </remarks>
|
||||
private AgentUpdateArgs m_lastAgentUpdateArgs;
|
||||
private AgentUpdateArgs m_thisAgentUpdateArgs = new AgentUpdateArgs();
|
||||
|
||||
protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>();
|
||||
protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers
|
||||
@@ -505,6 +506,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
m_udpServer = udpServer;
|
||||
m_udpClient = udpClient;
|
||||
m_udpClient.OnQueueEmpty += HandleQueueEmpty;
|
||||
m_udpClient.HasUpdates += HandleHasUpdates;
|
||||
m_udpClient.OnPacketStats += PopulateStats;
|
||||
|
||||
m_prioritizer = new Prioritizer(m_scene);
|
||||
@@ -4164,8 +4166,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
|
||||
void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories)
|
||||
{
|
||||
// if (!m_udpServer.IsRunningOutbound)
|
||||
// return;
|
||||
|
||||
if ((categories & ThrottleOutPacketTypeFlags.Task) != 0)
|
||||
{
|
||||
// if (!m_udpServer.IsRunningOutbound)
|
||||
// return;
|
||||
|
||||
if (m_maxUpdates == 0 || m_LastQueueFill == 0)
|
||||
{
|
||||
m_maxUpdates = m_udpServer.PrimUpdatesPerCallback;
|
||||
@@ -4191,6 +4199,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
ImageManager.ProcessImageQueue(m_udpServer.TextureSendLimit);
|
||||
}
|
||||
|
||||
internal bool HandleHasUpdates(ThrottleOutPacketTypeFlags categories)
|
||||
{
|
||||
bool hasUpdates = false;
|
||||
|
||||
if ((categories & ThrottleOutPacketTypeFlags.Task) != 0)
|
||||
{
|
||||
if (m_entityUpdates.Count > 0)
|
||||
hasUpdates = true;
|
||||
else if (m_entityProps.Count > 0)
|
||||
hasUpdates = true;
|
||||
}
|
||||
|
||||
if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0)
|
||||
{
|
||||
if (ImageManager.HasUpdates())
|
||||
hasUpdates = true;
|
||||
}
|
||||
|
||||
return hasUpdates;
|
||||
}
|
||||
|
||||
public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID)
|
||||
{
|
||||
AssetUploadCompletePacket newPack = new AssetUploadCompletePacket();
|
||||
@@ -5058,7 +5087,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
SceneObjectPart part = (SceneObjectPart)entity;
|
||||
|
||||
attachPoint = part.ParentGroup.AttachmentPoint;
|
||||
|
||||
attachPoint = ((attachPoint % 16) * 16 + (attachPoint / 16));
|
||||
// m_log.DebugFormat(
|
||||
// "[LLCLIENTVIEW]: Sending attachPoint {0} for {1} {2} to {3}",
|
||||
// attachPoint, part.Name, part.LocalId, Name);
|
||||
@@ -5086,7 +5115,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
pos += 4;
|
||||
|
||||
// Avatar/CollisionPlane
|
||||
data[pos++] = (byte)((attachPoint % 16) * 16 + (attachPoint / 16)); ;
|
||||
data[pos++] = (byte) attachPoint;
|
||||
if (avatar)
|
||||
{
|
||||
data[pos++] = 1;
|
||||
@@ -5618,83 +5647,137 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
|
||||
#region Packet Handlers
|
||||
|
||||
public int TotalAgentUpdates { get; set; }
|
||||
|
||||
#region Scene/Avatar
|
||||
|
||||
private bool HandleAgentUpdate(IClientAPI sener, Packet packet)
|
||||
// Threshold for body rotation to be a significant agent update
|
||||
private const float QDELTA = 0.000001f;
|
||||
// Threshold for camera rotation to be a significant agent update
|
||||
private const float VDELTA = 0.01f;
|
||||
|
||||
/// <summary>
|
||||
/// This checks the update significance against the last update made.
|
||||
/// </summary>
|
||||
/// <remarks>Can only be called by one thread at a time</remarks>
|
||||
/// <returns></returns>
|
||||
/// <param name='x'></param>
|
||||
public bool CheckAgentUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
|
||||
{
|
||||
if (OnAgentUpdate != null)
|
||||
return CheckAgentMovementUpdateSignificance(x) || CheckAgentCameraUpdateSignificance(x);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This checks the movement/state update significance against the last update made.
|
||||
/// </summary>
|
||||
/// <remarks>Can only be called by one thread at a time</remarks>
|
||||
/// <returns></returns>
|
||||
/// <param name='x'></param>
|
||||
private bool CheckAgentMovementUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
|
||||
{
|
||||
float qdelta1 = 1 - (float)Math.Pow(Quaternion.Dot(x.BodyRotation, m_thisAgentUpdateArgs.BodyRotation), 2);
|
||||
//qdelta2 = 1 - (float)Math.Pow(Quaternion.Dot(x.HeadRotation, m_thisAgentUpdateArgs.HeadRotation), 2);
|
||||
|
||||
bool movementSignificant =
|
||||
(qdelta1 > QDELTA) // significant if body rotation above threshold
|
||||
// Ignoring head rotation altogether, because it's not being used for anything interesting up the stack
|
||||
// || (qdelta2 > QDELTA * 10) // significant if head rotation above threshold
|
||||
|| (x.ControlFlags != m_thisAgentUpdateArgs.ControlFlags) // significant if control flags changed
|
||||
|| (x.ControlFlags != (byte)AgentManager.ControlFlags.NONE) // significant if user supplying any movement update commands
|
||||
|| (x.Far != m_thisAgentUpdateArgs.Far) // significant if far distance changed
|
||||
|| (x.Flags != m_thisAgentUpdateArgs.Flags) // significant if Flags changed
|
||||
|| (x.State != m_thisAgentUpdateArgs.State) // significant if Stats changed
|
||||
;
|
||||
//if (movementSignificant)
|
||||
//{
|
||||
//m_log.DebugFormat("[LLCLIENTVIEW]: Bod {0} {1}",
|
||||
// qdelta1, qdelta2);
|
||||
//m_log.DebugFormat("[LLCLIENTVIEW]: St {0} {1} {2} {3}",
|
||||
// x.ControlFlags, x.Flags, x.Far, x.State);
|
||||
//}
|
||||
return movementSignificant;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This checks the camera update significance against the last update made.
|
||||
/// </summary>
|
||||
/// <remarks>Can only be called by one thread at a time</remarks>
|
||||
/// <returns></returns>
|
||||
/// <param name='x'></param>
|
||||
private bool CheckAgentCameraUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
|
||||
{
|
||||
float vdelta1 = Vector3.Distance(x.CameraAtAxis, m_thisAgentUpdateArgs.CameraAtAxis);
|
||||
float vdelta2 = Vector3.Distance(x.CameraCenter, m_thisAgentUpdateArgs.CameraCenter);
|
||||
float vdelta3 = Vector3.Distance(x.CameraLeftAxis, m_thisAgentUpdateArgs.CameraLeftAxis);
|
||||
float vdelta4 = Vector3.Distance(x.CameraUpAxis, m_thisAgentUpdateArgs.CameraUpAxis);
|
||||
|
||||
bool cameraSignificant =
|
||||
(vdelta1 > VDELTA) ||
|
||||
(vdelta2 > VDELTA) ||
|
||||
(vdelta3 > VDELTA) ||
|
||||
(vdelta4 > VDELTA)
|
||||
;
|
||||
|
||||
//if (cameraSignificant)
|
||||
//{
|
||||
//m_log.DebugFormat("[LLCLIENTVIEW]: Cam1 {0} {1}",
|
||||
// x.CameraAtAxis, x.CameraCenter);
|
||||
//m_log.DebugFormat("[LLCLIENTVIEW]: Cam2 {0} {1}",
|
||||
// x.CameraLeftAxis, x.CameraUpAxis);
|
||||
//}
|
||||
|
||||
return cameraSignificant;
|
||||
}
|
||||
|
||||
private bool HandleAgentUpdate(IClientAPI sener, Packet packet)
|
||||
{
|
||||
// We got here, which means that something in agent update was significant
|
||||
|
||||
AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
|
||||
AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData;
|
||||
|
||||
if (x.AgentID != AgentId || x.SessionID != SessionId)
|
||||
return false;
|
||||
|
||||
// Before we update the current m_thisAgentUpdateArgs, let's check this again
|
||||
// to see what exactly changed
|
||||
bool movement = CheckAgentMovementUpdateSignificance(x);
|
||||
bool camera = CheckAgentCameraUpdateSignificance(x);
|
||||
|
||||
m_thisAgentUpdateArgs.AgentID = x.AgentID;
|
||||
m_thisAgentUpdateArgs.BodyRotation = x.BodyRotation;
|
||||
m_thisAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis;
|
||||
m_thisAgentUpdateArgs.CameraCenter = x.CameraCenter;
|
||||
m_thisAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis;
|
||||
m_thisAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis;
|
||||
m_thisAgentUpdateArgs.ControlFlags = x.ControlFlags;
|
||||
m_thisAgentUpdateArgs.Far = x.Far;
|
||||
m_thisAgentUpdateArgs.Flags = x.Flags;
|
||||
m_thisAgentUpdateArgs.HeadRotation = x.HeadRotation;
|
||||
m_thisAgentUpdateArgs.SessionID = x.SessionID;
|
||||
m_thisAgentUpdateArgs.State = x.State;
|
||||
|
||||
UpdateAgent handlerAgentUpdate = OnAgentUpdate;
|
||||
UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate;
|
||||
UpdateAgent handlerAgentCameraUpdate = OnAgentCameraUpdate;
|
||||
|
||||
// Was there a significant movement/state change?
|
||||
if (movement)
|
||||
{
|
||||
AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
|
||||
if (handlerPreAgentUpdate != null)
|
||||
OnPreAgentUpdate(this, m_thisAgentUpdateArgs);
|
||||
|
||||
#region Packet Session and User Check
|
||||
if (agentUpdate.AgentData.SessionID != SessionId || agentUpdate.AgentData.AgentID != AgentId)
|
||||
{
|
||||
PacketPool.Instance.ReturnPacket(packet);
|
||||
return false;
|
||||
}
|
||||
#endregion
|
||||
|
||||
bool update = false;
|
||||
AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData;
|
||||
|
||||
if (m_lastAgentUpdateArgs != null)
|
||||
{
|
||||
// These should be ordered from most-likely to
|
||||
// least likely to change. I've made an initial
|
||||
// guess at that.
|
||||
update =
|
||||
(
|
||||
(x.BodyRotation != m_lastAgentUpdateArgs.BodyRotation) ||
|
||||
(x.CameraAtAxis != m_lastAgentUpdateArgs.CameraAtAxis) ||
|
||||
(x.CameraCenter != m_lastAgentUpdateArgs.CameraCenter) ||
|
||||
(x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) ||
|
||||
(x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) ||
|
||||
(x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) ||
|
||||
(x.ControlFlags != 0) ||
|
||||
(x.Far != m_lastAgentUpdateArgs.Far) ||
|
||||
(x.Flags != m_lastAgentUpdateArgs.Flags) ||
|
||||
(x.State != m_lastAgentUpdateArgs.State) ||
|
||||
(x.HeadRotation != m_lastAgentUpdateArgs.HeadRotation) ||
|
||||
(x.SessionID != m_lastAgentUpdateArgs.SessionID) ||
|
||||
(x.AgentID != m_lastAgentUpdateArgs.AgentID)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_lastAgentUpdateArgs = new AgentUpdateArgs();
|
||||
update = true;
|
||||
}
|
||||
|
||||
if (update)
|
||||
{
|
||||
// m_log.DebugFormat("[LLCLIENTVIEW]: Triggered AgentUpdate for {0}", sener.Name);
|
||||
|
||||
m_lastAgentUpdateArgs.AgentID = x.AgentID;
|
||||
m_lastAgentUpdateArgs.BodyRotation = x.BodyRotation;
|
||||
m_lastAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis;
|
||||
m_lastAgentUpdateArgs.CameraCenter = x.CameraCenter;
|
||||
m_lastAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis;
|
||||
m_lastAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis;
|
||||
m_lastAgentUpdateArgs.ControlFlags = x.ControlFlags;
|
||||
m_lastAgentUpdateArgs.Far = x.Far;
|
||||
m_lastAgentUpdateArgs.Flags = x.Flags;
|
||||
m_lastAgentUpdateArgs.HeadRotation = x.HeadRotation;
|
||||
m_lastAgentUpdateArgs.SessionID = x.SessionID;
|
||||
m_lastAgentUpdateArgs.State = x.State;
|
||||
|
||||
UpdateAgent handlerAgentUpdate = OnAgentUpdate;
|
||||
UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate;
|
||||
|
||||
if (handlerPreAgentUpdate != null)
|
||||
OnPreAgentUpdate(this, m_lastAgentUpdateArgs);
|
||||
|
||||
if (handlerAgentUpdate != null)
|
||||
OnAgentUpdate(this, m_lastAgentUpdateArgs);
|
||||
|
||||
handlerAgentUpdate = null;
|
||||
handlerPreAgentUpdate = null;
|
||||
}
|
||||
if (handlerAgentUpdate != null)
|
||||
OnAgentUpdate(this, m_thisAgentUpdateArgs);
|
||||
}
|
||||
// Was there a significant camera(s) change?
|
||||
if (camera)
|
||||
if (handlerAgentCameraUpdate != null)
|
||||
handlerAgentCameraUpdate(this, m_thisAgentUpdateArgs);
|
||||
|
||||
handlerAgentUpdate = null;
|
||||
handlerPreAgentUpdate = null;
|
||||
handlerAgentCameraUpdate = null;
|
||||
|
||||
PacketPool.Instance.ReturnPacket(packet);
|
||||
|
||||
@@ -12813,7 +12896,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
OutPacket(dialog, ThrottleOutPacketType.Task);
|
||||
}
|
||||
|
||||
public void StopFlying(ISceneEntity p)
|
||||
public void SendAgentTerseUpdate(ISceneEntity p)
|
||||
{
|
||||
if (p is ScenePresence)
|
||||
{
|
||||
@@ -12827,25 +12910,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
|
||||
Vector3 pos = presence.AbsolutePosition;
|
||||
|
||||
if (presence.Appearance.AvatarHeight != 127.0f)
|
||||
pos += new Vector3(0f, 0f, (presence.Appearance.AvatarHeight/6f));
|
||||
else
|
||||
pos += new Vector3(0f, 0f, (1.56f/6f));
|
||||
|
||||
presence.AbsolutePosition = pos;
|
||||
|
||||
// attach a suitable collision plane regardless of the actual situation to force the LLClient to land.
|
||||
// Collision plane below the avatar's position a 6th of the avatar's height is suitable.
|
||||
// Mind you, that this method doesn't get called if the avatar's velocity magnitude is greater then a
|
||||
// certain amount.. because the LLClient wouldn't land in that situation anyway.
|
||||
|
||||
// why are we still testing for this really old height value default???
|
||||
if (presence.Appearance.AvatarHeight != 127.0f)
|
||||
presence.CollisionPlane = new Vector4(0, 0, 0, pos.Z - presence.Appearance.AvatarHeight/6f);
|
||||
else
|
||||
presence.CollisionPlane = new Vector4(0, 0, 0, pos.Z - (1.56f/6f));
|
||||
|
||||
|
||||
ImprovedTerseObjectUpdatePacket.ObjectDataBlock block =
|
||||
CreateImprovedTerseBlock(p, false);
|
||||
|
||||
|
||||
@@ -206,6 +206,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasUpdates()
|
||||
{
|
||||
J2KImage image = GetHighestPriorityImage();
|
||||
|
||||
return image != null && image.IsDecoded;
|
||||
}
|
||||
|
||||
public bool ProcessImageQueue(int packetsToSend)
|
||||
{
|
||||
int packetsSent = 0;
|
||||
|
||||
@@ -31,6 +31,7 @@ using System.Net;
|
||||
using System.Threading;
|
||||
using log4net;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Framework.Monitoring;
|
||||
using OpenMetaverse;
|
||||
using OpenMetaverse.Packets;
|
||||
|
||||
@@ -81,6 +82,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
/// hooked to put more data on the empty queue</summary>
|
||||
public event QueueEmpty OnQueueEmpty;
|
||||
|
||||
public event Func<ThrottleOutPacketTypeFlags, bool> HasUpdates;
|
||||
|
||||
/// <summary>AgentID for this client</summary>
|
||||
public readonly UUID AgentID;
|
||||
/// <summary>The remote address of the connected client</summary>
|
||||
@@ -645,15 +648,38 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
/// <param name="categories">Throttle categories to fire the callback for</param>
|
||||
private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories)
|
||||
{
|
||||
if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty)
|
||||
// if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty)
|
||||
if (!m_isQueueEmptyRunning && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty)
|
||||
{
|
||||
m_isQueueEmptyRunning = true;
|
||||
|
||||
int start = Environment.TickCount & Int32.MaxValue;
|
||||
const int MIN_CALLBACK_MS = 30;
|
||||
|
||||
m_nextOnQueueEmpty = start + MIN_CALLBACK_MS;
|
||||
if (m_nextOnQueueEmpty == 0)
|
||||
m_nextOnQueueEmpty = 1;
|
||||
|
||||
// Use a value of 0 to signal that FireQueueEmpty is running
|
||||
m_nextOnQueueEmpty = 0;
|
||||
// Asynchronously run the callback
|
||||
Util.FireAndForget(FireQueueEmpty, categories);
|
||||
// m_nextOnQueueEmpty = 0;
|
||||
|
||||
m_categories = categories;
|
||||
|
||||
if (HasUpdates(m_categories))
|
||||
{
|
||||
// Asynchronously run the callback
|
||||
Util.FireAndForget(FireQueueEmpty, categories);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_isQueueEmptyRunning = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool m_isQueueEmptyRunning;
|
||||
private ThrottleOutPacketTypeFlags m_categories = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Fires the OnQueueEmpty callback and sets the minimum time that it
|
||||
/// can be called again
|
||||
@@ -663,22 +689,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
/// signature</param>
|
||||
private void FireQueueEmpty(object o)
|
||||
{
|
||||
const int MIN_CALLBACK_MS = 30;
|
||||
// int start = Environment.TickCount & Int32.MaxValue;
|
||||
// const int MIN_CALLBACK_MS = 30;
|
||||
|
||||
ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o;
|
||||
QueueEmpty callback = OnQueueEmpty;
|
||||
|
||||
int start = Environment.TickCount & Int32.MaxValue;
|
||||
// if (m_udpServer.IsRunningOutbound)
|
||||
// {
|
||||
ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o;
|
||||
QueueEmpty callback = OnQueueEmpty;
|
||||
|
||||
if (callback != null)
|
||||
{
|
||||
try { callback(categories); }
|
||||
catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); }
|
||||
}
|
||||
if (callback != null)
|
||||
{
|
||||
// if (m_udpServer.IsRunningOutbound)
|
||||
// {
|
||||
try { callback(categories); }
|
||||
catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); }
|
||||
// }
|
||||
}
|
||||
// }
|
||||
|
||||
m_nextOnQueueEmpty = start + MIN_CALLBACK_MS;
|
||||
if (m_nextOnQueueEmpty == 0)
|
||||
m_nextOnQueueEmpty = 1;
|
||||
// m_nextOnQueueEmpty = start + MIN_CALLBACK_MS;
|
||||
// if (m_nextOnQueueEmpty == 0)
|
||||
// m_nextOnQueueEmpty = 1;
|
||||
|
||||
// }
|
||||
|
||||
m_isQueueEmptyRunning = false;
|
||||
}
|
||||
internal void ForceThrottleSetting(int throttle, int setting)
|
||||
{
|
||||
|
||||
@@ -67,11 +67,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
{
|
||||
m_udpServer.AddScene(scene);
|
||||
|
||||
StatsManager.RegisterStat(
|
||||
new Stat(
|
||||
"IncomingUDPReceivesCount",
|
||||
"Number of UDP receives performed",
|
||||
"Number of UDP receives performed",
|
||||
"",
|
||||
"clientstack",
|
||||
scene.Name,
|
||||
StatType.Pull,
|
||||
MeasuresOfInterest.AverageChangeOverTime,
|
||||
stat => stat.Value = m_udpServer.UdpReceives,
|
||||
StatVerbosity.Debug));
|
||||
|
||||
StatsManager.RegisterStat(
|
||||
new Stat(
|
||||
"IncomingPacketsProcessedCount",
|
||||
"Number of inbound UDP packets processed",
|
||||
"Number of inbound UDP packets processed",
|
||||
"Number of inbound LL protocol packets processed",
|
||||
"Number of inbound LL protocol packets processed",
|
||||
"",
|
||||
"clientstack",
|
||||
scene.Name,
|
||||
@@ -79,6 +92,34 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
MeasuresOfInterest.AverageChangeOverTime,
|
||||
stat => stat.Value = m_udpServer.IncomingPacketsProcessed,
|
||||
StatVerbosity.Debug));
|
||||
|
||||
StatsManager.RegisterStat(
|
||||
new Stat(
|
||||
"OutgoingUDPSendsCount",
|
||||
"Number of UDP sends performed",
|
||||
"Number of UDP sends performed",
|
||||
"",
|
||||
"clientstack",
|
||||
scene.Name,
|
||||
StatType.Pull,
|
||||
MeasuresOfInterest.AverageChangeOverTime,
|
||||
stat => stat.Value = m_udpServer.UdpSends,
|
||||
StatVerbosity.Debug));
|
||||
|
||||
StatsManager.RegisterStat(
|
||||
new Stat(
|
||||
"AverageUDPProcessTime",
|
||||
"Average number of milliseconds taken to process each incoming UDP packet in a sample.",
|
||||
"This is for initial receive processing which is separate from the later client LL packet processing stage.",
|
||||
"ms",
|
||||
"clientstack",
|
||||
scene.Name,
|
||||
StatType.Pull,
|
||||
MeasuresOfInterest.None,
|
||||
stat => stat.Value = m_udpServer.AverageReceiveTicksForLastSamplePeriod / TimeSpan.TicksPerMillisecond,
|
||||
// stat =>
|
||||
// stat.Value = Math.Round(m_udpServer.AverageReceiveTicksForLastSamplePeriod / TimeSpan.TicksPerMillisecond, 7),
|
||||
StatVerbosity.Debug));
|
||||
}
|
||||
|
||||
public bool HandlesRegion(Location x)
|
||||
@@ -185,6 +226,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
protected bool m_sendPing;
|
||||
|
||||
private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>();
|
||||
|
||||
/// <summary>
|
||||
/// Event used to signal when queued packets are available for sending.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This allows the outbound loop to only operate when there is data to send rather than continuously polling.
|
||||
/// Some data is sent immediately and not queued. That data would not trigger this event.
|
||||
/// </remarks>
|
||||
private AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false);
|
||||
|
||||
private Pool<IncomingPacket> m_incomingPacketPool;
|
||||
|
||||
/// <summary>
|
||||
@@ -462,6 +513,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
m_scene = (Scene)scene;
|
||||
m_location = new Location(m_scene.RegionInfo.RegionHandle);
|
||||
|
||||
StatsManager.RegisterStat(
|
||||
new Stat(
|
||||
"InboxPacketsCount",
|
||||
"Number of LL protocol packets waiting for the second stage of processing after initial receive.",
|
||||
"Number of LL protocol packets waiting for the second stage of processing after initial receive.",
|
||||
"",
|
||||
"clientstack",
|
||||
scene.Name,
|
||||
StatType.Pull,
|
||||
MeasuresOfInterest.AverageChangeOverTime,
|
||||
stat => stat.Value = packetInbox.Count,
|
||||
StatVerbosity.Debug));
|
||||
|
||||
// XXX: These stats are also pool stats but we register them separately since they are currently not
|
||||
// turned on and off by EnablePools()/DisablePools()
|
||||
StatsManager.RegisterStat(
|
||||
@@ -575,6 +639,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
"debug lludp status",
|
||||
"Return status of LLUDP packet processing.",
|
||||
HandleStatusCommand);
|
||||
|
||||
MainConsole.Instance.Commands.AddCommand(
|
||||
"Debug",
|
||||
false,
|
||||
"debug lludp toggle agentupdate",
|
||||
"debug lludp toggle agentupdate",
|
||||
"Toggle whether agentupdate packets are processed or simply discarded.",
|
||||
HandleAgentUpdateCommand);
|
||||
}
|
||||
|
||||
private void HandlePacketCommand(string module, string[] args)
|
||||
@@ -709,6 +781,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
}
|
||||
}
|
||||
|
||||
bool m_discardAgentUpdates;
|
||||
|
||||
private void HandleAgentUpdateCommand(string module, string[] args)
|
||||
{
|
||||
if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
|
||||
return;
|
||||
|
||||
m_discardAgentUpdates = !m_discardAgentUpdates;
|
||||
|
||||
MainConsole.Instance.OutputFormat(
|
||||
"Discard AgentUpdates now {0} for {1}", m_discardAgentUpdates, m_scene.Name);
|
||||
}
|
||||
|
||||
private void HandleStatusCommand(string module, string[] args)
|
||||
{
|
||||
if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
|
||||
@@ -809,12 +894,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
}
|
||||
|
||||
PacketPool.Instance.ReturnPacket(packet);
|
||||
|
||||
m_dataPresentEvent.Set();
|
||||
|
||||
}
|
||||
|
||||
private AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false);
|
||||
|
||||
/// <summary>
|
||||
/// Start the process of sending a packet to the client.
|
||||
/// </summary>
|
||||
@@ -1325,6 +1408,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length);
|
||||
#endregion BinaryStats
|
||||
|
||||
if (packet.Type == PacketType.AgentUpdate)
|
||||
{
|
||||
if (m_discardAgentUpdates)
|
||||
return;
|
||||
|
||||
((LLClientView)client).TotalAgentUpdates++;
|
||||
|
||||
AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
|
||||
|
||||
LLClientView llClient = client as LLClientView;
|
||||
if (agentUpdate.AgentData.SessionID != client.SessionId
|
||||
|| agentUpdate.AgentData.AgentID != client.AgentId
|
||||
|| !(llClient == null || llClient.CheckAgentUpdateSignificance(agentUpdate.AgentData)) )
|
||||
{
|
||||
PacketPool.Instance.ReturnPacket(packet);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#region Ping Check Handling
|
||||
|
||||
if (packet.Type == PacketType.StartPingCheck)
|
||||
@@ -1734,7 +1836,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
// Action generic every round
|
||||
Action<IClientAPI> clientPacketHandler = ClientOutgoingPacketHandler;
|
||||
|
||||
// while (true)
|
||||
while (base.IsRunningOutbound)
|
||||
{
|
||||
m_scene.ThreadAlive(2);
|
||||
@@ -1798,6 +1899,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
// token bucket could get more tokens
|
||||
//if (!m_packetSent)
|
||||
// Thread.Sleep((int)TickCountResolution);
|
||||
//
|
||||
// Instead, now wait for data present to be explicitly signalled. Evidence so far is that with
|
||||
// modern mono it reduces CPU base load since there is no more continuous polling.
|
||||
m_dataPresentEvent.WaitOne(100);
|
||||
|
||||
Watchdog.UpdateThread();
|
||||
|
||||
@@ -77,6 +77,36 @@ namespace OpenMetaverse
|
||||
/// <remarks>If IsRunningOut = false, then any request to send a packet is simply dropped.</remarks>
|
||||
public bool IsRunningOutbound { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of UDP receives.
|
||||
/// </summary>
|
||||
public int UdpReceives { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of UDP sends
|
||||
/// </summary>
|
||||
public int UdpSends { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of receives over which to establish a receive time average.
|
||||
/// </summary>
|
||||
private readonly static int s_receiveTimeSamples = 500;
|
||||
|
||||
/// <summary>
|
||||
/// Current number of samples taken to establish a receive time average.
|
||||
/// </summary>
|
||||
private int m_currentReceiveTimeSamples;
|
||||
|
||||
/// <summary>
|
||||
/// Cumulative receive time for the sample so far.
|
||||
/// </summary>
|
||||
private int m_receiveTicksInCurrentSamplePeriod;
|
||||
|
||||
/// <summary>
|
||||
/// The average time taken for each require receive in the last sample.
|
||||
/// </summary>
|
||||
public float AverageReceiveTicksForLastSamplePeriod { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
@@ -111,6 +141,8 @@ namespace OpenMetaverse
|
||||
|
||||
if (!IsRunningInbound)
|
||||
{
|
||||
m_log.DebugFormat("[UDPBASE]: Starting inbound UDP loop");
|
||||
|
||||
const int SIO_UDP_CONNRESET = -1744830452;
|
||||
|
||||
IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort);
|
||||
@@ -151,6 +183,8 @@ namespace OpenMetaverse
|
||||
/// </summary>
|
||||
public void StartOutbound()
|
||||
{
|
||||
m_log.DebugFormat("[UDPBASE]: Starting outbound UDP loop");
|
||||
|
||||
IsRunningOutbound = true;
|
||||
}
|
||||
|
||||
@@ -158,10 +192,8 @@ namespace OpenMetaverse
|
||||
{
|
||||
if (IsRunningInbound)
|
||||
{
|
||||
// wait indefinitely for a writer lock. Once this is called, the .NET runtime
|
||||
// will deny any more reader locks, in effect blocking all other send/receive
|
||||
// threads. Once we have the lock, we set IsRunningInbound = false to inform the other
|
||||
// threads that the socket is closed.
|
||||
m_log.DebugFormat("[UDPBASE]: Stopping inbound UDP loop");
|
||||
|
||||
IsRunningInbound = false;
|
||||
m_udpSocket.Close();
|
||||
}
|
||||
@@ -169,6 +201,8 @@ namespace OpenMetaverse
|
||||
|
||||
public void StopOutbound()
|
||||
{
|
||||
m_log.DebugFormat("[UDPBASE]: Stopping outbound UDP loop");
|
||||
|
||||
IsRunningOutbound = false;
|
||||
}
|
||||
|
||||
@@ -267,6 +301,8 @@ namespace OpenMetaverse
|
||||
// to AsyncBeginReceive
|
||||
if (IsRunningInbound)
|
||||
{
|
||||
UdpReceives++;
|
||||
|
||||
// Asynchronous mode will start another receive before the
|
||||
// callback for this packet is even fired. Very parallel :-)
|
||||
if (m_asyncPacketHandling)
|
||||
@@ -278,6 +314,8 @@ namespace OpenMetaverse
|
||||
|
||||
try
|
||||
{
|
||||
int startTick = Util.EnvironmentTickCount();
|
||||
|
||||
// get the length of data actually read from the socket, store it with the
|
||||
// buffer
|
||||
buffer.DataLength = m_udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint);
|
||||
@@ -285,6 +323,23 @@ namespace OpenMetaverse
|
||||
// call the abstract method PacketReceived(), passing the buffer that
|
||||
// has just been filled from the socket read.
|
||||
PacketReceived(buffer);
|
||||
|
||||
// If more than one thread can be calling AsyncEndReceive() at once (e.g. if m_asyncPacketHandler)
|
||||
// then a particular stat may be inaccurate due to a race condition. We won't worry about this
|
||||
// since this should be rare and won't cause a runtime problem.
|
||||
if (m_currentReceiveTimeSamples >= s_receiveTimeSamples)
|
||||
{
|
||||
AverageReceiveTicksForLastSamplePeriod
|
||||
= (float)m_receiveTicksInCurrentSamplePeriod / s_receiveTimeSamples;
|
||||
|
||||
m_receiveTicksInCurrentSamplePeriod = 0;
|
||||
m_currentReceiveTimeSamples = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_receiveTicksInCurrentSamplePeriod += Util.EnvironmentTickCountSubtract(startTick);
|
||||
m_currentReceiveTimeSamples++;
|
||||
}
|
||||
}
|
||||
catch (SocketException) { }
|
||||
catch (ObjectDisposedException) { }
|
||||
@@ -298,14 +353,13 @@ namespace OpenMetaverse
|
||||
if (!m_asyncPacketHandling)
|
||||
AsyncBeginReceive();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void AsyncBeginSend(UDPPacketBuffer buf)
|
||||
{
|
||||
if (IsRunningOutbound)
|
||||
{
|
||||
// if (IsRunningOutbound)
|
||||
// {
|
||||
try
|
||||
{
|
||||
m_udpSocket.BeginSendTo(
|
||||
@@ -319,7 +373,7 @@ namespace OpenMetaverse
|
||||
}
|
||||
catch (SocketException) { }
|
||||
catch (ObjectDisposedException) { }
|
||||
}
|
||||
// }
|
||||
}
|
||||
|
||||
void AsyncEndSend(IAsyncResult result)
|
||||
@@ -328,6 +382,8 @@ namespace OpenMetaverse
|
||||
{
|
||||
// UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState;
|
||||
m_udpSocket.EndSendTo(result);
|
||||
|
||||
UdpSends++;
|
||||
}
|
||||
catch (SocketException) { }
|
||||
catch (ObjectDisposedException) { }
|
||||
|
||||
Reference in New Issue
Block a user