* Big performance increase in loading prims from the region database with MySQL
* Handle the AgentFOV packet * Bypass queuing and throttles for ping checks to make ping times more closely match network latency * Only track reliable bytes in LLUDPCLient.BytesSinceLastACKprioritization
parent
a3f93cffb4
commit
b4526a5a6d
|
@ -403,26 +403,23 @@ namespace OpenSim.Data.MySQL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<SceneObjectGroup> LoadObjects(UUID regionUUID)
|
public List<SceneObjectGroup> LoadObjects(UUID regionID)
|
||||||
{
|
{
|
||||||
UUID lastGroupID = UUID.Zero;
|
const int ROWS_PER_QUERY = 5000;
|
||||||
|
|
||||||
|
Dictionary<UUID, SceneObjectPart> prims = new Dictionary<UUID, SceneObjectPart>(ROWS_PER_QUERY);
|
||||||
Dictionary<UUID, SceneObjectGroup> objects = new Dictionary<UUID, SceneObjectGroup>();
|
Dictionary<UUID, SceneObjectGroup> objects = new Dictionary<UUID, SceneObjectGroup>();
|
||||||
Dictionary<UUID, SceneObjectPart> prims = new Dictionary<UUID, SceneObjectPart>();
|
|
||||||
SceneObjectGroup grp = null;
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
|
#region Prim Loading
|
||||||
|
|
||||||
lock (m_Connection)
|
lock (m_Connection)
|
||||||
{
|
{
|
||||||
using (MySqlCommand cmd = m_Connection.CreateCommand())
|
using (MySqlCommand cmd = m_Connection.CreateCommand())
|
||||||
{
|
{
|
||||||
cmd.CommandText = "select *, " +
|
cmd.CommandText =
|
||||||
"case when prims.UUID = SceneGroupID " +
|
"SELECT * FROM prims LEFT JOIN primshapes ON prims.UUID = primshapes.UUID WHERE RegionUUID = ?RegionUUID";
|
||||||
"then 0 else 1 end as sort from prims " +
|
cmd.Parameters.AddWithValue("RegionUUID", regionID.ToString());
|
||||||
"left join primshapes on prims.UUID = primshapes.UUID " +
|
|
||||||
"where RegionUUID = ?RegionUUID " +
|
|
||||||
"order by SceneGroupID asc, sort asc, LinkNumber asc";
|
|
||||||
|
|
||||||
cmd.Parameters.AddWithValue("RegionUUID", regionUUID.ToString());
|
|
||||||
|
|
||||||
using (IDataReader reader = ExecuteReader(cmd))
|
using (IDataReader reader = ExecuteReader(cmd))
|
||||||
{
|
{
|
||||||
|
@ -434,56 +431,61 @@ namespace OpenSim.Data.MySQL
|
||||||
else
|
else
|
||||||
prim.Shape = BuildShape(reader);
|
prim.Shape = BuildShape(reader);
|
||||||
|
|
||||||
|
UUID parentID = new UUID(reader["SceneGroupID"].ToString());
|
||||||
|
if (parentID != prim.UUID)
|
||||||
|
prim.ParentUUID = parentID;
|
||||||
|
|
||||||
prims[prim.UUID] = prim;
|
prims[prim.UUID] = prim;
|
||||||
|
|
||||||
UUID groupID = new UUID(reader["SceneGroupID"].ToString());
|
|
||||||
|
|
||||||
if (groupID != lastGroupID) // New SOG
|
|
||||||
{
|
|
||||||
if (grp != null)
|
|
||||||
objects[grp.UUID] = grp;
|
|
||||||
|
|
||||||
lastGroupID = groupID;
|
|
||||||
|
|
||||||
// There sometimes exist OpenSim bugs that 'orphan groups' so that none of the prims are
|
|
||||||
// recorded as the root prim (for which the UUID must equal the persisted group UUID). In
|
|
||||||
// this case, force the UUID to be the same as the group UUID so that at least these can be
|
|
||||||
// deleted (we need to change the UUID so that any other prims in the linkset can also be
|
|
||||||
// deleted).
|
|
||||||
if (prim.UUID != groupID && groupID != UUID.Zero)
|
|
||||||
{
|
|
||||||
m_log.WarnFormat(
|
|
||||||
"[REGION DB]: Found root prim {0} {1} at {2} where group was actually {3}. Forcing UUID to group UUID",
|
|
||||||
prim.Name, prim.UUID, prim.GroupPosition, groupID);
|
|
||||||
|
|
||||||
prim.UUID = groupID;
|
|
||||||
}
|
|
||||||
|
|
||||||
grp = new SceneObjectGroup(prim);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Black magic to preserve link numbers
|
|
||||||
//
|
|
||||||
int link = prim.LinkNum;
|
|
||||||
|
|
||||||
grp.AddPart(prim);
|
|
||||||
|
|
||||||
if (link != 0)
|
|
||||||
prim.LinkNum = link;
|
|
||||||
}
|
|
||||||
|
|
||||||
++count;
|
++count;
|
||||||
if (count % 5000 == 0)
|
if (count % ROWS_PER_QUERY == 0)
|
||||||
m_log.Debug("[REGION DB]: Loaded " + count + " prims...");
|
m_log.Debug("[REGION DB]: Loaded " + count + " prims...");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (grp != null)
|
|
||||||
objects[grp.UUID] = grp;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion Prim Loading
|
||||||
|
|
||||||
|
#region SceneObjectGroup Creation
|
||||||
|
|
||||||
|
// Create all of the SOGs from the root prims first
|
||||||
|
foreach (SceneObjectPart prim in prims.Values)
|
||||||
|
{
|
||||||
|
if (prim.ParentUUID == UUID.Zero)
|
||||||
|
objects[prim.UUID] = new SceneObjectGroup(prim);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add all of the children objects to the SOGs
|
||||||
|
foreach (SceneObjectPart prim in prims.Values)
|
||||||
|
{
|
||||||
|
SceneObjectGroup sog;
|
||||||
|
if (prim.UUID != prim.ParentUUID)
|
||||||
|
{
|
||||||
|
if (objects.TryGetValue(prim.ParentUUID, out sog))
|
||||||
|
{
|
||||||
|
int originalLinkNum = prim.LinkNum;
|
||||||
|
|
||||||
|
sog.AddPart(prim);
|
||||||
|
|
||||||
|
// SceneObjectGroup.AddPart() tries to be smart and automatically set the LinkNum.
|
||||||
|
// We override that here
|
||||||
|
if (originalLinkNum != 0)
|
||||||
|
prim.LinkNum = originalLinkNum;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_log.Warn("[REGION DB]: Database contains an orphan child prim " + prim.UUID + " pointing to missing parent " + prim.ParentUUID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion SceneObjectGroup Creation
|
||||||
|
|
||||||
|
m_log.DebugFormat("[REGION DB]: Loaded {0} objects using {1} prims", objects.Count, prims.Count);
|
||||||
|
|
||||||
|
#region Prim Inventory Loading
|
||||||
|
|
||||||
// Instead of attempting to LoadItems on every prim,
|
// Instead of attempting to LoadItems on every prim,
|
||||||
// most of which probably have no items... get a
|
// most of which probably have no items... get a
|
||||||
// list from DB of all prims which have items and
|
// list from DB of all prims which have items and
|
||||||
|
@ -493,7 +495,7 @@ namespace OpenSim.Data.MySQL
|
||||||
{
|
{
|
||||||
using (MySqlCommand itemCmd = m_Connection.CreateCommand())
|
using (MySqlCommand itemCmd = m_Connection.CreateCommand())
|
||||||
{
|
{
|
||||||
itemCmd.CommandText = "select distinct primID from primitems";
|
itemCmd.CommandText = "SELECT DISTINCT primID FROM primitems";
|
||||||
using (IDataReader itemReader = ExecuteReader(itemCmd))
|
using (IDataReader itemReader = ExecuteReader(itemCmd))
|
||||||
{
|
{
|
||||||
while (itemReader.Read())
|
while (itemReader.Read())
|
||||||
|
@ -502,9 +504,7 @@ namespace OpenSim.Data.MySQL
|
||||||
{
|
{
|
||||||
UUID primID = new UUID(itemReader["primID"].ToString());
|
UUID primID = new UUID(itemReader["primID"].ToString());
|
||||||
if (prims.ContainsKey(primID))
|
if (prims.ContainsKey(primID))
|
||||||
{
|
|
||||||
primsWithInventory.Add(prims[primID]);
|
primsWithInventory.Add(prims[primID]);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -512,9 +512,14 @@ namespace OpenSim.Data.MySQL
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (SceneObjectPart prim in primsWithInventory)
|
foreach (SceneObjectPart prim in primsWithInventory)
|
||||||
|
{
|
||||||
LoadItems(prim);
|
LoadItems(prim);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Prim Inventory Loading
|
||||||
|
|
||||||
|
m_log.DebugFormat("[REGION DB]: Loaded inventory from {0} objects", primsWithInventory.Count);
|
||||||
|
|
||||||
m_log.DebugFormat("[REGION DB]: Loaded {0} objects using {1} prims", objects.Count, prims.Count);
|
|
||||||
return new List<SceneObjectGroup>(objects.Values);
|
return new List<SceneObjectGroup>(objects.Values);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -811,137 +816,137 @@ namespace OpenSim.Data.MySQL
|
||||||
private SceneObjectPart BuildPrim(IDataReader row)
|
private SceneObjectPart BuildPrim(IDataReader row)
|
||||||
{
|
{
|
||||||
SceneObjectPart prim = new SceneObjectPart();
|
SceneObjectPart prim = new SceneObjectPart();
|
||||||
prim.UUID = new UUID((String) row["UUID"]);
|
prim.UUID = new UUID((string)row["UUID"]);
|
||||||
// explicit conversion of integers is required, which sort
|
// explicit conversion of integers is required, which sort
|
||||||
// of sucks. No idea if there is a shortcut here or not.
|
// of sucks. No idea if there is a shortcut here or not.
|
||||||
prim.CreationDate = Convert.ToInt32(row["CreationDate"]);
|
prim.CreationDate = (int)row["CreationDate"];
|
||||||
if (row["Name"] != DBNull.Value)
|
if (row["Name"] != DBNull.Value)
|
||||||
prim.Name = (String)row["Name"];
|
prim.Name = (string)row["Name"];
|
||||||
else
|
else
|
||||||
prim.Name = string.Empty;
|
prim.Name = String.Empty;
|
||||||
// various text fields
|
// Various text fields
|
||||||
prim.Text = (String) row["Text"];
|
prim.Text = (string)row["Text"];
|
||||||
prim.Color = Color.FromArgb(Convert.ToInt32(row["ColorA"]),
|
prim.Color = Color.FromArgb((int)row["ColorA"],
|
||||||
Convert.ToInt32(row["ColorR"]),
|
(int)row["ColorR"],
|
||||||
Convert.ToInt32(row["ColorG"]),
|
(int)row["ColorG"],
|
||||||
Convert.ToInt32(row["ColorB"]));
|
(int)row["ColorB"]);
|
||||||
prim.Description = (String) row["Description"];
|
prim.Description = (string)row["Description"];
|
||||||
prim.SitName = (String) row["SitName"];
|
prim.SitName = (string)row["SitName"];
|
||||||
prim.TouchName = (String) row["TouchName"];
|
prim.TouchName = (string)row["TouchName"];
|
||||||
// permissions
|
// Permissions
|
||||||
prim.ObjectFlags = Convert.ToUInt32(row["ObjectFlags"]);
|
prim.ObjectFlags = (uint)(int)row["ObjectFlags"];
|
||||||
prim.CreatorID = new UUID((String) row["CreatorID"]);
|
prim.CreatorID = new UUID((string)row["CreatorID"]);
|
||||||
prim.OwnerID = new UUID((String) row["OwnerID"]);
|
prim.OwnerID = new UUID((string)row["OwnerID"]);
|
||||||
prim.GroupID = new UUID((String) row["GroupID"]);
|
prim.GroupID = new UUID((string)row["GroupID"]);
|
||||||
prim.LastOwnerID = new UUID((String) row["LastOwnerID"]);
|
prim.LastOwnerID = new UUID((string)row["LastOwnerID"]);
|
||||||
prim.OwnerMask = Convert.ToUInt32(row["OwnerMask"]);
|
prim.OwnerMask = (uint)(int)row["OwnerMask"];
|
||||||
prim.NextOwnerMask = Convert.ToUInt32(row["NextOwnerMask"]);
|
prim.NextOwnerMask = (uint)(int)row["NextOwnerMask"];
|
||||||
prim.GroupMask = Convert.ToUInt32(row["GroupMask"]);
|
prim.GroupMask = (uint)(int)row["GroupMask"];
|
||||||
prim.EveryoneMask = Convert.ToUInt32(row["EveryoneMask"]);
|
prim.EveryoneMask = (uint)(int)row["EveryoneMask"];
|
||||||
prim.BaseMask = Convert.ToUInt32(row["BaseMask"]);
|
prim.BaseMask = (uint)(int)row["BaseMask"];
|
||||||
// vectors
|
// Vectors
|
||||||
prim.OffsetPosition = new Vector3(
|
prim.OffsetPosition = new Vector3(
|
||||||
Convert.ToSingle(row["PositionX"]),
|
(float)(double)row["PositionX"],
|
||||||
Convert.ToSingle(row["PositionY"]),
|
(float)(double)row["PositionY"],
|
||||||
Convert.ToSingle(row["PositionZ"])
|
(float)(double)row["PositionZ"]
|
||||||
);
|
);
|
||||||
prim.GroupPosition = new Vector3(
|
prim.GroupPosition = new Vector3(
|
||||||
Convert.ToSingle(row["GroupPositionX"]),
|
(float)(double)row["GroupPositionX"],
|
||||||
Convert.ToSingle(row["GroupPositionY"]),
|
(float)(double)row["GroupPositionY"],
|
||||||
Convert.ToSingle(row["GroupPositionZ"])
|
(float)(double)row["GroupPositionZ"]
|
||||||
);
|
);
|
||||||
prim.Velocity = new Vector3(
|
prim.Velocity = new Vector3(
|
||||||
Convert.ToSingle(row["VelocityX"]),
|
(float)(double)row["VelocityX"],
|
||||||
Convert.ToSingle(row["VelocityY"]),
|
(float)(double)row["VelocityY"],
|
||||||
Convert.ToSingle(row["VelocityZ"])
|
(float)(double)row["VelocityZ"]
|
||||||
);
|
);
|
||||||
prim.AngularVelocity = new Vector3(
|
prim.AngularVelocity = new Vector3(
|
||||||
Convert.ToSingle(row["AngularVelocityX"]),
|
(float)(double)row["AngularVelocityX"],
|
||||||
Convert.ToSingle(row["AngularVelocityY"]),
|
(float)(double)row["AngularVelocityY"],
|
||||||
Convert.ToSingle(row["AngularVelocityZ"])
|
(float)(double)row["AngularVelocityZ"]
|
||||||
);
|
);
|
||||||
prim.Acceleration = new Vector3(
|
prim.Acceleration = new Vector3(
|
||||||
Convert.ToSingle(row["AccelerationX"]),
|
(float)(double)row["AccelerationX"],
|
||||||
Convert.ToSingle(row["AccelerationY"]),
|
(float)(double)row["AccelerationY"],
|
||||||
Convert.ToSingle(row["AccelerationZ"])
|
(float)(double)row["AccelerationZ"]
|
||||||
);
|
);
|
||||||
// quaternions
|
// quaternions
|
||||||
prim.RotationOffset = new Quaternion(
|
prim.RotationOffset = new Quaternion(
|
||||||
Convert.ToSingle(row["RotationX"]),
|
(float)(double)row["RotationX"],
|
||||||
Convert.ToSingle(row["RotationY"]),
|
(float)(double)row["RotationY"],
|
||||||
Convert.ToSingle(row["RotationZ"]),
|
(float)(double)row["RotationZ"],
|
||||||
Convert.ToSingle(row["RotationW"])
|
(float)(double)row["RotationW"]
|
||||||
);
|
);
|
||||||
prim.SitTargetPositionLL = new Vector3(
|
prim.SitTargetPositionLL = new Vector3(
|
||||||
Convert.ToSingle(row["SitTargetOffsetX"]),
|
(float)(double)row["SitTargetOffsetX"],
|
||||||
Convert.ToSingle(row["SitTargetOffsetY"]),
|
(float)(double)row["SitTargetOffsetY"],
|
||||||
Convert.ToSingle(row["SitTargetOffsetZ"])
|
(float)(double)row["SitTargetOffsetZ"]
|
||||||
);
|
);
|
||||||
prim.SitTargetOrientationLL = new Quaternion(
|
prim.SitTargetOrientationLL = new Quaternion(
|
||||||
Convert.ToSingle(row["SitTargetOrientX"]),
|
(float)(double)row["SitTargetOrientX"],
|
||||||
Convert.ToSingle(row["SitTargetOrientY"]),
|
(float)(double)row["SitTargetOrientY"],
|
||||||
Convert.ToSingle(row["SitTargetOrientZ"]),
|
(float)(double)row["SitTargetOrientZ"],
|
||||||
Convert.ToSingle(row["SitTargetOrientW"])
|
(float)(double)row["SitTargetOrientW"]
|
||||||
);
|
);
|
||||||
|
|
||||||
prim.PayPrice[0] = Convert.ToInt32(row["PayPrice"]);
|
prim.PayPrice[0] = (int)row["PayPrice"];
|
||||||
prim.PayPrice[1] = Convert.ToInt32(row["PayButton1"]);
|
prim.PayPrice[1] = (int)row["PayButton1"];
|
||||||
prim.PayPrice[2] = Convert.ToInt32(row["PayButton2"]);
|
prim.PayPrice[2] = (int)row["PayButton2"];
|
||||||
prim.PayPrice[3] = Convert.ToInt32(row["PayButton3"]);
|
prim.PayPrice[3] = (int)row["PayButton3"];
|
||||||
prim.PayPrice[4] = Convert.ToInt32(row["PayButton4"]);
|
prim.PayPrice[4] = (int)row["PayButton4"];
|
||||||
|
|
||||||
prim.Sound = new UUID(row["LoopedSound"].ToString());
|
prim.Sound = new UUID(row["LoopedSound"].ToString());
|
||||||
prim.SoundGain = Convert.ToSingle(row["LoopedSoundGain"]);
|
prim.SoundGain = (float)(double)row["LoopedSoundGain"];
|
||||||
prim.SoundFlags = 1; // If it's persisted at all, it's looped
|
prim.SoundFlags = 1; // If it's persisted at all, it's looped
|
||||||
|
|
||||||
if (!(row["TextureAnimation"] is DBNull))
|
if (!(row["TextureAnimation"] is DBNull))
|
||||||
prim.TextureAnimation = (Byte[])row["TextureAnimation"];
|
prim.TextureAnimation = (byte[])row["TextureAnimation"];
|
||||||
if (!(row["ParticleSystem"] is DBNull))
|
if (!(row["ParticleSystem"] is DBNull))
|
||||||
prim.ParticleSystem = (Byte[])row["ParticleSystem"];
|
prim.ParticleSystem = (byte[])row["ParticleSystem"];
|
||||||
|
|
||||||
prim.RotationalVelocity = new Vector3(
|
prim.RotationalVelocity = new Vector3(
|
||||||
Convert.ToSingle(row["OmegaX"]),
|
(float)(double)row["OmegaX"],
|
||||||
Convert.ToSingle(row["OmegaY"]),
|
(float)(double)row["OmegaY"],
|
||||||
Convert.ToSingle(row["OmegaZ"])
|
(float)(double)row["OmegaZ"]
|
||||||
);
|
);
|
||||||
|
|
||||||
prim.SetCameraEyeOffset(new Vector3(
|
prim.SetCameraEyeOffset(new Vector3(
|
||||||
Convert.ToSingle(row["CameraEyeOffsetX"]),
|
(float)(double)row["CameraEyeOffsetX"],
|
||||||
Convert.ToSingle(row["CameraEyeOffsetY"]),
|
(float)(double)row["CameraEyeOffsetY"],
|
||||||
Convert.ToSingle(row["CameraEyeOffsetZ"])
|
(float)(double)row["CameraEyeOffsetZ"]
|
||||||
));
|
));
|
||||||
|
|
||||||
prim.SetCameraAtOffset(new Vector3(
|
prim.SetCameraAtOffset(new Vector3(
|
||||||
Convert.ToSingle(row["CameraAtOffsetX"]),
|
(float)(double)row["CameraAtOffsetX"],
|
||||||
Convert.ToSingle(row["CameraAtOffsetY"]),
|
(float)(double)row["CameraAtOffsetY"],
|
||||||
Convert.ToSingle(row["CameraAtOffsetZ"])
|
(float)(double)row["CameraAtOffsetZ"]
|
||||||
));
|
));
|
||||||
|
|
||||||
if (Convert.ToInt16(row["ForceMouselook"]) != 0)
|
if ((sbyte)row["ForceMouselook"] != 0)
|
||||||
prim.SetForceMouselook(true);
|
prim.SetForceMouselook(true);
|
||||||
|
|
||||||
prim.ScriptAccessPin = Convert.ToInt32(row["ScriptAccessPin"]);
|
prim.ScriptAccessPin = (int)row["ScriptAccessPin"];
|
||||||
|
|
||||||
if (Convert.ToInt16(row["AllowedDrop"]) != 0)
|
if ((sbyte)row["AllowedDrop"] != 0)
|
||||||
prim.AllowedDrop = true;
|
prim.AllowedDrop = true;
|
||||||
|
|
||||||
if (Convert.ToInt16(row["DieAtEdge"]) != 0)
|
if ((sbyte)row["DieAtEdge"] != 0)
|
||||||
prim.DIE_AT_EDGE = true;
|
prim.DIE_AT_EDGE = true;
|
||||||
|
|
||||||
prim.SalePrice = Convert.ToInt32(row["SalePrice"]);
|
prim.SalePrice = (int)row["SalePrice"];
|
||||||
prim.ObjectSaleType = unchecked((byte)Convert.ToSByte(row["SaleType"]));
|
prim.ObjectSaleType = unchecked((byte)(sbyte)row["SaleType"]);
|
||||||
|
|
||||||
prim.Material = unchecked((byte)Convert.ToSByte(row["Material"]));
|
prim.Material = unchecked((byte)(sbyte)row["Material"]);
|
||||||
|
|
||||||
if (!(row["ClickAction"] is DBNull))
|
if (!(row["ClickAction"] is DBNull))
|
||||||
prim.ClickAction = unchecked((byte)Convert.ToSByte(row["ClickAction"]));
|
prim.ClickAction = unchecked((byte)(sbyte)row["ClickAction"]);
|
||||||
|
|
||||||
prim.CollisionSound = new UUID(row["CollisionSound"].ToString());
|
prim.CollisionSound = new UUID(row["CollisionSound"].ToString());
|
||||||
prim.CollisionSoundVolume = Convert.ToSingle(row["CollisionSoundVolume"]);
|
prim.CollisionSoundVolume = (float)(double)row["CollisionSoundVolume"];
|
||||||
|
|
||||||
if (Convert.ToInt16(row["PassTouches"]) != 0)
|
if ((sbyte)row["PassTouches"] != 0)
|
||||||
prim.PassTouches = true;
|
prim.PassTouches = true;
|
||||||
prim.LinkNum = Convert.ToInt32(row["LinkNumber"]);
|
prim.LinkNum = (int)row["LinkNumber"];
|
||||||
|
|
||||||
return prim;
|
return prim;
|
||||||
}
|
}
|
||||||
|
|
|
@ -448,6 +448,8 @@ namespace OpenSim.Framework
|
||||||
public delegate void AvatarInterestUpdate(IClientAPI client, uint wantmask, string wanttext, uint skillsmask, string skillstext, string languages);
|
public delegate void AvatarInterestUpdate(IClientAPI client, uint wantmask, string wanttext, uint skillsmask, string skillstext, string languages);
|
||||||
public delegate void PlacesQuery(UUID QueryID, UUID TransactionID, string QueryText, uint QueryFlags, byte Category, string SimName, IClientAPI client);
|
public delegate void PlacesQuery(UUID QueryID, UUID TransactionID, string QueryText, uint QueryFlags, byte Category, string SimName, IClientAPI client);
|
||||||
|
|
||||||
|
public delegate void AgentFOV(IClientAPI client, float verticalAngle);
|
||||||
|
|
||||||
public delegate double UpdatePriorityHandler(UpdatePriorityData data);
|
public delegate double UpdatePriorityHandler(UpdatePriorityData data);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
|
@ -295,6 +295,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
public event MuteListRequest OnMuteListRequest;
|
public event MuteListRequest OnMuteListRequest;
|
||||||
public event AvatarInterestUpdate OnAvatarInterestUpdate;
|
public event AvatarInterestUpdate OnAvatarInterestUpdate;
|
||||||
public event PlacesQuery OnPlacesQuery;
|
public event PlacesQuery OnPlacesQuery;
|
||||||
|
public event AgentFOV OnAgentFOV;
|
||||||
|
|
||||||
#endregion Events
|
#endregion Events
|
||||||
|
|
||||||
|
@ -346,6 +347,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
protected ulong m_activeGroupPowers;
|
protected ulong m_activeGroupPowers;
|
||||||
protected Dictionary<UUID,ulong> m_groupPowers = new Dictionary<UUID, ulong>();
|
protected Dictionary<UUID,ulong> m_groupPowers = new Dictionary<UUID, ulong>();
|
||||||
protected int m_terrainCheckerCount;
|
protected int m_terrainCheckerCount;
|
||||||
|
protected uint m_agentFOVCounter;
|
||||||
|
|
||||||
// These numbers are guesses at a decent tradeoff between responsiveness
|
// These numbers are guesses at a decent tradeoff between responsiveness
|
||||||
// of the interest list and throughput. Lower is more responsive, higher
|
// of the interest list and throughput. Lower is more responsive, higher
|
||||||
|
@ -8871,20 +8873,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
case PacketType.AgentFOV:
|
||||||
|
AgentFOVPacket fovPacket = (AgentFOVPacket)Pack;
|
||||||
|
|
||||||
|
if (fovPacket.FOVBlock.GenCounter > m_agentFOVCounter)
|
||||||
|
{
|
||||||
|
m_agentFOVCounter = fovPacket.FOVBlock.GenCounter;
|
||||||
|
AgentFOV handlerAgentFOV = OnAgentFOV;
|
||||||
|
if (handlerAgentFOV != null)
|
||||||
|
{
|
||||||
|
handlerAgentFOV(this, fovPacket.FOVBlock.VerticalAngle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
#region unimplemented handlers
|
#region unimplemented handlers
|
||||||
|
|
||||||
case PacketType.StartPingCheck:
|
|
||||||
StartPingCheckPacket pingStart = (StartPingCheckPacket)Pack;
|
|
||||||
CompletePingCheckPacket pingComplete = new CompletePingCheckPacket();
|
|
||||||
pingComplete.PingID.PingID = pingStart.PingID.PingID;
|
|
||||||
m_udpServer.SendPacket(m_udpClient, pingComplete, ThrottleOutPacketType.Unknown, false);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PacketType.CompletePingCheck:
|
|
||||||
// TODO: Do stats tracking or something with these?
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PacketType.ViewerStats:
|
case PacketType.ViewerStats:
|
||||||
// TODO: handle this packet
|
// TODO: handle this packet
|
||||||
//m_log.Warn("[CLIENT]: unhandled ViewerStats packet");
|
//m_log.Warn("[CLIENT]: unhandled ViewerStats packet");
|
||||||
|
|
|
@ -572,6 +572,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
for (int i = 0; i < ackPacket.Packets.Length; i++)
|
for (int i = 0; i < ackPacket.Packets.Length; i++)
|
||||||
AcknowledgePacket(udpClient, ackPacket.Packets[i].ID, now, packet.Header.Resent);
|
AcknowledgePacket(udpClient, ackPacket.Packets[i].ID, now, packet.Header.Resent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We don't need to do anything else with PacketAck packets
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion ACK Receiving
|
#endregion ACK Receiving
|
||||||
|
@ -579,20 +582,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
#region ACK Sending
|
#region ACK Sending
|
||||||
|
|
||||||
if (packet.Header.Reliable)
|
if (packet.Header.Reliable)
|
||||||
|
{
|
||||||
udpClient.PendingAcks.Enqueue(packet.Header.Sequence);
|
udpClient.PendingAcks.Enqueue(packet.Header.Sequence);
|
||||||
|
|
||||||
// This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out,
|
// This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out,
|
||||||
// add the current received bytes to it, test if 2*MTU bytes have been sent, if so remove
|
// add the current received bytes to it, test if 2*MTU bytes have been sent, if so remove
|
||||||
// 2*MTU bytes from the value and send ACKs, and finally add the local value back to
|
// 2*MTU bytes from the value and send ACKs, and finally add the local value back to
|
||||||
// client.BytesSinceLastACK. Lockless thread safety
|
// client.BytesSinceLastACK. Lockless thread safety
|
||||||
int bytesSinceLastACK = Interlocked.Exchange(ref udpClient.BytesSinceLastACK, 0);
|
int bytesSinceLastACK = Interlocked.Exchange(ref udpClient.BytesSinceLastACK, 0);
|
||||||
bytesSinceLastACK += buffer.DataLength;
|
bytesSinceLastACK += buffer.DataLength;
|
||||||
if (bytesSinceLastACK > LLUDPServer.MTU * 2)
|
if (bytesSinceLastACK > LLUDPServer.MTU * 2)
|
||||||
{
|
{
|
||||||
bytesSinceLastACK -= LLUDPServer.MTU * 2;
|
bytesSinceLastACK -= LLUDPServer.MTU * 2;
|
||||||
SendAcks(udpClient);
|
SendAcks(udpClient);
|
||||||
|
}
|
||||||
|
Interlocked.Add(ref udpClient.BytesSinceLastACK, bytesSinceLastACK);
|
||||||
}
|
}
|
||||||
Interlocked.Add(ref udpClient.BytesSinceLastACK, bytesSinceLastACK);
|
|
||||||
|
|
||||||
#endregion ACK Sending
|
#endregion ACK Sending
|
||||||
|
|
||||||
|
@ -612,12 +617,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
|
|
||||||
#endregion Incoming Packet Accounting
|
#endregion Incoming Packet Accounting
|
||||||
|
|
||||||
// Don't bother clogging up the queue with PacketAck packets that are already handled here
|
#region Ping Check Handling
|
||||||
if (packet.Type != PacketType.PacketAck)
|
|
||||||
|
if (packet.Type == PacketType.StartPingCheck)
|
||||||
{
|
{
|
||||||
// Inbox insertion
|
// We don't need to do anything else with ping checks
|
||||||
packetInbox.Enqueue(new IncomingPacket(udpClient, packet));
|
StartPingCheckPacket startPing = (StartPingCheckPacket)packet;
|
||||||
|
|
||||||
|
CompletePingCheckPacket completePing = new CompletePingCheckPacket();
|
||||||
|
completePing.PingID.PingID = startPing.PingID.PingID;
|
||||||
|
SendPacket(udpClient, completePing, ThrottleOutPacketType.Unknown, false);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
else if (packet.Type == PacketType.CompletePingCheck)
|
||||||
|
{
|
||||||
|
// We don't currently track client ping times
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Ping Check Handling
|
||||||
|
|
||||||
|
// Inbox insertion
|
||||||
|
packetInbox.Enqueue(new IncomingPacket(udpClient, packet));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void PacketSent(UDPPacketBuffer buffer, int bytesSent)
|
protected override void PacketSent(UDPPacketBuffer buffer, int bytesSent)
|
||||||
|
|
Loading…
Reference in New Issue