Prioritizer.cs 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. using System;
  2. using System.Collections.Generic;
  3. using log4net;
  4. using Nini.Config;
  5. using OpenSim.Framework;
  6. using OpenMetaverse;
  7. using OpenSim.Region.Physics.Manager;
  8. /*
  9. * Steps to add a new prioritization policy:
  10. *
  11. * - Add a new value to the UpdatePrioritizationSchemes enum.
  12. * - Specify this new value in the [InterestManagement] section of your
  13. * OpenSim.ini. The name in the config file must match the enum value name
  14. * (although it is not case sensitive).
  15. * - Write a new GetPriorityBy*() method in this class.
  16. * - Add a new entry to the switch statement in GetUpdatePriority() that calls
  17. * your method.
  18. */
  19. namespace OpenSim.Region.Framework.Scenes
  20. {
  21. public enum UpdatePrioritizationSchemes
  22. {
  23. Time = 0,
  24. Distance = 1,
  25. SimpleAngularDistance = 2,
  26. FrontBack = 3,
  27. BestAvatarResponsiveness = 4,
  28. }
  29. public class Prioritizer
  30. {
  31. private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
  32. /// <summary>
  33. /// This is added to the priority of all child prims, to make sure that the root prim update is sent to the
  34. /// viewer before child prim updates.
  35. /// The adjustment is added to child prims and subtracted from root prims, so the gap ends up
  36. /// being double. We do it both ways so that there is a still a priority delta even if the priority is already
  37. /// double.MinValue or double.MaxValue.
  38. /// </summary>
  39. private double m_childPrimAdjustmentFactor = 0.05;
  40. private Scene m_scene;
  41. public Prioritizer(Scene scene)
  42. {
  43. m_scene = scene;
  44. }
  45. public double GetUpdatePriority(IClientAPI client, ISceneEntity entity)
  46. {
  47. double priority = 0;
  48. if (entity == null)
  49. return 100000;
  50. switch (m_scene.UpdatePrioritizationScheme)
  51. {
  52. case UpdatePrioritizationSchemes.Time:
  53. priority = GetPriorityByTime();
  54. break;
  55. case UpdatePrioritizationSchemes.Distance:
  56. priority = GetPriorityByDistance(client, entity);
  57. break;
  58. case UpdatePrioritizationSchemes.SimpleAngularDistance:
  59. priority = GetPriorityByDistance(client, entity); // TODO: Reimplement SimpleAngularDistance
  60. break;
  61. case UpdatePrioritizationSchemes.FrontBack:
  62. priority = GetPriorityByFrontBack(client, entity);
  63. break;
  64. case UpdatePrioritizationSchemes.BestAvatarResponsiveness:
  65. priority = GetPriorityByBestAvatarResponsiveness(client, entity);
  66. break;
  67. default:
  68. throw new InvalidOperationException("UpdatePrioritizationScheme not defined.");
  69. break;
  70. }
  71. // Adjust priority so that root prims are sent to the viewer first. This is especially important for
  72. // attachments acting as huds, since current viewers fail to display hud child prims if their updates
  73. // arrive before the root one.
  74. if (entity is SceneObjectPart)
  75. {
  76. SceneObjectPart sop = ((SceneObjectPart)entity);
  77. if (sop.IsRoot)
  78. {
  79. if (priority >= double.MinValue + m_childPrimAdjustmentFactor)
  80. priority -= m_childPrimAdjustmentFactor;
  81. }
  82. else
  83. {
  84. if (priority <= double.MaxValue - m_childPrimAdjustmentFactor)
  85. priority += m_childPrimAdjustmentFactor;
  86. }
  87. }
  88. return priority;
  89. }
  90. private double GetPriorityByTime()
  91. {
  92. return DateTime.UtcNow.ToOADate();
  93. }
  94. private double GetPriorityByDistance(IClientAPI client, ISceneEntity entity)
  95. {
  96. ScenePresence presence = m_scene.GetScenePresence(client.AgentId);
  97. if (presence != null)
  98. {
  99. // If this is an update for our own avatar give it the highest priority
  100. if (presence == entity)
  101. return 0.0;
  102. // Use the camera position for local agents and avatar position for remote agents
  103. Vector3 presencePos = (presence.IsChildAgent) ?
  104. presence.AbsolutePosition :
  105. presence.CameraPosition;
  106. // Use group position for child prims
  107. Vector3 entityPos;
  108. if (entity is SceneObjectPart)
  109. entityPos = m_scene.GetGroupByPrim(entity.LocalId).AbsolutePosition;
  110. else
  111. entityPos = entity.AbsolutePosition;
  112. return Vector3.DistanceSquared(presencePos, entityPos);
  113. }
  114. return double.NaN;
  115. }
  116. private double GetPriorityByFrontBack(IClientAPI client, ISceneEntity entity)
  117. {
  118. ScenePresence presence = m_scene.GetScenePresence(client.AgentId);
  119. if (presence != null)
  120. {
  121. // If this is an update for our own avatar give it the highest priority
  122. if (presence == entity)
  123. return 0.0;
  124. // Use group position for child prims
  125. Vector3 entityPos = entity.AbsolutePosition;
  126. if (entity is SceneObjectPart)
  127. entityPos = m_scene.GetGroupByPrim(entity.LocalId).AbsolutePosition;
  128. else
  129. entityPos = entity.AbsolutePosition;
  130. if (!presence.IsChildAgent)
  131. {
  132. // Root agent. Use distance from camera and a priority decrease for objects behind us
  133. Vector3 camPosition = presence.CameraPosition;
  134. Vector3 camAtAxis = presence.CameraAtAxis;
  135. // Distance
  136. double priority = Vector3.DistanceSquared(camPosition, entityPos);
  137. // Plane equation
  138. float d = -Vector3.Dot(camPosition, camAtAxis);
  139. float p = Vector3.Dot(camAtAxis, entityPos) + d;
  140. if (p < 0.0f) priority *= 2.0;
  141. return priority;
  142. }
  143. else
  144. {
  145. // Child agent. Use the normal distance method
  146. Vector3 presencePos = presence.AbsolutePosition;
  147. return Vector3.DistanceSquared(presencePos, entityPos);
  148. }
  149. }
  150. return double.NaN;
  151. }
  152. private double GetPriorityByBestAvatarResponsiveness(IClientAPI client, ISceneEntity entity)
  153. {
  154. ScenePresence presence = m_scene.GetScenePresence(client.AgentId);
  155. if (presence != null)
  156. {
  157. // If this is an update for our own avatar give it the highest priority
  158. if (presence == entity)
  159. return 0.0;
  160. // Use group position for child prims
  161. Vector3 entityPos = entity.AbsolutePosition;
  162. if (entity is SceneObjectPart)
  163. entityPos = m_scene.GetGroupByPrim(entity.LocalId).AbsolutePosition;
  164. else
  165. entityPos = entity.AbsolutePosition;
  166. if (!presence.IsChildAgent)
  167. {
  168. if (entity is ScenePresence)
  169. return 1.0;
  170. // Root agent. Use distance from camera and a priority decrease for objects behind us
  171. Vector3 camPosition = presence.CameraPosition;
  172. Vector3 camAtAxis = presence.CameraAtAxis;
  173. // Distance
  174. double priority = Vector3.DistanceSquared(camPosition, entityPos);
  175. // Plane equation
  176. float d = -Vector3.Dot(camPosition, camAtAxis);
  177. float p = Vector3.Dot(camAtAxis, entityPos) + d;
  178. if (p < 0.0f) priority *= 2.0;
  179. if (entity is SceneObjectPart)
  180. {
  181. PhysicsActor physActor = ((SceneObjectPart)entity).ParentGroup.RootPart.PhysActor;
  182. if (physActor == null || !physActor.IsPhysical)
  183. priority += 100;
  184. if (((SceneObjectPart)entity).ParentGroup.RootPart.IsAttachment)
  185. priority = 1.0;
  186. }
  187. return priority;
  188. }
  189. else
  190. {
  191. // Child agent. Use the normal distance method
  192. Vector3 presencePos = presence.AbsolutePosition;
  193. return Vector3.DistanceSquared(presencePos, entityPos);
  194. }
  195. }
  196. return double.NaN;
  197. }
  198. }
  199. }