aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim
diff options
context:
space:
mode:
authorJohn Hurliman2009-10-18 02:00:42 -0700
committerJohn Hurliman2009-10-18 02:00:42 -0700
commitb4526a5a6d170e04655990c8edb8e355156a2061 (patch)
tree457cc8535e9213f6003545a0363f325b9ef9e90b /OpenSim
parent* Committing Nini.dll with the patch from #3773 applied (diff)
downloadopensim-SC_OLD-b4526a5a6d170e04655990c8edb8e355156a2061.zip
opensim-SC_OLD-b4526a5a6d170e04655990c8edb8e355156a2061.tar.gz
opensim-SC_OLD-b4526a5a6d170e04655990c8edb8e355156a2061.tar.bz2
opensim-SC_OLD-b4526a5a6d170e04655990c8edb8e355156a2061.tar.xz
* 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.BytesSinceLastACK
Diffstat (limited to 'OpenSim')
-rw-r--r--OpenSim/Data/MySQL/MySQLLegacyRegionData.cs271
-rw-r--r--OpenSim/Framework/IClientAPI.cs2
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs24
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs51
4 files changed, 190 insertions, 158 deletions
diff --git a/OpenSim/Data/MySQL/MySQLLegacyRegionData.cs b/OpenSim/Data/MySQL/MySQLLegacyRegionData.cs
index 6bc8bec..801d6b9 100644
--- a/OpenSim/Data/MySQL/MySQLLegacyRegionData.cs
+++ b/OpenSim/Data/MySQL/MySQLLegacyRegionData.cs
@@ -403,26 +403,23 @@ namespace OpenSim.Data.MySQL
403 } 403 }
404 } 404 }
405 405
406 public List<SceneObjectGroup> LoadObjects(UUID regionUUID) 406 public List<SceneObjectGroup> LoadObjects(UUID regionID)
407 { 407 {
408 UUID lastGroupID = UUID.Zero; 408 const int ROWS_PER_QUERY = 5000;
409
410 Dictionary<UUID, SceneObjectPart> prims = new Dictionary<UUID, SceneObjectPart>(ROWS_PER_QUERY);
409 Dictionary<UUID, SceneObjectGroup> objects = new Dictionary<UUID, SceneObjectGroup>(); 411 Dictionary<UUID, SceneObjectGroup> objects = new Dictionary<UUID, SceneObjectGroup>();
410 Dictionary<UUID, SceneObjectPart> prims = new Dictionary<UUID, SceneObjectPart>();
411 SceneObjectGroup grp = null;
412 int count = 0; 412 int count = 0;
413 413
414 #region Prim Loading
415
414 lock (m_Connection) 416 lock (m_Connection)
415 { 417 {
416 using (MySqlCommand cmd = m_Connection.CreateCommand()) 418 using (MySqlCommand cmd = m_Connection.CreateCommand())
417 { 419 {
418 cmd.CommandText = "select *, " + 420 cmd.CommandText =
419 "case when prims.UUID = SceneGroupID " + 421 "SELECT * FROM prims LEFT JOIN primshapes ON prims.UUID = primshapes.UUID WHERE RegionUUID = ?RegionUUID";
420 "then 0 else 1 end as sort from prims " + 422 cmd.Parameters.AddWithValue("RegionUUID", regionID.ToString());
421 "left join primshapes on prims.UUID = primshapes.UUID " +
422 "where RegionUUID = ?RegionUUID " +
423 "order by SceneGroupID asc, sort asc, LinkNumber asc";
424
425 cmd.Parameters.AddWithValue("RegionUUID", regionUUID.ToString());
426 423
427 using (IDataReader reader = ExecuteReader(cmd)) 424 using (IDataReader reader = ExecuteReader(cmd))
428 { 425 {
@@ -434,56 +431,61 @@ namespace OpenSim.Data.MySQL
434 else 431 else
435 prim.Shape = BuildShape(reader); 432 prim.Shape = BuildShape(reader);
436 433
437 prims[prim.UUID] = prim; 434 UUID parentID = new UUID(reader["SceneGroupID"].ToString());
438 435 if (parentID != prim.UUID)
439 UUID groupID = new UUID(reader["SceneGroupID"].ToString()); 436 prim.ParentUUID = parentID;
440 437
441 if (groupID != lastGroupID) // New SOG 438 prims[prim.UUID] = prim;
442 {
443 if (grp != null)
444 objects[grp.UUID] = grp;
445 439
446 lastGroupID = groupID; 440 ++count;
441 if (count % ROWS_PER_QUERY == 0)
442 m_log.Debug("[REGION DB]: Loaded " + count + " prims...");
443 }
444 }
445 }
446 }
447 447
448 // There sometimes exist OpenSim bugs that 'orphan groups' so that none of the prims are 448 #endregion Prim Loading
449 // recorded as the root prim (for which the UUID must equal the persisted group UUID). In
450 // this case, force the UUID to be the same as the group UUID so that at least these can be
451 // deleted (we need to change the UUID so that any other prims in the linkset can also be
452 // deleted).
453 if (prim.UUID != groupID && groupID != UUID.Zero)
454 {
455 m_log.WarnFormat(
456 "[REGION DB]: Found root prim {0} {1} at {2} where group was actually {3}. Forcing UUID to group UUID",
457 prim.Name, prim.UUID, prim.GroupPosition, groupID);
458 449
459 prim.UUID = groupID; 450 #region SceneObjectGroup Creation
460 }
461 451
462 grp = new SceneObjectGroup(prim); 452 // Create all of the SOGs from the root prims first
463 } 453 foreach (SceneObjectPart prim in prims.Values)
464 else 454 {
465 { 455 if (prim.ParentUUID == UUID.Zero)
466 // Black magic to preserve link numbers 456 objects[prim.UUID] = new SceneObjectGroup(prim);
467 // 457 }
468 int link = prim.LinkNum;
469 458
470 grp.AddPart(prim); 459 // Add all of the children objects to the SOGs
460 foreach (SceneObjectPart prim in prims.Values)
461 {
462 SceneObjectGroup sog;
463 if (prim.UUID != prim.ParentUUID)
464 {
465 if (objects.TryGetValue(prim.ParentUUID, out sog))
466 {
467 int originalLinkNum = prim.LinkNum;
471 468
472 if (link != 0) 469 sog.AddPart(prim);
473 prim.LinkNum = link;
474 }
475 470
476 ++count; 471 // SceneObjectGroup.AddPart() tries to be smart and automatically set the LinkNum.
477 if (count % 5000 == 0) 472 // We override that here
478 m_log.Debug("[REGION DB]: Loaded " + count + " prims..."); 473 if (originalLinkNum != 0)
479 } 474 prim.LinkNum = originalLinkNum;
475 }
476 else
477 {
478 m_log.Warn("[REGION DB]: Database contains an orphan child prim " + prim.UUID + " pointing to missing parent " + prim.ParentUUID);
480 } 479 }
481
482 if (grp != null)
483 objects[grp.UUID] = grp;
484 } 480 }
485 } 481 }
486 482
483 #endregion SceneObjectGroup Creation
484
485 m_log.DebugFormat("[REGION DB]: Loaded {0} objects using {1} prims", objects.Count, prims.Count);
486
487 #region Prim Inventory Loading
488
487 // Instead of attempting to LoadItems on every prim, 489 // Instead of attempting to LoadItems on every prim,
488 // most of which probably have no items... get a 490 // most of which probably have no items... get a
489 // list from DB of all prims which have items and 491 // list from DB of all prims which have items and
@@ -493,7 +495,7 @@ namespace OpenSim.Data.MySQL
493 { 495 {
494 using (MySqlCommand itemCmd = m_Connection.CreateCommand()) 496 using (MySqlCommand itemCmd = m_Connection.CreateCommand())
495 { 497 {
496 itemCmd.CommandText = "select distinct primID from primitems"; 498 itemCmd.CommandText = "SELECT DISTINCT primID FROM primitems";
497 using (IDataReader itemReader = ExecuteReader(itemCmd)) 499 using (IDataReader itemReader = ExecuteReader(itemCmd))
498 { 500 {
499 while (itemReader.Read()) 501 while (itemReader.Read())
@@ -502,9 +504,7 @@ namespace OpenSim.Data.MySQL
502 { 504 {
503 UUID primID = new UUID(itemReader["primID"].ToString()); 505 UUID primID = new UUID(itemReader["primID"].ToString());
504 if (prims.ContainsKey(primID)) 506 if (prims.ContainsKey(primID))
505 {
506 primsWithInventory.Add(prims[primID]); 507 primsWithInventory.Add(prims[primID]);
507 }
508 } 508 }
509 } 509 }
510 } 510 }
@@ -512,9 +512,14 @@ namespace OpenSim.Data.MySQL
512 } 512 }
513 513
514 foreach (SceneObjectPart prim in primsWithInventory) 514 foreach (SceneObjectPart prim in primsWithInventory)
515 {
515 LoadItems(prim); 516 LoadItems(prim);
517 }
518
519 #endregion Prim Inventory Loading
520
521 m_log.DebugFormat("[REGION DB]: Loaded inventory from {0} objects", primsWithInventory.Count);
516 522
517 m_log.DebugFormat("[REGION DB]: Loaded {0} objects using {1} prims", objects.Count, prims.Count);
518 return new List<SceneObjectGroup>(objects.Values); 523 return new List<SceneObjectGroup>(objects.Values);
519 } 524 }
520 525
@@ -811,137 +816,137 @@ namespace OpenSim.Data.MySQL
811 private SceneObjectPart BuildPrim(IDataReader row) 816 private SceneObjectPart BuildPrim(IDataReader row)
812 { 817 {
813 SceneObjectPart prim = new SceneObjectPart(); 818 SceneObjectPart prim = new SceneObjectPart();
814 prim.UUID = new UUID((String) row["UUID"]); 819 prim.UUID = new UUID((string)row["UUID"]);
815 // explicit conversion of integers is required, which sort 820 // explicit conversion of integers is required, which sort
816 // of sucks. No idea if there is a shortcut here or not. 821 // of sucks. No idea if there is a shortcut here or not.
817 prim.CreationDate = Convert.ToInt32(row["CreationDate"]); 822 prim.CreationDate = (int)row["CreationDate"];
818 if (row["Name"] != DBNull.Value) 823 if (row["Name"] != DBNull.Value)
819 prim.Name = (String)row["Name"]; 824 prim.Name = (string)row["Name"];
820 else 825 else
821 prim.Name = string.Empty; 826 prim.Name = String.Empty;
822 // various text fields 827 // Various text fields
823 prim.Text = (String) row["Text"]; 828 prim.Text = (string)row["Text"];
824 prim.Color = Color.FromArgb(Convert.ToInt32(row["ColorA"]), 829 prim.Color = Color.FromArgb((int)row["ColorA"],
825 Convert.ToInt32(row["ColorR"]), 830 (int)row["ColorR"],
826 Convert.ToInt32(row["ColorG"]), 831 (int)row["ColorG"],
827 Convert.ToInt32(row["ColorB"])); 832 (int)row["ColorB"]);
828 prim.Description = (String) row["Description"]; 833 prim.Description = (string)row["Description"];
829 prim.SitName = (String) row["SitName"]; 834 prim.SitName = (string)row["SitName"];
830 prim.TouchName = (String) row["TouchName"]; 835 prim.TouchName = (string)row["TouchName"];
831 // permissions 836 // Permissions
832 prim.ObjectFlags = Convert.ToUInt32(row["ObjectFlags"]); 837 prim.ObjectFlags = (uint)(int)row["ObjectFlags"];
833 prim.CreatorID = new UUID((String) row["CreatorID"]); 838 prim.CreatorID = new UUID((string)row["CreatorID"]);
834 prim.OwnerID = new UUID((String) row["OwnerID"]); 839 prim.OwnerID = new UUID((string)row["OwnerID"]);
835 prim.GroupID = new UUID((String) row["GroupID"]); 840 prim.GroupID = new UUID((string)row["GroupID"]);
836 prim.LastOwnerID = new UUID((String) row["LastOwnerID"]); 841 prim.LastOwnerID = new UUID((string)row["LastOwnerID"]);
837 prim.OwnerMask = Convert.ToUInt32(row["OwnerMask"]); 842 prim.OwnerMask = (uint)(int)row["OwnerMask"];
838 prim.NextOwnerMask = Convert.ToUInt32(row["NextOwnerMask"]); 843 prim.NextOwnerMask = (uint)(int)row["NextOwnerMask"];
839 prim.GroupMask = Convert.ToUInt32(row["GroupMask"]); 844 prim.GroupMask = (uint)(int)row["GroupMask"];
840 prim.EveryoneMask = Convert.ToUInt32(row["EveryoneMask"]); 845 prim.EveryoneMask = (uint)(int)row["EveryoneMask"];
841 prim.BaseMask = Convert.ToUInt32(row["BaseMask"]); 846 prim.BaseMask = (uint)(int)row["BaseMask"];
842 // vectors 847 // Vectors
843 prim.OffsetPosition = new Vector3( 848 prim.OffsetPosition = new Vector3(
844 Convert.ToSingle(row["PositionX"]), 849 (float)(double)row["PositionX"],
845 Convert.ToSingle(row["PositionY"]), 850 (float)(double)row["PositionY"],
846 Convert.ToSingle(row["PositionZ"]) 851 (float)(double)row["PositionZ"]
847 ); 852 );
848 prim.GroupPosition = new Vector3( 853 prim.GroupPosition = new Vector3(
849 Convert.ToSingle(row["GroupPositionX"]), 854 (float)(double)row["GroupPositionX"],
850 Convert.ToSingle(row["GroupPositionY"]), 855 (float)(double)row["GroupPositionY"],
851 Convert.ToSingle(row["GroupPositionZ"]) 856 (float)(double)row["GroupPositionZ"]
852 ); 857 );
853 prim.Velocity = new Vector3( 858 prim.Velocity = new Vector3(
854 Convert.ToSingle(row["VelocityX"]), 859 (float)(double)row["VelocityX"],
855 Convert.ToSingle(row["VelocityY"]), 860 (float)(double)row["VelocityY"],
856 Convert.ToSingle(row["VelocityZ"]) 861 (float)(double)row["VelocityZ"]
857 ); 862 );
858 prim.AngularVelocity = new Vector3( 863 prim.AngularVelocity = new Vector3(
859 Convert.ToSingle(row["AngularVelocityX"]), 864 (float)(double)row["AngularVelocityX"],
860 Convert.ToSingle(row["AngularVelocityY"]), 865 (float)(double)row["AngularVelocityY"],
861 Convert.ToSingle(row["AngularVelocityZ"]) 866 (float)(double)row["AngularVelocityZ"]
862 ); 867 );
863 prim.Acceleration = new Vector3( 868 prim.Acceleration = new Vector3(
864 Convert.ToSingle(row["AccelerationX"]), 869 (float)(double)row["AccelerationX"],
865 Convert.ToSingle(row["AccelerationY"]), 870 (float)(double)row["AccelerationY"],
866 Convert.ToSingle(row["AccelerationZ"]) 871 (float)(double)row["AccelerationZ"]
867 ); 872 );
868 // quaternions 873 // quaternions
869 prim.RotationOffset = new Quaternion( 874 prim.RotationOffset = new Quaternion(
870 Convert.ToSingle(row["RotationX"]), 875 (float)(double)row["RotationX"],
871 Convert.ToSingle(row["RotationY"]), 876 (float)(double)row["RotationY"],
872 Convert.ToSingle(row["RotationZ"]), 877 (float)(double)row["RotationZ"],
873 Convert.ToSingle(row["RotationW"]) 878 (float)(double)row["RotationW"]
874 ); 879 );
875 prim.SitTargetPositionLL = new Vector3( 880 prim.SitTargetPositionLL = new Vector3(
876 Convert.ToSingle(row["SitTargetOffsetX"]), 881 (float)(double)row["SitTargetOffsetX"],
877 Convert.ToSingle(row["SitTargetOffsetY"]), 882 (float)(double)row["SitTargetOffsetY"],
878 Convert.ToSingle(row["SitTargetOffsetZ"]) 883 (float)(double)row["SitTargetOffsetZ"]
879 ); 884 );
880 prim.SitTargetOrientationLL = new Quaternion( 885 prim.SitTargetOrientationLL = new Quaternion(
881 Convert.ToSingle(row["SitTargetOrientX"]), 886 (float)(double)row["SitTargetOrientX"],
882 Convert.ToSingle(row["SitTargetOrientY"]), 887 (float)(double)row["SitTargetOrientY"],
883 Convert.ToSingle(row["SitTargetOrientZ"]), 888 (float)(double)row["SitTargetOrientZ"],
884 Convert.ToSingle(row["SitTargetOrientW"]) 889 (float)(double)row["SitTargetOrientW"]
885 ); 890 );
886 891
887 prim.PayPrice[0] = Convert.ToInt32(row["PayPrice"]); 892 prim.PayPrice[0] = (int)row["PayPrice"];
888 prim.PayPrice[1] = Convert.ToInt32(row["PayButton1"]); 893 prim.PayPrice[1] = (int)row["PayButton1"];
889 prim.PayPrice[2] = Convert.ToInt32(row["PayButton2"]); 894 prim.PayPrice[2] = (int)row["PayButton2"];
890 prim.PayPrice[3] = Convert.ToInt32(row["PayButton3"]); 895 prim.PayPrice[3] = (int)row["PayButton3"];
891 prim.PayPrice[4] = Convert.ToInt32(row["PayButton4"]); 896 prim.PayPrice[4] = (int)row["PayButton4"];
892 897
893 prim.Sound = new UUID(row["LoopedSound"].ToString()); 898 prim.Sound = new UUID(row["LoopedSound"].ToString());
894 prim.SoundGain = Convert.ToSingle(row["LoopedSoundGain"]); 899 prim.SoundGain = (float)(double)row["LoopedSoundGain"];
895 prim.SoundFlags = 1; // If it's persisted at all, it's looped 900 prim.SoundFlags = 1; // If it's persisted at all, it's looped
896 901
897 if (!(row["TextureAnimation"] is DBNull)) 902 if (!(row["TextureAnimation"] is DBNull))
898 prim.TextureAnimation = (Byte[])row["TextureAnimation"]; 903 prim.TextureAnimation = (byte[])row["TextureAnimation"];
899 if (!(row["ParticleSystem"] is DBNull)) 904 if (!(row["ParticleSystem"] is DBNull))
900 prim.ParticleSystem = (Byte[])row["ParticleSystem"]; 905 prim.ParticleSystem = (byte[])row["ParticleSystem"];
901 906
902 prim.RotationalVelocity = new Vector3( 907 prim.RotationalVelocity = new Vector3(
903 Convert.ToSingle(row["OmegaX"]), 908 (float)(double)row["OmegaX"],
904 Convert.ToSingle(row["OmegaY"]), 909 (float)(double)row["OmegaY"],
905 Convert.ToSingle(row["OmegaZ"]) 910 (float)(double)row["OmegaZ"]
906 ); 911 );
907 912
908 prim.SetCameraEyeOffset(new Vector3( 913 prim.SetCameraEyeOffset(new Vector3(
909 Convert.ToSingle(row["CameraEyeOffsetX"]), 914 (float)(double)row["CameraEyeOffsetX"],
910 Convert.ToSingle(row["CameraEyeOffsetY"]), 915 (float)(double)row["CameraEyeOffsetY"],
911 Convert.ToSingle(row["CameraEyeOffsetZ"]) 916 (float)(double)row["CameraEyeOffsetZ"]
912 )); 917 ));
913 918
914 prim.SetCameraAtOffset(new Vector3( 919 prim.SetCameraAtOffset(new Vector3(
915 Convert.ToSingle(row["CameraAtOffsetX"]), 920 (float)(double)row["CameraAtOffsetX"],
916 Convert.ToSingle(row["CameraAtOffsetY"]), 921 (float)(double)row["CameraAtOffsetY"],
917 Convert.ToSingle(row["CameraAtOffsetZ"]) 922 (float)(double)row["CameraAtOffsetZ"]
918 )); 923 ));
919 924
920 if (Convert.ToInt16(row["ForceMouselook"]) != 0) 925 if ((sbyte)row["ForceMouselook"] != 0)
921 prim.SetForceMouselook(true); 926 prim.SetForceMouselook(true);
922 927
923 prim.ScriptAccessPin = Convert.ToInt32(row["ScriptAccessPin"]); 928 prim.ScriptAccessPin = (int)row["ScriptAccessPin"];
924 929
925 if (Convert.ToInt16(row["AllowedDrop"]) != 0) 930 if ((sbyte)row["AllowedDrop"] != 0)
926 prim.AllowedDrop = true; 931 prim.AllowedDrop = true;
927 932
928 if (Convert.ToInt16(row["DieAtEdge"]) != 0) 933 if ((sbyte)row["DieAtEdge"] != 0)
929 prim.DIE_AT_EDGE = true; 934 prim.DIE_AT_EDGE = true;
930 935
931 prim.SalePrice = Convert.ToInt32(row["SalePrice"]); 936 prim.SalePrice = (int)row["SalePrice"];
932 prim.ObjectSaleType = unchecked((byte)Convert.ToSByte(row["SaleType"])); 937 prim.ObjectSaleType = unchecked((byte)(sbyte)row["SaleType"]);
933 938
934 prim.Material = unchecked((byte)Convert.ToSByte(row["Material"])); 939 prim.Material = unchecked((byte)(sbyte)row["Material"]);
935 940
936 if (!(row["ClickAction"] is DBNull)) 941 if (!(row["ClickAction"] is DBNull))
937 prim.ClickAction = unchecked((byte)Convert.ToSByte(row["ClickAction"])); 942 prim.ClickAction = unchecked((byte)(sbyte)row["ClickAction"]);
938 943
939 prim.CollisionSound = new UUID(row["CollisionSound"].ToString()); 944 prim.CollisionSound = new UUID(row["CollisionSound"].ToString());
940 prim.CollisionSoundVolume = Convert.ToSingle(row["CollisionSoundVolume"]); 945 prim.CollisionSoundVolume = (float)(double)row["CollisionSoundVolume"];
941 946
942 if (Convert.ToInt16(row["PassTouches"]) != 0) 947 if ((sbyte)row["PassTouches"] != 0)
943 prim.PassTouches = true; 948 prim.PassTouches = true;
944 prim.LinkNum = Convert.ToInt32(row["LinkNumber"]); 949 prim.LinkNum = (int)row["LinkNumber"];
945 950
946 return prim; 951 return prim;
947 } 952 }
diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs
index 03e7a25..1e03d4c 100644
--- a/OpenSim/Framework/IClientAPI.cs
+++ b/OpenSim/Framework/IClientAPI.cs
@@ -448,6 +448,8 @@ namespace OpenSim.Framework
448 public delegate void AvatarInterestUpdate(IClientAPI client, uint wantmask, string wanttext, uint skillsmask, string skillstext, string languages); 448 public delegate void AvatarInterestUpdate(IClientAPI client, uint wantmask, string wanttext, uint skillsmask, string skillstext, string languages);
449 public delegate void PlacesQuery(UUID QueryID, UUID TransactionID, string QueryText, uint QueryFlags, byte Category, string SimName, IClientAPI client); 449 public delegate void PlacesQuery(UUID QueryID, UUID TransactionID, string QueryText, uint QueryFlags, byte Category, string SimName, IClientAPI client);
450 450
451 public delegate void AgentFOV(IClientAPI client, float verticalAngle);
452
451 public delegate double UpdatePriorityHandler(UpdatePriorityData data); 453 public delegate double UpdatePriorityHandler(UpdatePriorityData data);
452 454
453 #endregion 455 #endregion
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
index 2773a5e..b93e905 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
@@ -295,6 +295,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
295 public event MuteListRequest OnMuteListRequest; 295 public event MuteListRequest OnMuteListRequest;
296 public event AvatarInterestUpdate OnAvatarInterestUpdate; 296 public event AvatarInterestUpdate OnAvatarInterestUpdate;
297 public event PlacesQuery OnPlacesQuery; 297 public event PlacesQuery OnPlacesQuery;
298 public event AgentFOV OnAgentFOV;
298 299
299 #endregion Events 300 #endregion Events
300 301
@@ -346,6 +347,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
346 protected ulong m_activeGroupPowers; 347 protected ulong m_activeGroupPowers;
347 protected Dictionary<UUID,ulong> m_groupPowers = new Dictionary<UUID, ulong>(); 348 protected Dictionary<UUID,ulong> m_groupPowers = new Dictionary<UUID, ulong>();
348 protected int m_terrainCheckerCount; 349 protected int m_terrainCheckerCount;
350 protected uint m_agentFOVCounter;
349 351
350 // These numbers are guesses at a decent tradeoff between responsiveness 352 // These numbers are guesses at a decent tradeoff between responsiveness
351 // of the interest list and throughput. Lower is more responsive, higher 353 // of the interest list and throughput. Lower is more responsive, higher
@@ -8871,19 +8873,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
8871 8873
8872 #endregion 8874 #endregion
8873 8875
8876 case PacketType.AgentFOV:
8877 AgentFOVPacket fovPacket = (AgentFOVPacket)Pack;
8874 8878
8875 #region unimplemented handlers 8879 if (fovPacket.FOVBlock.GenCounter > m_agentFOVCounter)
8876 8880 {
8877 case PacketType.StartPingCheck: 8881 m_agentFOVCounter = fovPacket.FOVBlock.GenCounter;
8878 StartPingCheckPacket pingStart = (StartPingCheckPacket)Pack; 8882 AgentFOV handlerAgentFOV = OnAgentFOV;
8879 CompletePingCheckPacket pingComplete = new CompletePingCheckPacket(); 8883 if (handlerAgentFOV != null)
8880 pingComplete.PingID.PingID = pingStart.PingID.PingID; 8884 {
8881 m_udpServer.SendPacket(m_udpClient, pingComplete, ThrottleOutPacketType.Unknown, false); 8885 handlerAgentFOV(this, fovPacket.FOVBlock.VerticalAngle);
8886 }
8887 }
8882 break; 8888 break;
8883 8889
8884 case PacketType.CompletePingCheck: 8890 #region unimplemented handlers
8885 // TODO: Do stats tracking or something with these?
8886 break;
8887 8891
8888 case PacketType.ViewerStats: 8892 case PacketType.ViewerStats:
8889 // TODO: handle this packet 8893 // TODO: handle this packet
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
index 7a403aa..4f3478b 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
@@ -572,6 +572,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
572 for (int i = 0; i < ackPacket.Packets.Length; i++) 572 for (int i = 0; i < ackPacket.Packets.Length; i++)
573 AcknowledgePacket(udpClient, ackPacket.Packets[i].ID, now, packet.Header.Resent); 573 AcknowledgePacket(udpClient, ackPacket.Packets[i].ID, now, packet.Header.Resent);
574 } 574 }
575
576 // We don't need to do anything else with PacketAck packets
577 return;
575 } 578 }
576 579
577 #endregion ACK Receiving 580 #endregion ACK Receiving
@@ -579,20 +582,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
579 #region ACK Sending 582 #region ACK Sending
580 583
581 if (packet.Header.Reliable) 584 if (packet.Header.Reliable)
585 {
582 udpClient.PendingAcks.Enqueue(packet.Header.Sequence); 586 udpClient.PendingAcks.Enqueue(packet.Header.Sequence);
583 587
584 // This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out, 588 // This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out,
585 // add the current received bytes to it, test if 2*MTU bytes have been sent, if so remove 589 // add the current received bytes to it, test if 2*MTU bytes have been sent, if so remove
586 // 2*MTU bytes from the value and send ACKs, and finally add the local value back to 590 // 2*MTU bytes from the value and send ACKs, and finally add the local value back to
587 // client.BytesSinceLastACK. Lockless thread safety 591 // client.BytesSinceLastACK. Lockless thread safety
588 int bytesSinceLastACK = Interlocked.Exchange(ref udpClient.BytesSinceLastACK, 0); 592 int bytesSinceLastACK = Interlocked.Exchange(ref udpClient.BytesSinceLastACK, 0);
589 bytesSinceLastACK += buffer.DataLength; 593 bytesSinceLastACK += buffer.DataLength;
590 if (bytesSinceLastACK > LLUDPServer.MTU * 2) 594 if (bytesSinceLastACK > LLUDPServer.MTU * 2)
591 { 595 {
592 bytesSinceLastACK -= LLUDPServer.MTU * 2; 596 bytesSinceLastACK -= LLUDPServer.MTU * 2;
593 SendAcks(udpClient); 597 SendAcks(udpClient);
598 }
599 Interlocked.Add(ref udpClient.BytesSinceLastACK, bytesSinceLastACK);
594 } 600 }
595 Interlocked.Add(ref udpClient.BytesSinceLastACK, bytesSinceLastACK);
596 601
597 #endregion ACK Sending 602 #endregion ACK Sending
598 603
@@ -612,12 +617,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
612 617
613 #endregion Incoming Packet Accounting 618 #endregion Incoming Packet Accounting
614 619
615 // Don't bother clogging up the queue with PacketAck packets that are already handled here 620 #region Ping Check Handling
616 if (packet.Type != PacketType.PacketAck) 621
622 if (packet.Type == PacketType.StartPingCheck)
617 { 623 {
618 // Inbox insertion 624 // We don't need to do anything else with ping checks
619 packetInbox.Enqueue(new IncomingPacket(udpClient, packet)); 625 StartPingCheckPacket startPing = (StartPingCheckPacket)packet;
626
627 CompletePingCheckPacket completePing = new CompletePingCheckPacket();
628 completePing.PingID.PingID = startPing.PingID.PingID;
629 SendPacket(udpClient, completePing, ThrottleOutPacketType.Unknown, false);
630 return;
620 } 631 }
632 else if (packet.Type == PacketType.CompletePingCheck)
633 {
634 // We don't currently track client ping times
635 return;
636 }
637
638 #endregion Ping Check Handling
639
640 // Inbox insertion
641 packetInbox.Enqueue(new IncomingPacket(udpClient, packet));
621 } 642 }
622 643
623 protected override void PacketSent(UDPPacketBuffer buffer, int bytesSent) 644 protected override void PacketSent(UDPPacketBuffer buffer, int bytesSent)