diff options
author | John Hurliman | 2009-10-18 02:00:42 -0700 |
---|---|---|
committer | John Hurliman | 2009-10-18 02:00:42 -0700 |
commit | b4526a5a6d170e04655990c8edb8e355156a2061 (patch) | |
tree | 457cc8535e9213f6003545a0363f325b9ef9e90b /OpenSim | |
parent | * Committing Nini.dll with the patch from #3773 applied (diff) | |
download | opensim-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.cs | 271 | ||||
-rw-r--r-- | OpenSim/Framework/IClientAPI.cs | 2 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs | 24 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs | 51 |
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) |