aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim')
-rwxr-xr-xOpenSim/Framework/Monitoring/SimExtraStatsCollector.cs19
-rwxr-xr-xOpenSim/Region/Framework/Scenes/Scene.cs11370
-rwxr-xr-xOpenSim/Region/Framework/Scenes/SimStatsReporter.cs52
3 files changed, 5733 insertions, 5708 deletions
diff --git a/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs b/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs
index 98fa65a..432efdb 100755
--- a/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs
+++ b/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs
@@ -72,6 +72,7 @@ namespace OpenSim.Framework.Monitoring
72 private volatile float pendingUploads; 72 private volatile float pendingUploads;
73 private volatile float activeScripts; 73 private volatile float activeScripts;
74 private volatile float scriptLinesPerSecond; 74 private volatile float scriptLinesPerSecond;
75 private volatile float m_frameDilation;
75 private volatile float m_usersLoggingIn; 76 private volatile float m_usersLoggingIn;
76 private volatile float m_totalGeoPrims; 77 private volatile float m_totalGeoPrims;
77 private volatile float m_totalMeshes; 78 private volatile float m_totalMeshes;
@@ -257,7 +258,7 @@ namespace OpenSim.Framework.Monitoring
257 258
258 // For an unknown reason the original designers decided not to 259 // For an unknown reason the original designers decided not to
259 // include the spare MS statistic inside of this class, this is 260 // include the spare MS statistic inside of this class, this is
260 // located inside the StatsBlock at location 21 thus it is skipped 261 // located inside the StatsBlock at location 21, thus it is skipped
261 timeDilation = stats.StatsBlock[0].StatValue; 262 timeDilation = stats.StatsBlock[0].StatValue;
262 simFps = stats.StatsBlock[1].StatValue; 263 simFps = stats.StatsBlock[1].StatValue;
263 physicsFps = stats.StatsBlock[2].StatValue; 264 physicsFps = stats.StatsBlock[2].StatValue;
@@ -279,10 +280,11 @@ namespace OpenSim.Framework.Monitoring
279 pendingUploads = stats.StatsBlock[18].StatValue; 280 pendingUploads = stats.StatsBlock[18].StatValue;
280 activeScripts = stats.StatsBlock[19].StatValue; 281 activeScripts = stats.StatsBlock[19].StatValue;
281 scriptLinesPerSecond = stats.StatsBlock[20].StatValue; 282 scriptLinesPerSecond = stats.StatsBlock[20].StatValue;
282 m_usersLoggingIn = stats.StatsBlock[22].StatValue; 283 m_frameDilation = stats.StatsBlock[22].StatValue;
283 m_totalGeoPrims = stats.StatsBlock[23].StatValue; 284 m_usersLoggingIn = stats.StatsBlock[23].StatValue;
284 m_totalMeshes = stats.StatsBlock[24].StatValue; 285 m_totalGeoPrims = stats.StatsBlock[24].StatValue;
285 m_inUseThreads = stats.StatsBlock[25].StatValue; 286 m_totalMeshes = stats.StatsBlock[25].StatValue;
287 m_inUseThreads = stats.StatsBlock[26].StatValue;
286 } 288 }
287 289
288 /// <summary> 290 /// <summary>
@@ -474,14 +476,13 @@ Asset service request failures: {3}" + Environment.NewLine,
474 args["Uptime"] = OSD.FromString (uptime); 476 args["Uptime"] = OSD.FromString (uptime);
475 args["Version"] = OSD.FromString (version); 477 args["Version"] = OSD.FromString (version);
476 478
479 args["FrameDilatn"] = OSD.FromString(String.Format("{0:0.##}", m_frameDilation));
477 args["Logging in Users"] = OSD.FromString(String.Format("{0:0.##}", 480 args["Logging in Users"] = OSD.FromString(String.Format("{0:0.##}",
478 m_usersLoggingIn)); 481 m_usersLoggingIn));
479 args["GeoPrims"] = OSD.FromString(String.Format("{0:0.##}", 482 args["GeoPrims"] = OSD.FromString(String.Format("{0:0.##}",
480 m_totalGeoPrims)); 483 m_totalGeoPrims));
481 args["Mesh Objects"] = OSD.FromString(String.Format("{0:0.##}", 484 args["Mesh Objects"] = OSD.FromString(String.Format("{0:0.##}",
482 m_totalMeshes)); 485 m_totalMeshes));
483 args["Polygon Count"] = OSD.FromString(String.Format("{0:0.##}", 0));
484 args["Texture Count"] = OSD.FromString(String.Format("{0:0.##}", 0));
485 args["XEngine Thread Count"] = OSD.FromString(String.Format("{0:0.##}", 486 args["XEngine Thread Count"] = OSD.FromString(String.Format("{0:0.##}",
486 m_inUseThreads)); 487 m_inUseThreads));
487 args["Util Thread Count"] = OSD.FromString(String.Format("{0:0.##}", 488 args["Util Thread Count"] = OSD.FromString(String.Format("{0:0.##}",
@@ -489,7 +490,7 @@ Asset service request failures: {3}" + Environment.NewLine,
489 args["System Thread Count"] = OSD.FromString(String.Format( 490 args["System Thread Count"] = OSD.FromString(String.Format(
490 "{0:0.##}", numberThreadsRunning)); 491 "{0:0.##}", numberThreadsRunning));
491 args["ProcMem"] = OSD.FromString(String.Format("{0:#,###,###.##}", 492 args["ProcMem"] = OSD.FromString(String.Format("{0:#,###,###.##}",
492 memUsage)); 493 memUsage));
493 494
494 return args; 495 return args;
495 } 496 }
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index 052567f..31e4ee0 100755
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -48,5960 +48,5982 @@ using OpenSim.Region.Framework.Interfaces;
48using OpenSim.Region.Framework.Scenes.Scripting; 48using OpenSim.Region.Framework.Scenes.Scripting;
49using OpenSim.Region.Framework.Scenes.Serialization; 49using OpenSim.Region.Framework.Scenes.Serialization;
50using OpenSim.Region.Physics.Manager; 50using OpenSim.Region.Physics.Manager;
51using Timer=System.Timers.Timer; 51using Timer = System.Timers.Timer;
52using TPFlags = OpenSim.Framework.Constants.TeleportFlags; 52using TPFlags = OpenSim.Framework.Constants.TeleportFlags;
53using GridRegion = OpenSim.Services.Interfaces.GridRegion; 53using GridRegion = OpenSim.Services.Interfaces.GridRegion;
54using PermissionMask = OpenSim.Framework.PermissionMask; 54using PermissionMask = OpenSim.Framework.PermissionMask;
55 55
56namespace OpenSim.Region.Framework.Scenes 56namespace OpenSim.Region.Framework.Scenes
57{ 57{
58 public delegate bool FilterAvatarList(ScenePresence avatar); 58 public delegate bool FilterAvatarList(ScenePresence avatar);
59 59
60 public partial class Scene : SceneBase 60 public partial class Scene : SceneBase
61 { 61 {
62 private const long DEFAULT_MIN_TIME_FOR_PERSISTENCE = 60L; 62 private const long DEFAULT_MIN_TIME_FOR_PERSISTENCE = 60L;
63 private const long DEFAULT_MAX_TIME_FOR_PERSISTENCE = 600L; 63 private const long DEFAULT_MAX_TIME_FOR_PERSISTENCE = 600L;
64 64
65 public delegate void SynchronizeSceneHandler(Scene scene); 65 public delegate void SynchronizeSceneHandler(Scene scene);
66 66
67 #region Fields 67 #region Fields
68 68
69 public bool EmergencyMonitoring = false; 69 public bool EmergencyMonitoring = false;
70 70
71 /// <summary> 71 /// <summary>
72 /// Show debug information about animations. 72 /// Show debug information about animations.
73 /// </summary> 73 /// </summary>
74 public bool DebugAnimations { get; set; } 74 public bool DebugAnimations { get; set; }
75 75
76 /// <summary> 76 /// <summary>
77 /// Show debug information about teleports. 77 /// Show debug information about teleports.
78 /// </summary> 78 /// </summary>
79 public bool DebugTeleporting { get; set; } 79 public bool DebugTeleporting { get; set; }
80 80
81 /// <summary> 81 /// <summary>
82 /// Show debug information about the scene loop. 82 /// Show debug information about the scene loop.
83 /// </summary> 83 /// </summary>
84 public bool DebugUpdates { get; set; } 84 public bool DebugUpdates { get; set; }
85 85
86 /// <summary> 86 /// <summary>
87 /// If true then the scene is saved to persistent storage periodically, every m_update_backup frames and 87 /// If true then the scene is saved to persistent storage periodically, every m_update_backup frames and
88 /// if objects meet required conditions (m_dontPersistBefore and m_dontPersistAfter). 88 /// if objects meet required conditions (m_dontPersistBefore and m_dontPersistAfter).
89 /// </summary> 89 /// </summary>
90 /// <remarks> 90 /// <remarks>
91 /// Even if false, the scene will still be saved on clean shutdown. 91 /// Even if false, the scene will still be saved on clean shutdown.
92 /// FIXME: Currently, setting this to false will mean that objects are not periodically returned from parcels. 92 /// FIXME: Currently, setting this to false will mean that objects are not periodically returned from parcels.
93 /// This needs to be fixed. 93 /// This needs to be fixed.
94 /// </remarks> 94 /// </remarks>
95 public bool PeriodicBackup { get; set; } 95 public bool PeriodicBackup { get; set; }
96 96
97 /// <summary> 97 /// <summary>
98 /// If false then the scene is never saved to persistence storage even if PeriodicBackup == true and even 98 /// If false then the scene is never saved to persistence storage even if PeriodicBackup == true and even
99 /// if the scene is being shut down for the final time. 99 /// if the scene is being shut down for the final time.
100 /// </summary> 100 /// </summary>
101 public bool UseBackup { get; set; } 101 public bool UseBackup { get; set; }
102 102
103 /// <summary> 103 /// <summary>
104 /// If false then physical objects are disabled, though collisions will continue as normal. 104 /// If false then physical objects are disabled, though collisions will continue as normal.
105 /// </summary> 105 /// </summary>
106 public bool PhysicsEnabled 106 public bool PhysicsEnabled
107 { 107 {
108 get 108 get
109 { 109 {
110 return m_physicsEnabled; 110 return m_physicsEnabled;
111 } 111 }
112 112
113 set 113 set
114 { 114 {
115 m_physicsEnabled = value; 115 m_physicsEnabled = value;
116
117 if (PhysicsScene != null)
118 {
119 IPhysicsParameters physScene = PhysicsScene as IPhysicsParameters;
120
121 if (physScene != null)
122 physScene.SetPhysicsParameter(
123 "Active", m_physicsEnabled.ToString(), PhysParameterEntry.APPLY_TO_NONE);
124 }
125 }
126 }
127
128 private bool m_physicsEnabled;
129
130 /// <summary>
131 /// If false then scripts are not enabled on the smiulator
132 /// </summary>
133 public bool ScriptsEnabled
134 {
135 get { return m_scripts_enabled; }
136 set
137 {
138 if (m_scripts_enabled != value)
139 {
140 if (!value)
141 {
142 m_log.Info("Stopping all Scripts in Scene");
143
144 EntityBase[] entities = Entities.GetEntities();
145 foreach (EntityBase ent in entities)
146 {
147 if (ent is SceneObjectGroup)
148 ((SceneObjectGroup)ent).RemoveScriptInstances(false);
149 }
150 }
151 else
152 {
153 m_log.Info("Starting all Scripts in Scene");
154
155 EntityBase[] entities = Entities.GetEntities();
156 foreach (EntityBase ent in entities)
157 {
158 if (ent is SceneObjectGroup)
159 {
160 SceneObjectGroup sog = (SceneObjectGroup)ent;
161 sog.CreateScriptInstances(0, false, DefaultScriptEngine, 0);
162 sog.ResumeScripts();
163 }
164 }
165 }
166
167 m_scripts_enabled = value;
168 }
169 }
170 }
171 private bool m_scripts_enabled;
172
173 public SynchronizeSceneHandler SynchronizeScene;
174
175 /// <summary>
176 /// Used to prevent simultaneous calls to code that adds and removes agents.
177 /// </summary>
178 private object m_removeClientLock = new object();
179
180 /// <summary>
181 /// Statistical information for this scene.
182 /// </summary>
183 public SimStatsReporter StatsReporter { get; private set; }
184
185 /// <summary>
186 /// Controls whether physics can be applied to prims. Even if false, prims still have entries in a
187 /// PhysicsScene in order to perform collision detection
188 /// </summary>
189 public bool PhysicalPrims { get; private set; }
190
191 /// <summary>
192 /// Controls whether prims can be collided with.
193 /// </summary>
194 /// <remarks>
195 /// If this is set to false then prims cannot be subject to physics either.
196 /// </summary>
197 public bool CollidablePrims { get; private set; }
198
199 /// <summary>
200 /// Minimum value of the size of a non-physical prim in each axis
201 /// </summary>
202 public float m_minNonphys = 0.001f;
203
204 /// <summary>
205 /// Maximum value of the size of a non-physical prim in each axis
206 /// </summary>
207 public float m_maxNonphys = 256;
208
209 /// <summary>
210 /// Minimum value of the size of a physical prim in each axis
211 /// </summary>
212 public float m_minPhys = 0.01f;
213
214 /// <summary>
215 /// Maximum value of the size of a physical prim in each axis
216 /// </summary>
217 public float m_maxPhys = 64;
218
219 /// <summary>
220 /// Max prims an object will hold
221 /// </summary>
222 public int m_linksetCapacity = 0;
223
224 public bool m_clampPrimSize;
225 public bool m_trustBinaries;
226 public bool m_allowScriptCrossings = true;
227
228 /// <summary>
229 /// Can avatars cross from and to this region?
230 /// </summary>
231 public bool AllowAvatarCrossing { get; set; }
232
233 public bool m_useFlySlow;
234 public bool m_useTrashOnDelete = true;
235
236 /// <summary>
237 /// Temporarily setting to trigger appearance resends at 60 second intervals.
238 /// </summary>
239 public bool SendPeriodicAppearanceUpdates { get; set; }
240
241 /// <summary>
242 /// How much a root agent has to change position before updates are sent to viewers.
243 /// </summary>
244 public float RootPositionUpdateTolerance { get; set; }
245
246 /// <summary>
247 /// How much a root agent has to rotate before updates are sent to viewers.
248 /// </summary>
249 public float RootRotationUpdateTolerance { get; set; }
250
251 /// <summary>
252 /// How much a root agent has to change velocity before updates are sent to viewers.
253 /// </summary>
254 public float RootVelocityUpdateTolerance { get; set; }
255
256 /// <summary>
257 /// If greater than 1, we only send terse updates to other root agents on every n updates.
258 /// </summary>
259 public int RootTerseUpdatePeriod { get; set; }
260
261 /// <summary>
262 /// If greater than 1, we only send terse updates to child agents on every n updates.
263 /// </summary>
264 public int ChildTerseUpdatePeriod { get; set; }
265
266 protected float m_defaultDrawDistance = 255.0f;
267 public float DefaultDrawDistance
268 {
269 // get { return m_defaultDrawDistance; }
270 get {
271 if (RegionInfo != null)
272 {
273 float largestDimension = Math.Max(RegionInfo.RegionSizeX, RegionInfo.RegionSizeY);
274 m_defaultDrawDistance = Math.Max(m_defaultDrawDistance, largestDimension);
275
276 }
277 return m_defaultDrawDistance;
278 }
279 }
280
281 private List<string> m_AllowedViewers = new List<string>();
282 private List<string> m_BannedViewers = new List<string>();
283
284 // TODO: need to figure out how allow client agents but deny
285 // root agents when ACL denies access to root agent
286 public bool m_strictAccessControl = true;
287
288 public int MaxUndoCount { get; set; }
289
290 public bool SeeIntoRegion { get; set; }
291
292 // Using this for RegionReady module to prevent LoginsDisabled from changing under our feet;
293 public bool LoginLock = false;
294
295 public bool StartDisabled = false;
296 public bool LoadingPrims;
297 public IXfer XferManager;
298
299 // the minimum time that must elapse before a changed object will be considered for persisted
300 public long m_dontPersistBefore = DEFAULT_MIN_TIME_FOR_PERSISTENCE * 10000000L;
301 // the maximum time that must elapse before a changed object will be considered for persisted
302 public long m_persistAfter = DEFAULT_MAX_TIME_FOR_PERSISTENCE * 10000000L;
303
304 protected int m_splitRegionID;
305 protected Timer m_restartWaitTimer = new Timer();
306 protected List<RegionInfo> m_regionRestartNotifyList = new List<RegionInfo>();
307 protected List<RegionInfo> m_neighbours = new List<RegionInfo>();
308 protected string m_simulatorVersion = "OpenSimulator Server";
309 protected AgentCircuitManager m_authenticateHandler;
310 protected SceneCommunicationService m_sceneGridService;
311
312 protected ISimulationDataService m_SimulationDataService;
313 protected IEstateDataService m_EstateDataService;
314 protected IAssetService m_AssetService;
315 protected IAuthorizationService m_AuthorizationService;
316 protected IInventoryService m_InventoryService;
317 protected IGridService m_GridService;
318 protected ILibraryService m_LibraryService;
319 protected ISimulationService m_simulationService;
320 protected IAuthenticationService m_AuthenticationService;
321 protected IPresenceService m_PresenceService;
322 protected IUserAccountService m_UserAccountService;
323 protected IAvatarService m_AvatarService;
324 protected IGridUserService m_GridUserService;
325
326 protected IXMLRPC m_xmlrpcModule;
327 protected IWorldComm m_worldCommModule;
328 protected IAvatarFactoryModule m_AvatarFactory;
329 protected IConfigSource m_config;
330 protected IRegionSerialiserModule m_serialiser;
331 protected IDialogModule m_dialogModule;
332 protected ICapabilitiesModule m_capsModule;
333 protected IGroupsModule m_groupsModule;
334
335 private Dictionary<string, string> m_extraSettings;
336
337 /// <summary>
338 /// If true then the next time the scene loop is activated, updates will be performed by firing of a timer
339 /// rather than on a single thread that sleeps.
340 /// </summary>
341 public bool UpdateOnTimer { get; set; }
342
343 /// <summary>
344 /// Only used if we are updating scene on a timer rather than sleeping a thread.
345 /// </summary>
346 private Timer m_sceneUpdateTimer;
347
348 /// <summary>
349 /// Current scene frame number
350 /// </summary>
351 public uint Frame
352 {
353 get;
354 protected set;
355 }
356
357 /// <summary>
358 /// Current maintenance run number
359 /// </summary>
360 public uint MaintenanceRun { get; private set; }
361
362 /// <summary>
363 /// The minimum length of time in milliseconds that will be taken for a scene frame. If the frame takes less time then we
364 /// will sleep for the remaining period.
365 /// </summary>
366 /// <remarks>
367 /// One can tweak this number to experiment. One current effect of reducing it is to make avatar animations
368 /// occur too quickly (viewer 1) or with even more slide (viewer 2).
369 /// </remarks>
370 public int MinFrameTicks
371 {
372 get { return m_minFrameTicks; }
373 private set
374 {
375 m_minFrameTicks = value;
376 MinFrameSeconds = (float)m_minFrameTicks / 1000;
377 }
378 }
379 private int m_minFrameTicks;
380
381 /// <summary>
382 /// The minimum length of time in seconds that will be taken for a scene frame.
383 /// </summary>
384 /// <remarks>
385 /// Always derived from MinFrameTicks.
386 /// </remarks>
387 public float MinFrameSeconds { get; private set; }
388
389 /// <summary>
390 /// The minimum length of time in milliseconds that will be taken for a scene frame. If the frame takes less time then we
391 /// will sleep for the remaining period.
392 /// </summary>
393 /// <remarks>
394 /// One can tweak this number to experiment. One current effect of reducing it is to make avatar animations
395 /// occur too quickly (viewer 1) or with even more slide (viewer 2).
396 /// </remarks>
397 public int MinMaintenanceTicks { get; set; }
398
399 private int m_update_physics = 1;
400 private int m_update_entitymovement = 1;
401 private int m_update_objects = 1;
402 private int m_update_presences = 1; // Update scene presence movements
403 private int m_update_events = 1;
404 private int m_update_backup = 200;
405 private int m_update_terrain = 50;
406// private int m_update_land = 1;
407 private int m_update_coarse_locations = 50;
408 private int m_update_temp_cleaning = 180;
409
410 private int agentMS;
411 private int frameMS;
412 private int physicsMS2;
413 private int physicsMS;
414 private int otherMS;
415 private int tempOnRezMS;
416 private int eventMS;
417 private int backupMS;
418 private int terrainMS;
419 private int landMS;
420 private int spareMS;
421
422 /// <summary>
423 /// Tick at which the last frame was processed.
424 /// </summary>
425 private int m_lastFrameTick;
426
427 /// <summary>
428 /// Tick at which the last maintenance run occurred.
429 /// </summary>
430 private int m_lastMaintenanceTick;
431
432 /// <summary>
433 /// Signals whether temporary objects are currently being cleaned up. Needed because this is launched
434 /// asynchronously from the update loop.
435 /// </summary>
436 private bool m_cleaningTemps = false;
437
438 /// <summary>
439 /// Used to control main scene thread looping time when not updating via timer.
440 /// </summary>
441 private ManualResetEvent m_updateWaitEvent = new ManualResetEvent(false);
442
443 /// <summary>
444 /// Used to control maintenance thread runs.
445 /// </summary>
446 private ManualResetEvent m_maintenanceWaitEvent = new ManualResetEvent(false);
447
448 // TODO: Possibly stop other classes being able to manipulate this directly.
449 private SceneGraph m_sceneGraph;
450 private readonly Timer m_restartTimer = new Timer(15000); // Wait before firing
451 private volatile bool m_backingup;
452 private Dictionary<UUID, ReturnInfo> m_returns = new Dictionary<UUID, ReturnInfo>();
453 private Dictionary<UUID, SceneObjectGroup> m_groupsWithTargets = new Dictionary<UUID, SceneObjectGroup>();
454
455 private string m_defaultScriptEngine;
456
457 /// <summary>
458 /// Tick at which the last login occurred.
459 /// </summary>
460 private int m_LastLogin;
461
462 /// <summary>
463 /// Thread that runs the scene loop.
464 /// </summary>
465 private Thread m_heartbeatThread;
466
467 /// <summary>
468 /// True if these scene is in the process of shutting down or is shutdown.
469 /// </summary>
470 public bool ShuttingDown
471 {
472 get { return m_shuttingDown; }
473 }
474 private volatile bool m_shuttingDown;
475
476 /// <summary>
477 /// Is the scene active?
478 /// </summary>
479 /// <remarks>
480 /// If false, maintenance and update loops are not being run, though after setting to false update may still
481 /// be active for a period (and IsRunning will still be true). Updates can still be triggered manually if
482 /// the scene is not active.
483 /// </remarks>
484 public bool Active
485 {
486 get { return m_active; }
487 set
488 {
489 if (value)
490 {
491 if (!m_active)
492 Start(false);
493 }
494 else
495 {
496 // This appears assymetric with Start() above but is not - setting m_active = false stops the loops
497 // XXX: Possibly this should be in an explicit Stop() method for symmetry.
498 m_active = false;
499 }
500 }
501 }
502 private volatile bool m_active;
503
504 /// <summary>
505 /// If true then updates are running. This may be true for a short period after a scene is de-activated.
506 /// </summary>
507 public bool IsRunning { get { return m_isRunning; } }
508 private volatile bool m_isRunning;
509
510 private Timer m_mapGenerationTimer = new Timer();
511 private bool m_generateMaptiles;
512
513 #endregion Fields
514
515 #region Properties
516
517 /* Used by the loadbalancer plugin on GForge */
518 public int SplitRegionID
519 {
520 get { return m_splitRegionID; }
521 set { m_splitRegionID = value; }
522 }
523
524 public new float TimeDilation
525 {
526 get { return m_sceneGraph.PhysicsScene.TimeDilation; }
527 }
528
529 public void setThreadCount(int inUseThreads)
530 {
531 // Just pass the thread count information on its way as the Scene
532 // does not require the value for anything at this time
533 StatsReporter.SetThreadCount(inUseThreads);
534 }
535
536 public SceneCommunicationService SceneGridService
537 {
538 get { return m_sceneGridService; }
539 }
540
541 public ISimulationDataService SimulationDataService
542 {
543 get
544 {
545 if (m_SimulationDataService == null)
546 {
547 m_SimulationDataService = RequestModuleInterface<ISimulationDataService>();
548
549 if (m_SimulationDataService == null)
550 {
551 throw new Exception("No ISimulationDataService available.");
552 }
553 }
554
555 return m_SimulationDataService;
556 }
557 }
558
559 public IEstateDataService EstateDataService
560 {
561 get
562 {
563 if (m_EstateDataService == null)
564 {
565 m_EstateDataService = RequestModuleInterface<IEstateDataService>();
566
567 if (m_EstateDataService == null)
568 {
569 throw new Exception("No IEstateDataService available.");
570 }
571 }
572
573 return m_EstateDataService;
574 }
575 }
576
577 public IAssetService AssetService
578 {
579 get
580 {
581 if (m_AssetService == null)
582 {
583 m_AssetService = RequestModuleInterface<IAssetService>();
584
585 if (m_AssetService == null)
586 {
587 throw new Exception("No IAssetService available.");
588 }
589 }
590 116
591 return m_AssetService; 117 if (PhysicsScene != null)
118 {
119 IPhysicsParameters physScene = PhysicsScene as IPhysicsParameters;
120
121 if (physScene != null)
122 physScene.SetPhysicsParameter(
123 "Active", m_physicsEnabled.ToString(), PhysParameterEntry.APPLY_TO_NONE);
124 }
125 }
126 }
127
128 private bool m_physicsEnabled;
129
130 /// <summary>
131 /// If false then scripts are not enabled on the smiulator
132 /// </summary>
133 public bool ScriptsEnabled
134 {
135 get { return m_scripts_enabled; }
136 set
137 {
138 if (m_scripts_enabled != value)
139 {
140 if (!value)
141 {
142 m_log.Info("Stopping all Scripts in Scene");
143
144 EntityBase[] entities = Entities.GetEntities();
145 foreach (EntityBase ent in entities)
146 {
147 if (ent is SceneObjectGroup)
148 ((SceneObjectGroup)ent).RemoveScriptInstances(false);
149 }
150 }
151 else
152 {
153 m_log.Info("Starting all Scripts in Scene");
154
155 EntityBase[] entities = Entities.GetEntities();
156 foreach (EntityBase ent in entities)
157 {
158 if (ent is SceneObjectGroup)
159 {
160 SceneObjectGroup sog = (SceneObjectGroup)ent;
161 sog.CreateScriptInstances(0, false, DefaultScriptEngine, 0);
162 sog.ResumeScripts();
163 }
164 }
165 }
166
167 m_scripts_enabled = value;
168 }
169 }
170 }
171 private bool m_scripts_enabled;
172
173 public SynchronizeSceneHandler SynchronizeScene;
174
175 /// <summary>
176 /// Used to prevent simultaneous calls to code that adds and removes agents.
177 /// </summary>
178 private object m_removeClientLock = new object();
179
180 /// <summary>
181 /// Statistical information for this scene.
182 /// </summary>
183 public SimStatsReporter StatsReporter { get; private set; }
184
185 /// <summary>
186 /// Controls whether physics can be applied to prims. Even if false, prims still have entries in a
187 /// PhysicsScene in order to perform collision detection
188 /// </summary>
189 public bool PhysicalPrims { get; private set; }
190
191 /// <summary>
192 /// Controls whether prims can be collided with.
193 /// </summary>
194 /// <remarks>
195 /// If this is set to false then prims cannot be subject to physics either.
196 /// </summary>
197 public bool CollidablePrims { get; private set; }
198
199 /// <summary>
200 /// Minimum value of the size of a non-physical prim in each axis
201 /// </summary>
202 public float m_minNonphys = 0.001f;
203
204 /// <summary>
205 /// Maximum value of the size of a non-physical prim in each axis
206 /// </summary>
207 public float m_maxNonphys = 256;
208
209 /// <summary>
210 /// Minimum value of the size of a physical prim in each axis
211 /// </summary>
212 public float m_minPhys = 0.01f;
213
214 /// <summary>
215 /// Maximum value of the size of a physical prim in each axis
216 /// </summary>
217 public float m_maxPhys = 64;
218
219 /// <summary>
220 /// Max prims an object will hold
221 /// </summary>
222 public int m_linksetCapacity = 0;
223
224 public bool m_clampPrimSize;
225 public bool m_trustBinaries;
226 public bool m_allowScriptCrossings = true;
227
228 /// <summary>
229 /// Can avatars cross from and to this region?
230 /// </summary>
231 public bool AllowAvatarCrossing { get; set; }
232
233 public bool m_useFlySlow;
234 public bool m_useTrashOnDelete = true;
235
236 /// <summary>
237 /// Temporarily setting to trigger appearance resends at 60 second intervals.
238 /// </summary>
239 public bool SendPeriodicAppearanceUpdates { get; set; }
240
241 /// <summary>
242 /// How much a root agent has to change position before updates are sent to viewers.
243 /// </summary>
244 public float RootPositionUpdateTolerance { get; set; }
245
246 /// <summary>
247 /// How much a root agent has to rotate before updates are sent to viewers.
248 /// </summary>
249 public float RootRotationUpdateTolerance { get; set; }
250
251 /// <summary>
252 /// How much a root agent has to change velocity before updates are sent to viewers.
253 /// </summary>
254 public float RootVelocityUpdateTolerance { get; set; }
255
256 /// <summary>
257 /// If greater than 1, we only send terse updates to other root agents on every n updates.
258 /// </summary>
259 public int RootTerseUpdatePeriod { get; set; }
260
261 /// <summary>
262 /// If greater than 1, we only send terse updates to child agents on every n updates.
263 /// </summary>
264 public int ChildTerseUpdatePeriod { get; set; }
265
266 protected float m_defaultDrawDistance = 255.0f;
267 public float DefaultDrawDistance
268 {
269 // get { return m_defaultDrawDistance; }
270 get
271 {
272 if (RegionInfo != null)
273 {
274 float largestDimension = Math.Max(RegionInfo.RegionSizeX, RegionInfo.RegionSizeY);
275 m_defaultDrawDistance = Math.Max(m_defaultDrawDistance, largestDimension);
276
277 }
278 return m_defaultDrawDistance;
279 }
280 }
281
282 private List<string> m_AllowedViewers = new List<string>();
283 private List<string> m_BannedViewers = new List<string>();
284
285 // TODO: need to figure out how allow client agents but deny
286 // root agents when ACL denies access to root agent
287 public bool m_strictAccessControl = true;
288
289 public int MaxUndoCount { get; set; }
290
291 public bool SeeIntoRegion { get; set; }
292
293 // Using this for RegionReady module to prevent LoginsDisabled from changing under our feet;
294 public bool LoginLock = false;
295
296 public bool StartDisabled = false;
297 public bool LoadingPrims;
298 public IXfer XferManager;
299
300 // the minimum time that must elapse before a changed object will be considered for persisted
301 public long m_dontPersistBefore = DEFAULT_MIN_TIME_FOR_PERSISTENCE * 10000000L;
302 // the maximum time that must elapse before a changed object will be considered for persisted
303 public long m_persistAfter = DEFAULT_MAX_TIME_FOR_PERSISTENCE * 10000000L;
304
305 protected int m_splitRegionID;
306 protected Timer m_restartWaitTimer = new Timer();
307 protected List<RegionInfo> m_regionRestartNotifyList = new List<RegionInfo>();
308 protected List<RegionInfo> m_neighbours = new List<RegionInfo>();
309 protected string m_simulatorVersion = "OpenSimulator Server";
310 protected AgentCircuitManager m_authenticateHandler;
311 protected SceneCommunicationService m_sceneGridService;
312
313 protected ISimulationDataService m_SimulationDataService;
314 protected IEstateDataService m_EstateDataService;
315 protected IAssetService m_AssetService;
316 protected IAuthorizationService m_AuthorizationService;
317 protected IInventoryService m_InventoryService;
318 protected IGridService m_GridService;
319 protected ILibraryService m_LibraryService;
320 protected ISimulationService m_simulationService;
321 protected IAuthenticationService m_AuthenticationService;
322 protected IPresenceService m_PresenceService;
323 protected IUserAccountService m_UserAccountService;
324 protected IAvatarService m_AvatarService;
325 protected IGridUserService m_GridUserService;
326
327 protected IXMLRPC m_xmlrpcModule;
328 protected IWorldComm m_worldCommModule;
329 protected IAvatarFactoryModule m_AvatarFactory;
330 protected IConfigSource m_config;
331 protected IRegionSerialiserModule m_serialiser;
332 protected IDialogModule m_dialogModule;
333 protected ICapabilitiesModule m_capsModule;
334 protected IGroupsModule m_groupsModule;
335
336 private Dictionary<string, string> m_extraSettings;
337
338 /// <summary>
339 /// If true then the next time the scene loop is activated, updates will be performed by firing of a timer
340 /// rather than on a single thread that sleeps.
341 /// </summary>
342 public bool UpdateOnTimer { get; set; }
343
344 /// <summary>
345 /// Only used if we are updating scene on a timer rather than sleeping a thread.
346 /// </summary>
347 private Timer m_sceneUpdateTimer;
348
349 /// <summary>
350 /// Current scene frame number
351 /// </summary>
352 public uint Frame
353 {
354 get;
355 protected set;
356 }
357
358 /// <summary>
359 /// Current maintenance run number
360 /// </summary>
361 public uint MaintenanceRun { get; private set; }
362
363 /// <summary>
364 /// The minimum length of time in milliseconds that will be taken for a scene frame. If the frame takes less time then we
365 /// will sleep for the remaining period.
366 /// </summary>
367 /// <remarks>
368 /// One can tweak this number to experiment. One current effect of reducing it is to make avatar animations
369 /// occur too quickly (viewer 1) or with even more slide (viewer 2).
370 /// </remarks>
371 public int MinFrameTicks
372 {
373 get { return m_minFrameTicks; }
374 private set
375 {
376 m_minFrameTicks = value;
377 MinFrameSeconds = (float)m_minFrameTicks / 1000;
378 }
379 }
380 private int m_minFrameTicks;
381
382 /// <summary>
383 /// The minimum length of time in seconds that will be taken for a scene frame.
384 /// </summary>
385 /// <remarks>
386 /// Always derived from MinFrameTicks.
387 /// </remarks>
388 public float MinFrameSeconds { get; private set; }
389
390 /// <summary>
391 /// The minimum length of time in milliseconds that will be taken for a scene frame. If the frame takes less time then we
392 /// will sleep for the remaining period.
393 /// </summary>
394 /// <remarks>
395 /// One can tweak this number to experiment. One current effect of reducing it is to make avatar animations
396 /// occur too quickly (viewer 1) or with even more slide (viewer 2).
397 /// </remarks>
398 public int MinMaintenanceTicks { get; set; }
399
400 private int m_update_physics = 1;
401 private int m_update_entitymovement = 1;
402 private int m_update_objects = 1;
403 private int m_update_presences = 1; // Update scene presence movements
404 private int m_update_events = 1;
405 private int m_update_backup = 200;
406 private int m_update_terrain = 50;
407 // private int m_update_land = 1;
408 private int m_update_coarse_locations = 50;
409 private int m_update_temp_cleaning = 180;
410
411 private int agentMS;
412 private int frameMS;
413 private int physicsMS2;
414 private int physicsMS;
415 private int otherMS;
416 private int tempOnRezMS;
417 private int eventMS;
418 private int backupMS;
419 private int terrainMS;
420 private int landMS;
421 private int spareMS;
422
423 /// <summary>
424 /// Tick at which the last frame was processed.
425 /// </summary>
426 private int m_lastFrameTick;
427
428 /// <summary>
429 /// Tick at which the last maintenance run occurred.
430 /// </summary>
431 private int m_lastMaintenanceTick;
432
433 /// <summary>
434 /// Signals whether temporary objects are currently being cleaned up. Needed because this is launched
435 /// asynchronously from the update loop.
436 /// </summary>
437 private bool m_cleaningTemps = false;
438
439 /// <summary>
440 /// Used to control main scene thread looping time when not updating via timer.
441 /// </summary>
442 private ManualResetEvent m_updateWaitEvent = new ManualResetEvent(false);
443
444 /// <summary>
445 /// Used to control maintenance thread runs.
446 /// </summary>
447 private ManualResetEvent m_maintenanceWaitEvent = new ManualResetEvent(false);
448
449 // TODO: Possibly stop other classes being able to manipulate this directly.
450 private SceneGraph m_sceneGraph;
451 private readonly Timer m_restartTimer = new Timer(15000); // Wait before firing
452 private volatile bool m_backingup;
453 private Dictionary<UUID, ReturnInfo> m_returns = new Dictionary<UUID, ReturnInfo>();
454 private Dictionary<UUID, SceneObjectGroup> m_groupsWithTargets = new Dictionary<UUID, SceneObjectGroup>();
455
456 private string m_defaultScriptEngine;
457
458 /// <summary>
459 /// Tick at which the last login occurred.
460 /// </summary>
461 private int m_LastLogin;
462
463 /// <summary>
464 /// Thread that runs the scene loop.
465 /// </summary>
466 private Thread m_heartbeatThread;
467
468 /// <summary>
469 /// True if these scene is in the process of shutting down or is shutdown.
470 /// </summary>
471 public bool ShuttingDown
472 {
473 get { return m_shuttingDown; }
474 }
475 private volatile bool m_shuttingDown;
476
477 /// <summary>
478 /// Is the scene active?
479 /// </summary>
480 /// <remarks>
481 /// If false, maintenance and update loops are not being run, though after setting to false update may still
482 /// be active for a period (and IsRunning will still be true). Updates can still be triggered manually if
483 /// the scene is not active.
484 /// </remarks>
485 public bool Active
486 {
487 get { return m_active; }
488 set
489 {
490 if (value)
491 {
492 if (!m_active)
493 Start(false);
592 } 494 }
593 } 495 else
594
595 public IAuthorizationService AuthorizationService
596 {
597 get
598 { 496 {
599 if (m_AuthorizationService == null) 497 // This appears assymetric with Start() above but is not - setting m_active = false stops the loops
600 { 498 // XXX: Possibly this should be in an explicit Stop() method for symmetry.
601 m_AuthorizationService = RequestModuleInterface<IAuthorizationService>(); 499 m_active = false;
602
603 //if (m_AuthorizationService == null)
604 //{
605 // // don't throw an exception if no authorization service is set for the time being
606 // m_log.InfoFormat("[SCENE]: No Authorization service is configured");
607 //}
608 }
609
610 return m_AuthorizationService;
611 } 500 }
612 } 501 }
502 }
503 private volatile bool m_active;
613 504
614 public IInventoryService InventoryService 505 /// <summary>
615 { 506 /// If true then updates are running. This may be true for a short period after a scene is de-activated.
616 get 507 /// </summary>
617 { 508 public bool IsRunning { get { return m_isRunning; } }
618 if (m_InventoryService == null) 509 private volatile bool m_isRunning;
619 {
620 m_InventoryService = RequestModuleInterface<IInventoryService>();
621 510
622 if (m_InventoryService == null) 511 private Timer m_mapGenerationTimer = new Timer();
623 { 512 private bool m_generateMaptiles;
624 throw new Exception("No IInventoryService available. This could happen if the config_include folder doesn't exist or if the OpenSim.ini [Architecture] section isn't set. Please also check that you have the correct version of your inventory service dll. Sometimes old versions of this dll will still exist. Do a clean checkout and re-create the opensim.ini from the opensim.ini.example.");
625 }
626 }
627 513
628 return m_InventoryService; 514 #endregion Fields
629 }
630 }
631 515
632 public IGridService GridService 516 #region Properties
633 {
634 get
635 {
636 if (m_GridService == null)
637 {
638 m_GridService = RequestModuleInterface<IGridService>();
639 517
640 if (m_GridService == null) 518 /* Used by the loadbalancer plugin on GForge */
641 { 519 public int SplitRegionID
642 throw new Exception("No IGridService available. This could happen if the config_include folder doesn't exist or if the OpenSim.ini [Architecture] section isn't set. Please also check that you have the correct version of your inventory service dll. Sometimes old versions of this dll will still exist. Do a clean checkout and re-create the opensim.ini from the opensim.ini.example."); 520 {
643 } 521 get { return m_splitRegionID; }
644 } 522 set { m_splitRegionID = value; }
523 }
645 524
646 return m_GridService; 525 public new float TimeDilation
647 } 526 {
648 } 527 get { return m_sceneGraph.PhysicsScene.TimeDilation; }
528 }
649 529
650 public ILibraryService LibraryService 530 public void setThreadCount(int inUseThreads)
651 { 531 {
652 get 532 // Just pass the thread count information on its way as the Scene
653 { 533 // does not require the value for anything at this time
654 if (m_LibraryService == null) 534 StatsReporter.SetThreadCount(inUseThreads);
655 m_LibraryService = RequestModuleInterface<ILibraryService>(); 535 }
656 536
657 return m_LibraryService; 537 public SceneCommunicationService SceneGridService
658 } 538 {
659 } 539 get { return m_sceneGridService; }
540 }
660 541
661 public ISimulationService SimulationService 542 public ISimulationDataService SimulationDataService
662 { 543 {
663 get 544 get
545 {
546 if (m_SimulationDataService == null)
664 { 547 {
665 if (m_simulationService == null) 548 m_SimulationDataService = RequestModuleInterface<ISimulationDataService>();
666 m_simulationService = RequestModuleInterface<ISimulationService>();
667 549
668 return m_simulationService; 550 if (m_SimulationDataService == null)
551 {
552 throw new Exception("No ISimulationDataService available.");
553 }
669 } 554 }
670 }
671 555
672 public IAuthenticationService AuthenticationService 556 return m_SimulationDataService;
673 { 557 }
674 get 558 }
559
560 public IEstateDataService EstateDataService
561 {
562 get
563 {
564 if (m_EstateDataService == null)
675 { 565 {
676 if (m_AuthenticationService == null) 566 m_EstateDataService = RequestModuleInterface<IEstateDataService>();
677 m_AuthenticationService = RequestModuleInterface<IAuthenticationService>();
678 return m_AuthenticationService;
679 }
680 }
681
682 public IPresenceService PresenceService
683 {
684 get
685 {
686 if (m_PresenceService == null)
687 m_PresenceService = RequestModuleInterface<IPresenceService>();
688 return m_PresenceService;
689 }
690 }
691 567
692 public IUserAccountService UserAccountService 568 if (m_EstateDataService == null)
693 { 569 {
694 get 570 throw new Exception("No IEstateDataService available.");
695 { 571 }
696 if (m_UserAccountService == null)
697 m_UserAccountService = RequestModuleInterface<IUserAccountService>();
698 return m_UserAccountService;
699 }
700 }
701
702 public IAvatarService AvatarService
703 {
704 get
705 {
706 if (m_AvatarService == null)
707 m_AvatarService = RequestModuleInterface<IAvatarService>();
708 return m_AvatarService;
709 }
710 }
711
712 public IGridUserService GridUserService
713 {
714 get
715 {
716 if (m_GridUserService == null)
717 m_GridUserService = RequestModuleInterface<IGridUserService>();
718 return m_GridUserService;
719 }
720 }
721
722 public IAttachmentsModule AttachmentsModule { get; set; }
723 public IEntityTransferModule EntityTransferModule { get; private set; }
724 public IAgentAssetTransactions AgentTransactionsModule { get; private set; }
725 public IUserManagement UserManagementModule { get; private set; }
726
727 public IAvatarFactoryModule AvatarFactory
728 {
729 get { return m_AvatarFactory; }
730 }
731
732 public ICapabilitiesModule CapsModule
733 {
734 get { return m_capsModule; }
735 }
736
737 public int MonitorFrameTime { get { return frameMS; } }
738 public int MonitorPhysicsUpdateTime { get { return physicsMS; } }
739 public int MonitorPhysicsSyncTime { get { return physicsMS2; } }
740 public int MonitorOtherTime { get { return otherMS; } }
741 public int MonitorTempOnRezTime { get { return tempOnRezMS; } }
742 public int MonitorEventTime { get { return eventMS; } } // This may need to be divided into each event?
743 public int MonitorBackupTime { get { return backupMS; } }
744 public int MonitorTerrainTime { get { return terrainMS; } }
745 public int MonitorLandTime { get { return landMS; } }
746 public int MonitorLastFrameTick { get { return m_lastFrameTick; } }
747
748 public UpdatePrioritizationSchemes UpdatePrioritizationScheme { get; set; }
749 public bool IsReprioritizationEnabled { get; set; }
750 public double ReprioritizationInterval { get; set; }
751 public double RootReprioritizationDistance { get; set; }
752 public double ChildReprioritizationDistance { get; set; }
753
754 public AgentCircuitManager AuthenticateHandler
755 {
756 get { return m_authenticateHandler; }
757 }
758
759 // an instance to the physics plugin's Scene object.
760 public PhysicsScene PhysicsScene
761 {
762 get { return m_sceneGraph.PhysicsScene; }
763 set
764 {
765 // If we're not doing the initial set
766 // Then we've got to remove the previous
767 // event handler
768 if (PhysicsScene != null && PhysicsScene.SupportsNINJAJoints)
769 {
770 PhysicsScene.OnJointMoved -= jointMoved;
771 PhysicsScene.OnJointDeactivated -= jointDeactivated;
772 PhysicsScene.OnJointErrorMessage -= jointErrorMessage;
773 }
774
775 m_sceneGraph.PhysicsScene = value;
776
777 if (PhysicsScene != null && m_sceneGraph.PhysicsScene.SupportsNINJAJoints)
778 {
779 // register event handlers to respond to joint movement/deactivation
780 PhysicsScene.OnJointMoved += jointMoved;
781 PhysicsScene.OnJointDeactivated += jointDeactivated;
782 PhysicsScene.OnJointErrorMessage += jointErrorMessage;
783 }
784 } 572 }
785 }
786
787 public string DefaultScriptEngine
788 {
789 get { return m_defaultScriptEngine; }
790 }
791
792 public EntityManager Entities
793 {
794 get { return m_sceneGraph.Entities; }
795 }
796
797
798 // used in sequence see: SpawnPoint()
799 private int m_SpawnPoint;
800 // can be closest/random/sequence
801 public string SpawnPointRouting
802 {
803 get; private set;
804 }
805 // allow landmarks to pass
806 public bool TelehubAllowLandmarks
807 {
808 get; private set;
809 }
810 573
811 #endregion Properties 574 return m_EstateDataService;
812 575 }
813 #region Constructors 576 }
577
578 public IAssetService AssetService
579 {
580 get
581 {
582 if (m_AssetService == null)
583 {
584 m_AssetService = RequestModuleInterface<IAssetService>();
585
586 if (m_AssetService == null)
587 {
588 throw new Exception("No IAssetService available.");
589 }
590 }
591
592 return m_AssetService;
593 }
594 }
595
596 public IAuthorizationService AuthorizationService
597 {
598 get
599 {
600 if (m_AuthorizationService == null)
601 {
602 m_AuthorizationService = RequestModuleInterface<IAuthorizationService>();
603
604 //if (m_AuthorizationService == null)
605 //{
606 // // don't throw an exception if no authorization service is set for the time being
607 // m_log.InfoFormat("[SCENE]: No Authorization service is configured");
608 //}
609 }
610
611 return m_AuthorizationService;
612 }
613 }
614
615 public IInventoryService InventoryService
616 {
617 get
618 {
619 if (m_InventoryService == null)
620 {
621 m_InventoryService = RequestModuleInterface<IInventoryService>();
622
623 if (m_InventoryService == null)
624 {
625 throw new Exception("No IInventoryService available. This could happen if the config_include folder doesn't exist or if the OpenSim.ini [Architecture] section isn't set. Please also check that you have the correct version of your inventory service dll. Sometimes old versions of this dll will still exist. Do a clean checkout and re-create the opensim.ini from the opensim.ini.example.");
626 }
627 }
628
629 return m_InventoryService;
630 }
631 }
632
633 public IGridService GridService
634 {
635 get
636 {
637 if (m_GridService == null)
638 {
639 m_GridService = RequestModuleInterface<IGridService>();
640
641 if (m_GridService == null)
642 {
643 throw new Exception("No IGridService available. This could happen if the config_include folder doesn't exist or if the OpenSim.ini [Architecture] section isn't set. Please also check that you have the correct version of your inventory service dll. Sometimes old versions of this dll will still exist. Do a clean checkout and re-create the opensim.ini from the opensim.ini.example.");
644 }
645 }
646
647 return m_GridService;
648 }
649 }
650
651 public ILibraryService LibraryService
652 {
653 get
654 {
655 if (m_LibraryService == null)
656 m_LibraryService = RequestModuleInterface<ILibraryService>();
657
658 return m_LibraryService;
659 }
660 }
661
662 public ISimulationService SimulationService
663 {
664 get
665 {
666 if (m_simulationService == null)
667 m_simulationService = RequestModuleInterface<ISimulationService>();
668
669 return m_simulationService;
670 }
671 }
672
673 public IAuthenticationService AuthenticationService
674 {
675 get
676 {
677 if (m_AuthenticationService == null)
678 m_AuthenticationService = RequestModuleInterface<IAuthenticationService>();
679 return m_AuthenticationService;
680 }
681 }
682
683 public IPresenceService PresenceService
684 {
685 get
686 {
687 if (m_PresenceService == null)
688 m_PresenceService = RequestModuleInterface<IPresenceService>();
689 return m_PresenceService;
690 }
691 }
692
693 public IUserAccountService UserAccountService
694 {
695 get
696 {
697 if (m_UserAccountService == null)
698 m_UserAccountService = RequestModuleInterface<IUserAccountService>();
699 return m_UserAccountService;
700 }
701 }
702
703 public IAvatarService AvatarService
704 {
705 get
706 {
707 if (m_AvatarService == null)
708 m_AvatarService = RequestModuleInterface<IAvatarService>();
709 return m_AvatarService;
710 }
711 }
712
713 public IGridUserService GridUserService
714 {
715 get
716 {
717 if (m_GridUserService == null)
718 m_GridUserService = RequestModuleInterface<IGridUserService>();
719 return m_GridUserService;
720 }
721 }
722
723 public IAttachmentsModule AttachmentsModule { get; set; }
724 public IEntityTransferModule EntityTransferModule { get; private set; }
725 public IAgentAssetTransactions AgentTransactionsModule { get; private set; }
726 public IUserManagement UserManagementModule { get; private set; }
727
728 public IAvatarFactoryModule AvatarFactory
729 {
730 get { return m_AvatarFactory; }
731 }
732
733 public ICapabilitiesModule CapsModule
734 {
735 get { return m_capsModule; }
736 }
737
738 public int MonitorFrameTime { get { return frameMS; } }
739 public int MonitorPhysicsUpdateTime { get { return physicsMS; } }
740 public int MonitorPhysicsSyncTime { get { return physicsMS2; } }
741 public int MonitorOtherTime { get { return otherMS; } }
742 public int MonitorTempOnRezTime { get { return tempOnRezMS; } }
743 public int MonitorEventTime { get { return eventMS; } } // This may need to be divided into each event?
744 public int MonitorBackupTime { get { return backupMS; } }
745 public int MonitorTerrainTime { get { return terrainMS; } }
746 public int MonitorLandTime { get { return landMS; } }
747 public int MonitorLastFrameTick { get { return m_lastFrameTick; } }
748
749 public UpdatePrioritizationSchemes UpdatePrioritizationScheme { get; set; }
750 public bool IsReprioritizationEnabled { get; set; }
751 public double ReprioritizationInterval { get; set; }
752 public double RootReprioritizationDistance { get; set; }
753 public double ChildReprioritizationDistance { get; set; }
754
755 public AgentCircuitManager AuthenticateHandler
756 {
757 get { return m_authenticateHandler; }
758 }
759
760 // an instance to the physics plugin's Scene object.
761 public PhysicsScene PhysicsScene
762 {
763 get { return m_sceneGraph.PhysicsScene; }
764 set
765 {
766 // If we're not doing the initial set
767 // Then we've got to remove the previous
768 // event handler
769 if (PhysicsScene != null && PhysicsScene.SupportsNINJAJoints)
770 {
771 PhysicsScene.OnJointMoved -= jointMoved;
772 PhysicsScene.OnJointDeactivated -= jointDeactivated;
773 PhysicsScene.OnJointErrorMessage -= jointErrorMessage;
774 }
775
776 m_sceneGraph.PhysicsScene = value;
777
778 if (PhysicsScene != null && m_sceneGraph.PhysicsScene.SupportsNINJAJoints)
779 {
780 // register event handlers to respond to joint movement/deactivation
781 PhysicsScene.OnJointMoved += jointMoved;
782 PhysicsScene.OnJointDeactivated += jointDeactivated;
783 PhysicsScene.OnJointErrorMessage += jointErrorMessage;
784 }
785 }
786 }
787
788 public string DefaultScriptEngine
789 {
790 get { return m_defaultScriptEngine; }
791 }
792
793 public EntityManager Entities
794 {
795 get { return m_sceneGraph.Entities; }
796 }
797
798
799 // used in sequence see: SpawnPoint()
800 private int m_SpawnPoint;
801 // can be closest/random/sequence
802 public string SpawnPointRouting
803 {
804 get;
805 private set;
806 }
807 // allow landmarks to pass
808 public bool TelehubAllowLandmarks
809 {
810 get;
811 private set;
812 }
813
814 #endregion Properties
815
816 #region Constructors
817
818 public Scene(RegionInfo regInfo, AgentCircuitManager authen, PhysicsScene physicsScene,
819 SceneCommunicationService sceneGridService,
820 ISimulationDataService simDataService, IEstateDataService estateDataService,
821 IConfigSource config, string simulatorVersion)
822 : this(regInfo, physicsScene)
823 {
824 m_config = config;
825 MinFrameTicks = 89;
826 MinMaintenanceTicks = 1000;
827 SeeIntoRegion = true;
828
829 Random random = new Random();
830
831 m_lastAllocatedLocalId = (uint)(random.NextDouble() * (double)(uint.MaxValue / 2)) + (uint)(uint.MaxValue / 4);
832 m_authenticateHandler = authen;
833 m_sceneGridService = sceneGridService;
834 m_SimulationDataService = simDataService;
835 m_EstateDataService = estateDataService;
836
837 m_asyncSceneObjectDeleter = new AsyncSceneObjectGroupDeleter(this);
838 m_asyncSceneObjectDeleter.Enabled = true;
839
840 m_asyncInventorySender = new AsyncInventorySender(this);
841
842 #region Region Settings
843
844 // Load region settings
845 // LoadRegionSettings creates new region settings in persistence if they don't already exist for this region.
846 // However, in this case, the default textures are not set in memory properly, so we need to do it here and
847 // resave.
848 // FIXME: It shouldn't be up to the database plugins to create this data - we should do it when a new
849 // region is set up and avoid these gyrations.
850 RegionSettings rs = simDataService.LoadRegionSettings(RegionInfo.RegionID);
851 m_extraSettings = simDataService.GetExtra(RegionInfo.RegionID);
852
853 bool updatedTerrainTextures = false;
854 if (rs.TerrainTexture1 == UUID.Zero)
855 {
856 rs.TerrainTexture1 = RegionSettings.DEFAULT_TERRAIN_TEXTURE_1;
857 updatedTerrainTextures = true;
858 }
859
860 if (rs.TerrainTexture2 == UUID.Zero)
861 {
862 rs.TerrainTexture2 = RegionSettings.DEFAULT_TERRAIN_TEXTURE_2;
863 updatedTerrainTextures = true;
864 }
865
866 if (rs.TerrainTexture3 == UUID.Zero)
867 {
868 rs.TerrainTexture3 = RegionSettings.DEFAULT_TERRAIN_TEXTURE_3;
869 updatedTerrainTextures = true;
870 }
871
872 if (rs.TerrainTexture4 == UUID.Zero)
873 {
874 rs.TerrainTexture4 = RegionSettings.DEFAULT_TERRAIN_TEXTURE_4;
875 updatedTerrainTextures = true;
876 }
877
878 if (updatedTerrainTextures)
879 rs.Save();
880
881 RegionInfo.RegionSettings = rs;
882
883 if (estateDataService != null)
884 RegionInfo.EstateSettings = estateDataService.LoadEstateSettings(RegionInfo.RegionID, false);
885
886 #endregion Region Settings
887
888 //Bind Storage Manager functions to some land manager functions for this scene
889 EventManager.OnLandObjectAdded +=
890 new EventManager.LandObjectAdded(simDataService.StoreLandObject);
891 EventManager.OnLandObjectRemoved +=
892 new EventManager.LandObjectRemoved(simDataService.RemoveLandObject);
893
894 RegisterDefaultSceneEvents();
895
896 // XXX: Don't set the public property since we don't want to activate here. This needs to be handled
897 // better in the future.
898 m_scripts_enabled = !RegionInfo.RegionSettings.DisableScripts;
899
900 PhysicsEnabled = !RegionInfo.RegionSettings.DisablePhysics;
901
902 m_simulatorVersion = simulatorVersion + " (" + Util.GetRuntimeInformation() + ")";
903
904 #region Region Config
905
906 // Region config overrides global config
907 //
908 if (m_config.Configs["Startup"] != null)
909 {
910 IConfig startupConfig = m_config.Configs["Startup"];
814 911
815 public Scene(RegionInfo regInfo, AgentCircuitManager authen, PhysicsScene physicsScene, 912 StartDisabled = startupConfig.GetBoolean("StartDisabled", false);
816 SceneCommunicationService sceneGridService,
817 ISimulationDataService simDataService, IEstateDataService estateDataService,
818 IConfigSource config, string simulatorVersion)
819 : this(regInfo, physicsScene)
820 {
821 m_config = config;
822 MinFrameTicks = 89;
823 MinMaintenanceTicks = 1000;
824 SeeIntoRegion = true;
825 913
826 Random random = new Random(); 914 m_defaultDrawDistance = startupConfig.GetFloat("DefaultDrawDistance", m_defaultDrawDistance);
827 915 UseBackup = startupConfig.GetBoolean("UseSceneBackup", UseBackup);
828 m_lastAllocatedLocalId = (uint)(random.NextDouble() * (double)(uint.MaxValue / 2)) + (uint)(uint.MaxValue / 4); 916 if (!UseBackup)
829 m_authenticateHandler = authen; 917 m_log.InfoFormat("[SCENE]: Backup has been disabled for {0}", RegionInfo.RegionName);
830 m_sceneGridService = sceneGridService;
831 m_SimulationDataService = simDataService;
832 m_EstateDataService = estateDataService;
833 918
834 m_asyncSceneObjectDeleter = new AsyncSceneObjectGroupDeleter(this); 919 //Animation states
835 m_asyncSceneObjectDeleter.Enabled = true; 920 m_useFlySlow = startupConfig.GetBoolean("enableflyslow", false);
836 921
837 m_asyncInventorySender = new AsyncInventorySender(this); 922 SeeIntoRegion = startupConfig.GetBoolean("see_into_region", SeeIntoRegion);
838 923
839 #region Region Settings 924 MaxUndoCount = startupConfig.GetInt("MaxPrimUndos", 20);
840 925
841 // Load region settings 926 PhysicalPrims = startupConfig.GetBoolean("physical_prim", PhysicalPrims);
842 // LoadRegionSettings creates new region settings in persistence if they don't already exist for this region. 927 CollidablePrims = startupConfig.GetBoolean("collidable_prim", CollidablePrims);
843 // However, in this case, the default textures are not set in memory properly, so we need to do it here and
844 // resave.
845 // FIXME: It shouldn't be up to the database plugins to create this data - we should do it when a new
846 // region is set up and avoid these gyrations.
847 RegionSettings rs = simDataService.LoadRegionSettings(RegionInfo.RegionID);
848 m_extraSettings = simDataService.GetExtra(RegionInfo.RegionID);
849 928
850 bool updatedTerrainTextures = false; 929 m_minNonphys = startupConfig.GetFloat("NonPhysicalPrimMin", m_minNonphys);
851 if (rs.TerrainTexture1 == UUID.Zero) 930 if (RegionInfo.NonphysPrimMin > 0)
852 { 931 {
853 rs.TerrainTexture1 = RegionSettings.DEFAULT_TERRAIN_TEXTURE_1; 932 m_minNonphys = RegionInfo.NonphysPrimMin;
854 updatedTerrainTextures = true;
855 } 933 }
856 934
857 if (rs.TerrainTexture2 == UUID.Zero) 935 m_maxNonphys = startupConfig.GetFloat("NonPhysicalPrimMax", m_maxNonphys);
936 if (RegionInfo.NonphysPrimMax > 0)
858 { 937 {
859 rs.TerrainTexture2 = RegionSettings.DEFAULT_TERRAIN_TEXTURE_2; 938 m_maxNonphys = RegionInfo.NonphysPrimMax;
860 updatedTerrainTextures = true;
861 } 939 }
862 940
863 if (rs.TerrainTexture3 == UUID.Zero) 941 m_minPhys = startupConfig.GetFloat("PhysicalPrimMin", m_minPhys);
942 if (RegionInfo.PhysPrimMin > 0)
864 { 943 {
865 rs.TerrainTexture3 = RegionSettings.DEFAULT_TERRAIN_TEXTURE_3; 944 m_minPhys = RegionInfo.PhysPrimMin;
866 updatedTerrainTextures = true;
867 } 945 }
868 946
869 if (rs.TerrainTexture4 == UUID.Zero) 947 m_maxPhys = startupConfig.GetFloat("PhysicalPrimMax", m_maxPhys);
948 if (RegionInfo.PhysPrimMax > 0)
870 { 949 {
871 rs.TerrainTexture4 = RegionSettings.DEFAULT_TERRAIN_TEXTURE_4; 950 m_maxPhys = RegionInfo.PhysPrimMax;
872 updatedTerrainTextures = true;
873 } 951 }
874 952
875 if (updatedTerrainTextures) 953 // Here, if clamping is requested in either global or
876 rs.Save(); 954 // local config, it will be used
877 955 //
878 RegionInfo.RegionSettings = rs; 956 m_clampPrimSize = startupConfig.GetBoolean("ClampPrimSize", m_clampPrimSize);
879 957 if (RegionInfo.ClampPrimSize)
880 if (estateDataService != null) 958 {
881 RegionInfo.EstateSettings = estateDataService.LoadEstateSettings(RegionInfo.RegionID, false); 959 m_clampPrimSize = true;
882 960 }
883 #endregion Region Settings
884
885 //Bind Storage Manager functions to some land manager functions for this scene
886 EventManager.OnLandObjectAdded +=
887 new EventManager.LandObjectAdded(simDataService.StoreLandObject);
888 EventManager.OnLandObjectRemoved +=
889 new EventManager.LandObjectRemoved(simDataService.RemoveLandObject);
890
891 RegisterDefaultSceneEvents();
892 961
893 // XXX: Don't set the public property since we don't want to activate here. This needs to be handled 962 m_linksetCapacity = startupConfig.GetInt("LinksetPrims", m_linksetCapacity);
894 // better in the future. 963 if (RegionInfo.LinksetCapacity > 0)
895 m_scripts_enabled = !RegionInfo.RegionSettings.DisableScripts; 964 {
965 m_linksetCapacity = RegionInfo.LinksetCapacity;
966 }
896 967
897 PhysicsEnabled = !RegionInfo.RegionSettings.DisablePhysics; 968 m_useTrashOnDelete = startupConfig.GetBoolean("UseTrashOnDelete", m_useTrashOnDelete);
969 m_trustBinaries = startupConfig.GetBoolean("TrustBinaries", m_trustBinaries);
970 m_allowScriptCrossings = startupConfig.GetBoolean("AllowScriptCrossing", m_allowScriptCrossings);
971 m_dontPersistBefore =
972 startupConfig.GetLong("MinimumTimeBeforePersistenceConsidered", DEFAULT_MIN_TIME_FOR_PERSISTENCE);
973 m_dontPersistBefore *= 10000000;
974 m_persistAfter =
975 startupConfig.GetLong("MaximumTimeBeforePersistenceConsidered", DEFAULT_MAX_TIME_FOR_PERSISTENCE);
976 m_persistAfter *= 10000000;
898 977
899 m_simulatorVersion = simulatorVersion + " (" + Util.GetRuntimeInformation() + ")"; 978 m_defaultScriptEngine = startupConfig.GetString("DefaultScriptEngine", "XEngine");
900 979
901 #region Region Config 980 SpawnPointRouting = startupConfig.GetString("SpawnPointRouting", "closest");
981 TelehubAllowLandmarks = startupConfig.GetBoolean("TelehubAllowLandmark", false);
902 982
903 // Region config overrides global config 983 m_strictAccessControl = startupConfig.GetBoolean("StrictAccessControl", m_strictAccessControl);
904 //
905 if (m_config.Configs["Startup"] != null)
906 {
907 IConfig startupConfig = m_config.Configs["Startup"];
908
909 StartDisabled = startupConfig.GetBoolean("StartDisabled", false);
910
911 m_defaultDrawDistance = startupConfig.GetFloat("DefaultDrawDistance", m_defaultDrawDistance);
912 UseBackup = startupConfig.GetBoolean("UseSceneBackup", UseBackup);
913 if (!UseBackup)
914 m_log.InfoFormat("[SCENE]: Backup has been disabled for {0}", RegionInfo.RegionName);
915
916 //Animation states
917 m_useFlySlow = startupConfig.GetBoolean("enableflyslow", false);
918
919 SeeIntoRegion = startupConfig.GetBoolean("see_into_region", SeeIntoRegion);
920
921 MaxUndoCount = startupConfig.GetInt("MaxPrimUndos", 20);
922
923 PhysicalPrims = startupConfig.GetBoolean("physical_prim", PhysicalPrims);
924 CollidablePrims = startupConfig.GetBoolean("collidable_prim", CollidablePrims);
925
926 m_minNonphys = startupConfig.GetFloat("NonPhysicalPrimMin", m_minNonphys);
927 if (RegionInfo.NonphysPrimMin > 0)
928 {
929 m_minNonphys = RegionInfo.NonphysPrimMin;
930 }
931
932 m_maxNonphys = startupConfig.GetFloat("NonPhysicalPrimMax", m_maxNonphys);
933 if (RegionInfo.NonphysPrimMax > 0)
934 {
935 m_maxNonphys = RegionInfo.NonphysPrimMax;
936 }
937
938 m_minPhys = startupConfig.GetFloat("PhysicalPrimMin", m_minPhys);
939 if (RegionInfo.PhysPrimMin > 0)
940 {
941 m_minPhys = RegionInfo.PhysPrimMin;
942 }
943
944 m_maxPhys = startupConfig.GetFloat("PhysicalPrimMax", m_maxPhys);
945 if (RegionInfo.PhysPrimMax > 0)
946 {
947 m_maxPhys = RegionInfo.PhysPrimMax;
948 }
949
950 // Here, if clamping is requested in either global or
951 // local config, it will be used
952 //
953 m_clampPrimSize = startupConfig.GetBoolean("ClampPrimSize", m_clampPrimSize);
954 if (RegionInfo.ClampPrimSize)
955 {
956 m_clampPrimSize = true;
957 }
958
959 m_linksetCapacity = startupConfig.GetInt("LinksetPrims", m_linksetCapacity);
960 if (RegionInfo.LinksetCapacity > 0)
961 {
962 m_linksetCapacity = RegionInfo.LinksetCapacity;
963 }
964
965 m_useTrashOnDelete = startupConfig.GetBoolean("UseTrashOnDelete", m_useTrashOnDelete);
966 m_trustBinaries = startupConfig.GetBoolean("TrustBinaries", m_trustBinaries);
967 m_allowScriptCrossings = startupConfig.GetBoolean("AllowScriptCrossing", m_allowScriptCrossings);
968 m_dontPersistBefore =
969 startupConfig.GetLong("MinimumTimeBeforePersistenceConsidered", DEFAULT_MIN_TIME_FOR_PERSISTENCE);
970 m_dontPersistBefore *= 10000000;
971 m_persistAfter =
972 startupConfig.GetLong("MaximumTimeBeforePersistenceConsidered", DEFAULT_MAX_TIME_FOR_PERSISTENCE);
973 m_persistAfter *= 10000000;
974
975 m_defaultScriptEngine = startupConfig.GetString("DefaultScriptEngine", "XEngine");
976
977 SpawnPointRouting = startupConfig.GetString("SpawnPointRouting", "closest");
978 TelehubAllowLandmarks = startupConfig.GetBoolean("TelehubAllowLandmark", false);
979
980 m_strictAccessControl = startupConfig.GetBoolean("StrictAccessControl", m_strictAccessControl);
981
982 string[] possibleMapConfigSections = new string[] { "Map", "Startup" };
983
984 m_generateMaptiles
985 = Util.GetConfigVarFromSections<bool>(config, "GenerateMaptiles", possibleMapConfigSections, true);
986
987 if (m_generateMaptiles)
988 {
989 int maptileRefresh = Util.GetConfigVarFromSections<int>(config, "MaptileRefresh", possibleMapConfigSections, 0);
990 m_log.InfoFormat("[SCENE]: Region {0}, WORLD MAP refresh time set to {1} seconds", RegionInfo.RegionName, maptileRefresh);
991 if (maptileRefresh != 0)
992 {
993 m_mapGenerationTimer.Interval = maptileRefresh * 1000;
994 m_mapGenerationTimer.Elapsed += RegenerateMaptileAndReregister;
995 m_mapGenerationTimer.AutoReset = true;
996 m_mapGenerationTimer.Start();
997 }
998 }
999 else
1000 {
1001 string tile
1002 = Util.GetConfigVarFromSections<string>(
1003 config, "MaptileStaticUUID", possibleMapConfigSections, UUID.Zero.ToString());
1004
1005 UUID tileID;
1006
1007 if (tile != UUID.Zero.ToString() && UUID.TryParse(tile, out tileID))
1008 {
1009 RegionInfo.RegionSettings.TerrainImageID = tileID;
1010 }
1011 else
1012 {
1013 RegionInfo.RegionSettings.TerrainImageID = RegionInfo.MaptileStaticUUID;
1014 m_log.InfoFormat("[SCENE]: Region {0}, maptile set to {1}", RegionInfo.RegionName, RegionInfo.MaptileStaticUUID.ToString());
1015 }
1016 }
1017
1018 string[] possibleAccessControlConfigSections = new string[] { "AccessControl", "Startup" };
1019
1020 string grant
1021 = Util.GetConfigVarFromSections<string>(
1022 config, "AllowedClients", possibleAccessControlConfigSections, "");
1023
1024 if (grant.Length > 0)
1025 {
1026 foreach (string viewer in grant.Split('|'))
1027 {
1028 m_AllowedViewers.Add(viewer.Trim().ToLower());
1029 }
1030 }
1031
1032 grant
1033 = Util.GetConfigVarFromSections<string>(
1034 config, "BannedClients", possibleAccessControlConfigSections, "");
1035
1036 if (grant.Length > 0)
1037 {
1038 foreach (string viewer in grant.Split('|'))
1039 {
1040 m_BannedViewers.Add(viewer.Trim().ToLower());
1041 }
1042 }
1043
1044 if (startupConfig.Contains("MinFrameTime"))
1045 MinFrameTicks = (int)(startupConfig.GetFloat("MinFrameTime") * 1000);
1046
1047 m_update_backup = startupConfig.GetInt( "UpdateStorageEveryNFrames", m_update_backup);
1048 m_update_coarse_locations = startupConfig.GetInt( "UpdateCoarseLocationsEveryNFrames", m_update_coarse_locations);
1049 m_update_entitymovement = startupConfig.GetInt( "UpdateEntityMovementEveryNFrames", m_update_entitymovement);
1050 m_update_events = startupConfig.GetInt( "UpdateEventsEveryNFrames", m_update_events);
1051 m_update_objects = startupConfig.GetInt( "UpdateObjectsEveryNFrames", m_update_objects);
1052 m_update_physics = startupConfig.GetInt( "UpdatePhysicsEveryNFrames", m_update_physics);
1053 m_update_presences = startupConfig.GetInt( "UpdateAgentsEveryNFrames", m_update_presences);
1054 m_update_terrain = startupConfig.GetInt( "UpdateTerrainEveryNFrames", m_update_terrain);
1055 m_update_temp_cleaning = startupConfig.GetInt( "UpdateTempCleaningEveryNSeconds", m_update_temp_cleaning);
1056 }
1057
1058 // FIXME: Ultimately this should be in a module.
1059 SendPeriodicAppearanceUpdates = false;
1060
1061 IConfig appearanceConfig = m_config.Configs["Appearance"];
1062 if (appearanceConfig != null)
1063 {
1064 SendPeriodicAppearanceUpdates
1065 = appearanceConfig.GetBoolean("ResendAppearanceUpdates", SendPeriodicAppearanceUpdates);
1066 }
1067
1068 #endregion Region Config
1069
1070 IConfig entityTransferConfig = m_config.Configs["EntityTransfer"];
1071 if (entityTransferConfig != null)
1072 {
1073 AllowAvatarCrossing = entityTransferConfig.GetBoolean("AllowAvatarCrossing", AllowAvatarCrossing);
1074 }
1075
1076 #region Interest Management
1077
1078 IConfig interestConfig = m_config.Configs["InterestManagement"];
1079 if (interestConfig != null)
1080 {
1081 string update_prioritization_scheme = interestConfig.GetString("UpdatePrioritizationScheme", "Time").Trim().ToLower();
1082
1083 try
1084 {
1085 UpdatePrioritizationScheme = (UpdatePrioritizationSchemes)Enum.Parse(typeof(UpdatePrioritizationSchemes), update_prioritization_scheme, true);
1086 }
1087 catch (Exception)
1088 {
1089 m_log.Warn("[PRIORITIZER]: UpdatePrioritizationScheme was not recognized, setting to default prioritizer Time");
1090 UpdatePrioritizationScheme = UpdatePrioritizationSchemes.Time;
1091 }
1092
1093 IsReprioritizationEnabled
1094 = interestConfig.GetBoolean("ReprioritizationEnabled", IsReprioritizationEnabled);
1095 ReprioritizationInterval
1096 = interestConfig.GetDouble("ReprioritizationInterval", ReprioritizationInterval);
1097 RootReprioritizationDistance
1098 = interestConfig.GetDouble("RootReprioritizationDistance", RootReprioritizationDistance);
1099 ChildReprioritizationDistance
1100 = interestConfig.GetDouble("ChildReprioritizationDistance", ChildReprioritizationDistance);
1101
1102 RootTerseUpdatePeriod = interestConfig.GetInt("RootTerseUpdatePeriod", RootTerseUpdatePeriod);
1103 ChildTerseUpdatePeriod = interestConfig.GetInt("ChildTerseUpdatePeriod", ChildTerseUpdatePeriod);
1104
1105 RootPositionUpdateTolerance
1106 = interestConfig.GetFloat("RootPositionUpdateTolerance", RootPositionUpdateTolerance);
1107 RootRotationUpdateTolerance
1108 = interestConfig.GetFloat("RootRotationUpdateTolerance", RootRotationUpdateTolerance);
1109 RootVelocityUpdateTolerance
1110 = interestConfig.GetFloat("RootVelocityUpdateTolerance", RootVelocityUpdateTolerance);
1111 }
1112
1113 m_log.DebugFormat("[SCENE]: Using the {0} prioritization scheme", UpdatePrioritizationScheme);
1114
1115 #endregion Interest Management
1116 984
1117 // The timer used by the Stopwatch class depends on the system hardware and operating system; inform 985 string[] possibleMapConfigSections = new string[] { "Map", "Startup" };
1118 // if the timer is based on a high-resolution performance counter or based on the system timer;
1119 // the performance counter will provide a more precise time than the system timer
1120 if (Stopwatch.IsHighResolution)
1121 m_log.InfoFormat("[SCENE]: Using high-resolution performance counter for statistics.");
1122 else
1123 m_log.InfoFormat("[SCENE]: Using system timer for statistics.");
1124 986
1125 // Acquire the statistics section of the OpenSim.ini file located 987 m_generateMaptiles
1126 // in the bin directory 988 = Util.GetConfigVarFromSections<bool>(config, "GenerateMaptiles", possibleMapConfigSections, true);
1127 IConfig statisticsConfig = m_config.Configs["Statistics"];
1128 989
1129 // Confirm that the statistics section existed in the configuration 990 if (m_generateMaptiles)
1130 // file
1131 if (statisticsConfig != null)
1132 { 991 {
1133 // Create the StatsReporter using the number of frames to store 992 int maptileRefresh = Util.GetConfigVarFromSections<int>(config, "MaptileRefresh", possibleMapConfigSections, 0);
1134 // for the frame time statistics, or 10 frames if the config 993 m_log.InfoFormat("[SCENE]: Region {0}, WORLD MAP refresh time set to {1} seconds", RegionInfo.RegionName, maptileRefresh);
1135 // file doesn't contain a value 994 if (maptileRefresh != 0)
1136 StatsReporter = new SimStatsReporter(this, 995 {
1137 statisticsConfig.GetInt("NumberOfFrames", 10)); 996 m_mapGenerationTimer.Interval = maptileRefresh * 1000;
997 m_mapGenerationTimer.Elapsed += RegenerateMaptileAndReregister;
998 m_mapGenerationTimer.AutoReset = true;
999 m_mapGenerationTimer.Start();
1000 }
1138 } 1001 }
1139 else 1002 else
1140 { 1003 {
1141 // Create a StatsReporter with the current scene and a default 1004 string tile
1142 // 10 frames stored for the frame time statistics 1005 = Util.GetConfigVarFromSections<string>(
1143 StatsReporter = new SimStatsReporter(this); 1006 config, "MaptileStaticUUID", possibleMapConfigSections, UUID.Zero.ToString());
1007
1008 UUID tileID;
1009
1010 if (tile != UUID.Zero.ToString() && UUID.TryParse(tile, out tileID))
1011 {
1012 RegionInfo.RegionSettings.TerrainImageID = tileID;
1013 }
1014 else
1015 {
1016 RegionInfo.RegionSettings.TerrainImageID = RegionInfo.MaptileStaticUUID;
1017 m_log.InfoFormat("[SCENE]: Region {0}, maptile set to {1}", RegionInfo.RegionName, RegionInfo.MaptileStaticUUID.ToString());
1018 }
1144 } 1019 }
1145 1020
1146 StatsReporter.OnSendStatsResult += SendSimStatsPackets; 1021 string[] possibleAccessControlConfigSections = new string[] { "AccessControl", "Startup" };
1147 StatsReporter.OnStatsIncorrect += m_sceneGraph.RecalculateStats;
1148 1022
1149 } 1023 string grant
1024 = Util.GetConfigVarFromSections<string>(
1025 config, "AllowedClients", possibleAccessControlConfigSections, "");
1150 1026
1151 public Scene(RegionInfo regInfo, PhysicsScene physicsScene) : base(regInfo) 1027 if (grant.Length > 0)
1152 { 1028 {
1153 m_sceneGraph = new SceneGraph(this); 1029 foreach (string viewer in grant.Split('|'))
1154 m_sceneGraph.PhysicsScene = physicsScene; 1030 {
1031 m_AllowedViewers.Add(viewer.Trim().ToLower());
1032 }
1033 }
1155 1034
1156 // If the scene graph has an Unrecoverable error, restart this sim. 1035 grant
1157 // Currently the only thing that causes it to happen is two kinds of specific 1036 = Util.GetConfigVarFromSections<string>(
1158 // Physics based crashes. 1037 config, "BannedClients", possibleAccessControlConfigSections, "");
1159 // 1038
1160 // Out of memory 1039 if (grant.Length > 0)
1161 // Operating system has killed the plugin
1162 m_sceneGraph.UnRecoverableError
1163 += () =>
1164 {
1165 m_log.ErrorFormat("[SCENE]: Restarting region {0} due to unrecoverable physics crash", Name);
1166 RestartNow();
1167 };
1168
1169 PhysicalPrims = true;
1170 CollidablePrims = true;
1171 PhysicsEnabled = true;
1172
1173 AllowAvatarCrossing = true;
1174
1175 PeriodicBackup = true;
1176 UseBackup = true;
1177
1178 IsReprioritizationEnabled = true;
1179 UpdatePrioritizationScheme = UpdatePrioritizationSchemes.Time;
1180 ReprioritizationInterval = 5000;
1181
1182 RootRotationUpdateTolerance = 0.1f;
1183 RootVelocityUpdateTolerance = 0.001f;
1184 RootPositionUpdateTolerance = 0.05f;
1185 RootReprioritizationDistance = 10.0;
1186 ChildReprioritizationDistance = 20.0;
1187
1188 m_eventManager = new EventManager();
1189
1190 m_permissions = new ScenePermissions(this);
1191 }
1192
1193 #endregion
1194
1195 #region Startup / Close Methods
1196
1197 /// <value>
1198 /// The scene graph for this scene
1199 /// </value>
1200 /// TODO: Possibly stop other classes being able to manipulate this directly.
1201 public SceneGraph SceneGraph
1202 {
1203 get { return m_sceneGraph; }
1204 }
1205
1206 protected virtual void RegisterDefaultSceneEvents()
1207 {
1208 IDialogModule dm = RequestModuleInterface<IDialogModule>();
1209
1210 if (dm != null)
1211 m_eventManager.OnPermissionError += dm.SendAlertToUser;
1212
1213 m_eventManager.OnSignificantClientMovement += HandleOnSignificantClientMovement;
1214 }
1215
1216 public override string GetSimulatorVersion()
1217 {
1218 return m_simulatorVersion;
1219 }
1220
1221 /// <summary>
1222 /// Process the fact that a neighbouring region has come up.
1223 /// </summary>
1224 /// <remarks>
1225 /// We only add it to the neighbor list if it's within 1 region from here.
1226 /// Agents may have draw distance values that cross two regions though, so
1227 /// we add it to the notify list regardless of distance. We'll check
1228 /// the agent's draw distance before notifying them though.
1229 /// </remarks>
1230 /// <param name="otherRegion">RegionInfo handle for the new region.</param>
1231 /// <returns>True after all operations complete, throws exceptions otherwise.</returns>
1232 public override void OtherRegionUp(GridRegion otherRegion)
1233 {
1234 if (RegionInfo.RegionHandle != otherRegion.RegionHandle)
1235 {
1236 //// If these are cast to INT because long + negative values + abs returns invalid data
1237 //int resultX = Math.Abs((int)xcell - (int)RegionInfo.RegionLocX);
1238 //int resultY = Math.Abs((int)ycell - (int)RegionInfo.RegionLocY);
1239 //if (resultX <= 1 && resultY <= 1)
1240 float dist = (float)Math.Max(DefaultDrawDistance,
1241 (float)Math.Max(RegionInfo.RegionSizeX, RegionInfo.RegionSizeY));
1242 uint newRegionX, newRegionY, thisRegionX, thisRegionY;
1243 Util.RegionHandleToRegionLoc(otherRegion.RegionHandle, out newRegionX, out newRegionY);
1244 Util.RegionHandleToRegionLoc(RegionInfo.RegionHandle, out thisRegionX, out thisRegionY);
1245
1246 //m_log.InfoFormat("[SCENE]: (on region {0}): Region {1} up in coords {2}-{3}",
1247 // RegionInfo.RegionName, otherRegion.RegionName, newRegionX, newRegionY);
1248
1249 if (!Util.IsOutsideView(dist, thisRegionX, newRegionX, thisRegionY, newRegionY))
1250 {
1251 // Let the grid service module know, so this can be cached
1252 m_eventManager.TriggerOnRegionUp(otherRegion);
1253
1254 try
1255 {
1256 ForEachRootScenePresence(delegate(ScenePresence agent)
1257 {
1258 //agent.ControllingClient.new
1259 //this.CommsManager.InterRegion.InformRegionOfChildAgent(otherRegion.RegionHandle, agent.ControllingClient.RequestClientInfo());
1260
1261 List<ulong> old = new List<ulong>();
1262 old.Add(otherRegion.RegionHandle);
1263 agent.DropOldNeighbours(old);
1264 if (EntityTransferModule != null && agent.PresenceType != PresenceType.Npc)
1265 EntityTransferModule.EnableChildAgent(agent, otherRegion);
1266 });
1267 }
1268 catch (NullReferenceException)
1269 {
1270 // This means that we're not booted up completely yet.
1271 // This shouldn't happen too often anymore.
1272 m_log.Error("[SCENE]: Couldn't inform client of regionup because we got a null reference exception");
1273 }
1274 }
1275 else
1276 {
1277 m_log.InfoFormat(
1278 "[SCENE]: Got notice about far away Region: {0} at ({1}, {2})",
1279 otherRegion.RegionName, otherRegion.RegionLocX, otherRegion.RegionLocY);
1280 }
1281 }
1282 }
1283
1284 public void AddNeighborRegion(RegionInfo region)
1285 {
1286 lock (m_neighbours)
1287 {
1288 if (!CheckNeighborRegion(region))
1289 {
1290 m_neighbours.Add(region);
1291 }
1292 }
1293 }
1294
1295 public bool CheckNeighborRegion(RegionInfo region)
1296 {
1297 bool found = false;
1298 lock (m_neighbours)
1299 {
1300 foreach (RegionInfo reg in m_neighbours)
1301 {
1302 if (reg.RegionHandle == region.RegionHandle)
1303 {
1304 found = true;
1305 break;
1306 }
1307 }
1308 }
1309 return found;
1310 }
1311
1312 // Alias IncomingHelloNeighbour OtherRegionUp, for now
1313 public GridRegion IncomingHelloNeighbour(RegionInfo neighbour)
1314 {
1315 OtherRegionUp(new GridRegion(neighbour));
1316 return new GridRegion(RegionInfo);
1317 }
1318
1319 // This causes the region to restart immediatley.
1320 public void RestartNow()
1321 {
1322 IConfig startupConfig = m_config.Configs["Startup"];
1323 if (startupConfig != null)
1324 { 1040 {
1325 if (startupConfig.GetBoolean("InworldRestartShutsDown", false)) 1041 foreach (string viewer in grant.Split('|'))
1326 { 1042 {
1327 MainConsole.Instance.RunCommand("shutdown"); 1043 m_BannedViewers.Add(viewer.Trim().ToLower());
1328 return; 1044 }
1329 }
1330 } 1045 }
1331 1046
1332 m_log.InfoFormat("[REGION]: Restarting region {0}", Name); 1047 if (startupConfig.Contains("MinFrameTime"))
1048 MinFrameTicks = (int)(startupConfig.GetFloat("MinFrameTime") * 1000);
1333 1049
1334 Close(); 1050 m_update_backup = startupConfig.GetInt("UpdateStorageEveryNFrames", m_update_backup);
1051 m_update_coarse_locations = startupConfig.GetInt("UpdateCoarseLocationsEveryNFrames", m_update_coarse_locations);
1052 m_update_entitymovement = startupConfig.GetInt("UpdateEntityMovementEveryNFrames", m_update_entitymovement);
1053 m_update_events = startupConfig.GetInt("UpdateEventsEveryNFrames", m_update_events);
1054 m_update_objects = startupConfig.GetInt("UpdateObjectsEveryNFrames", m_update_objects);
1055 m_update_physics = startupConfig.GetInt("UpdatePhysicsEveryNFrames", m_update_physics);
1056 m_update_presences = startupConfig.GetInt("UpdateAgentsEveryNFrames", m_update_presences);
1057 m_update_terrain = startupConfig.GetInt("UpdateTerrainEveryNFrames", m_update_terrain);
1058 m_update_temp_cleaning = startupConfig.GetInt("UpdateTempCleaningEveryNSeconds", m_update_temp_cleaning);
1059 }
1335 1060
1336 base.Restart(); 1061 // FIXME: Ultimately this should be in a module.
1337 } 1062 SendPeriodicAppearanceUpdates = false;
1338 1063
1339 // This is a helper function that notifies root agents in this region that a new sim near them has come up 1064 IConfig appearanceConfig = m_config.Configs["Appearance"];
1340 // This is in the form of a timer because when an instance of OpenSim.exe is started, 1065 if (appearanceConfig != null)
1341 // Even though the sims initialize, they don't listen until 'all of the sims are initialized' 1066 {
1342 // If we tell an agent about a sim that's not listening yet, the agent will not be able to connect to it. 1067 SendPeriodicAppearanceUpdates
1343 // subsequently the agent will never see the region come back online. 1068 = appearanceConfig.GetBoolean("ResendAppearanceUpdates", SendPeriodicAppearanceUpdates);
1344 public void RestartNotifyWaitElapsed(object sender, ElapsedEventArgs e) 1069 }
1345 {
1346 m_restartWaitTimer.Stop();
1347 lock (m_regionRestartNotifyList)
1348 {
1349 foreach (RegionInfo region in m_regionRestartNotifyList)
1350 {
1351 GridRegion r = new GridRegion(region);
1352 try
1353 {
1354 ForEachRootScenePresence(delegate(ScenePresence agent)
1355 {
1356 if (EntityTransferModule != null && agent.PresenceType != PresenceType.Npc)
1357 EntityTransferModule.EnableChildAgent(agent, r);
1358 });
1359 }
1360 catch (NullReferenceException)
1361 {
1362 // This means that we're not booted up completely yet.
1363 // This shouldn't happen too often anymore.
1364 }
1365 }
1366 1070
1367 // Reset list to nothing. 1071 #endregion Region Config
1368 m_regionRestartNotifyList.Clear(); 1072
1369 } 1073 IConfig entityTransferConfig = m_config.Configs["EntityTransfer"];
1370 } 1074 if (entityTransferConfig != null)
1075 {
1076 AllowAvatarCrossing = entityTransferConfig.GetBoolean("AllowAvatarCrossing", AllowAvatarCrossing);
1077 }
1078
1079 #region Interest Management
1371 1080
1372 public int GetInaccurateNeighborCount() 1081 IConfig interestConfig = m_config.Configs["InterestManagement"];
1373 { 1082 if (interestConfig != null)
1374 return m_neighbours.Count; 1083 {
1375 } 1084 string update_prioritization_scheme = interestConfig.GetString("UpdatePrioritizationScheme", "Time").Trim().ToLower();
1376 1085
1377 // This is the method that shuts down the scene. 1086 try
1378 public override void Close()
1379 {
1380 if (m_shuttingDown)
1381 { 1087 {
1382 m_log.WarnFormat("[SCENE]: Ignoring close request because already closing {0}", Name); 1088 UpdatePrioritizationScheme = (UpdatePrioritizationSchemes)Enum.Parse(typeof(UpdatePrioritizationSchemes), update_prioritization_scheme, true);
1383 return; 1089 }
1090 catch (Exception)
1091 {
1092 m_log.Warn("[PRIORITIZER]: UpdatePrioritizationScheme was not recognized, setting to default prioritizer Time");
1093 UpdatePrioritizationScheme = UpdatePrioritizationSchemes.Time;
1094 }
1095
1096 IsReprioritizationEnabled
1097 = interestConfig.GetBoolean("ReprioritizationEnabled", IsReprioritizationEnabled);
1098 ReprioritizationInterval
1099 = interestConfig.GetDouble("ReprioritizationInterval", ReprioritizationInterval);
1100 RootReprioritizationDistance
1101 = interestConfig.GetDouble("RootReprioritizationDistance", RootReprioritizationDistance);
1102 ChildReprioritizationDistance
1103 = interestConfig.GetDouble("ChildReprioritizationDistance", ChildReprioritizationDistance);
1104
1105 RootTerseUpdatePeriod = interestConfig.GetInt("RootTerseUpdatePeriod", RootTerseUpdatePeriod);
1106 ChildTerseUpdatePeriod = interestConfig.GetInt("ChildTerseUpdatePeriod", ChildTerseUpdatePeriod);
1107
1108 RootPositionUpdateTolerance
1109 = interestConfig.GetFloat("RootPositionUpdateTolerance", RootPositionUpdateTolerance);
1110 RootRotationUpdateTolerance
1111 = interestConfig.GetFloat("RootRotationUpdateTolerance", RootRotationUpdateTolerance);
1112 RootVelocityUpdateTolerance
1113 = interestConfig.GetFloat("RootVelocityUpdateTolerance", RootVelocityUpdateTolerance);
1114 }
1115
1116 m_log.DebugFormat("[SCENE]: Using the {0} prioritization scheme", UpdatePrioritizationScheme);
1117
1118 #endregion Interest Management
1119
1120 // The timer used by the Stopwatch class depends on the system hardware and operating system; inform
1121 // if the timer is based on a high-resolution performance counter or based on the system timer;
1122 // the performance counter will provide a more precise time than the system timer
1123 if (Stopwatch.IsHighResolution)
1124 m_log.InfoFormat("[SCENE]: Using high-resolution performance counter for statistics.");
1125 else
1126 m_log.InfoFormat("[SCENE]: Using system timer for statistics.");
1127
1128 // Acquire the statistics section of the OpenSim.ini file located
1129 // in the bin directory
1130 IConfig statisticsConfig = m_config.Configs["Statistics"];
1131
1132 // Confirm that the statistics section existed in the configuration
1133 // file
1134 if (statisticsConfig != null)
1135 {
1136 // Create the StatsReporter using the number of frames to store
1137 // for the frame time statistics, or 10 frames if the config
1138 // file doesn't contain a value
1139 StatsReporter = new SimStatsReporter(this,
1140 statisticsConfig.GetInt("NumberOfFrames", 10));
1141 }
1142 else
1143 {
1144 // Create a StatsReporter with the current scene and a default
1145 // 10 frames stored for the frame time statistics
1146 StatsReporter = new SimStatsReporter(this);
1147 }
1148
1149 StatsReporter.OnSendStatsResult += SendSimStatsPackets;
1150 StatsReporter.OnStatsIncorrect += m_sceneGraph.RecalculateStats;
1151
1152 }
1153
1154 public Scene(RegionInfo regInfo, PhysicsScene physicsScene)
1155 : base(regInfo)
1156 {
1157 m_sceneGraph = new SceneGraph(this);
1158 m_sceneGraph.PhysicsScene = physicsScene;
1159
1160 // If the scene graph has an Unrecoverable error, restart this sim.
1161 // Currently the only thing that causes it to happen is two kinds of specific
1162 // Physics based crashes.
1163 //
1164 // Out of memory
1165 // Operating system has killed the plugin
1166 m_sceneGraph.UnRecoverableError
1167 += () =>
1168 {
1169 m_log.ErrorFormat("[SCENE]: Restarting region {0} due to unrecoverable physics crash", Name);
1170 RestartNow();
1171 };
1172
1173 PhysicalPrims = true;
1174 CollidablePrims = true;
1175 PhysicsEnabled = true;
1176
1177 AllowAvatarCrossing = true;
1178
1179 PeriodicBackup = true;
1180 UseBackup = true;
1181
1182 IsReprioritizationEnabled = true;
1183 UpdatePrioritizationScheme = UpdatePrioritizationSchemes.Time;
1184 ReprioritizationInterval = 5000;
1185
1186 RootRotationUpdateTolerance = 0.1f;
1187 RootVelocityUpdateTolerance = 0.001f;
1188 RootPositionUpdateTolerance = 0.05f;
1189 RootReprioritizationDistance = 10.0;
1190 ChildReprioritizationDistance = 20.0;
1191
1192 m_eventManager = new EventManager();
1193
1194 m_permissions = new ScenePermissions(this);
1195 }
1196
1197 #endregion
1198
1199 #region Startup / Close Methods
1200
1201 /// <value>
1202 /// The scene graph for this scene
1203 /// </value>
1204 /// TODO: Possibly stop other classes being able to manipulate this directly.
1205 public SceneGraph SceneGraph
1206 {
1207 get { return m_sceneGraph; }
1208 }
1209
1210 protected virtual void RegisterDefaultSceneEvents()
1211 {
1212 IDialogModule dm = RequestModuleInterface<IDialogModule>();
1213
1214 if (dm != null)
1215 m_eventManager.OnPermissionError += dm.SendAlertToUser;
1216
1217 m_eventManager.OnSignificantClientMovement += HandleOnSignificantClientMovement;
1218 }
1219
1220 public override string GetSimulatorVersion()
1221 {
1222 return m_simulatorVersion;
1223 }
1224
1225 /// <summary>
1226 /// Process the fact that a neighbouring region has come up.
1227 /// </summary>
1228 /// <remarks>
1229 /// We only add it to the neighbor list if it's within 1 region from here.
1230 /// Agents may have draw distance values that cross two regions though, so
1231 /// we add it to the notify list regardless of distance. We'll check
1232 /// the agent's draw distance before notifying them though.
1233 /// </remarks>
1234 /// <param name="otherRegion">RegionInfo handle for the new region.</param>
1235 /// <returns>True after all operations complete, throws exceptions otherwise.</returns>
1236 public override void OtherRegionUp(GridRegion otherRegion)
1237 {
1238 if (RegionInfo.RegionHandle != otherRegion.RegionHandle)
1239 {
1240 //// If these are cast to INT because long + negative values + abs returns invalid data
1241 //int resultX = Math.Abs((int)xcell - (int)RegionInfo.RegionLocX);
1242 //int resultY = Math.Abs((int)ycell - (int)RegionInfo.RegionLocY);
1243 //if (resultX <= 1 && resultY <= 1)
1244 float dist = (float)Math.Max(DefaultDrawDistance,
1245 (float)Math.Max(RegionInfo.RegionSizeX, RegionInfo.RegionSizeY));
1246 uint newRegionX, newRegionY, thisRegionX, thisRegionY;
1247 Util.RegionHandleToRegionLoc(otherRegion.RegionHandle, out newRegionX, out newRegionY);
1248 Util.RegionHandleToRegionLoc(RegionInfo.RegionHandle, out thisRegionX, out thisRegionY);
1249
1250 //m_log.InfoFormat("[SCENE]: (on region {0}): Region {1} up in coords {2}-{3}",
1251 // RegionInfo.RegionName, otherRegion.RegionName, newRegionX, newRegionY);
1252
1253 if (!Util.IsOutsideView(dist, thisRegionX, newRegionX, thisRegionY, newRegionY))
1254 {
1255 // Let the grid service module know, so this can be cached
1256 m_eventManager.TriggerOnRegionUp(otherRegion);
1257
1258 try
1259 {
1260 ForEachRootScenePresence(delegate(ScenePresence agent)
1261 {
1262 //agent.ControllingClient.new
1263 //this.CommsManager.InterRegion.InformRegionOfChildAgent(otherRegion.RegionHandle, agent.ControllingClient.RequestClientInfo());
1264
1265 List<ulong> old = new List<ulong>();
1266 old.Add(otherRegion.RegionHandle);
1267 agent.DropOldNeighbours(old);
1268 if (EntityTransferModule != null && agent.PresenceType != PresenceType.Npc)
1269 EntityTransferModule.EnableChildAgent(agent, otherRegion);
1270 });
1271 }
1272 catch (NullReferenceException)
1273 {
1274 // This means that we're not booted up completely yet.
1275 // This shouldn't happen too often anymore.
1276 m_log.Error("[SCENE]: Couldn't inform client of regionup because we got a null reference exception");
1277 }
1384 } 1278 }
1279 else
1280 {
1281 m_log.InfoFormat(
1282 "[SCENE]: Got notice about far away Region: {0} at ({1}, {2})",
1283 otherRegion.RegionName, otherRegion.RegionLocX, otherRegion.RegionLocY);
1284 }
1285 }
1286 }
1287
1288 public void AddNeighborRegion(RegionInfo region)
1289 {
1290 lock (m_neighbours)
1291 {
1292 if (!CheckNeighborRegion(region))
1293 {
1294 m_neighbours.Add(region);
1295 }
1296 }
1297 }
1298
1299 public bool CheckNeighborRegion(RegionInfo region)
1300 {
1301 bool found = false;
1302 lock (m_neighbours)
1303 {
1304 foreach (RegionInfo reg in m_neighbours)
1305 {
1306 if (reg.RegionHandle == region.RegionHandle)
1307 {
1308 found = true;
1309 break;
1310 }
1311 }
1312 }
1313 return found;
1314 }
1315
1316 // Alias IncomingHelloNeighbour OtherRegionUp, for now
1317 public GridRegion IncomingHelloNeighbour(RegionInfo neighbour)
1318 {
1319 OtherRegionUp(new GridRegion(neighbour));
1320 return new GridRegion(RegionInfo);
1321 }
1322
1323 // This causes the region to restart immediatley.
1324 public void RestartNow()
1325 {
1326 IConfig startupConfig = m_config.Configs["Startup"];
1327 if (startupConfig != null)
1328 {
1329 if (startupConfig.GetBoolean("InworldRestartShutsDown", false))
1330 {
1331 MainConsole.Instance.RunCommand("shutdown");
1332 return;
1333 }
1334 }
1335
1336 m_log.InfoFormat("[REGION]: Restarting region {0}", Name);
1337
1338 Close();
1339
1340 base.Restart();
1341 }
1342
1343 // This is a helper function that notifies root agents in this region that a new sim near them has come up
1344 // This is in the form of a timer because when an instance of OpenSim.exe is started,
1345 // Even though the sims initialize, they don't listen until 'all of the sims are initialized'
1346 // If we tell an agent about a sim that's not listening yet, the agent will not be able to connect to it.
1347 // subsequently the agent will never see the region come back online.
1348 public void RestartNotifyWaitElapsed(object sender, ElapsedEventArgs e)
1349 {
1350 m_restartWaitTimer.Stop();
1351 lock (m_regionRestartNotifyList)
1352 {
1353 foreach (RegionInfo region in m_regionRestartNotifyList)
1354 {
1355 GridRegion r = new GridRegion(region);
1356 try
1357 {
1358 ForEachRootScenePresence(delegate(ScenePresence agent)
1359 {
1360 if (EntityTransferModule != null && agent.PresenceType != PresenceType.Npc)
1361 EntityTransferModule.EnableChildAgent(agent, r);
1362 });
1363 }
1364 catch (NullReferenceException)
1365 {
1366 // This means that we're not booted up completely yet.
1367 // This shouldn't happen too often anymore.
1368 }
1369 }
1370
1371 // Reset list to nothing.
1372 m_regionRestartNotifyList.Clear();
1373 }
1374 }
1375
1376 public int GetInaccurateNeighborCount()
1377 {
1378 return m_neighbours.Count;
1379 }
1380
1381 // This is the method that shuts down the scene.
1382 public override void Close()
1383 {
1384 if (m_shuttingDown)
1385 {
1386 m_log.WarnFormat("[SCENE]: Ignoring close request because already closing {0}", Name);
1387 return;
1388 }
1389
1390 m_log.InfoFormat("[SCENE]: Closing down the single simulator: {0}", RegionInfo.RegionName);
1391
1392 StatsReporter.Close();
1393
1394 m_restartTimer.Stop();
1395 m_restartTimer.Close();
1396
1397 // Kick all ROOT agents with the message, 'The simulator is going down'
1398 ForEachScenePresence(delegate(ScenePresence avatar)
1399 {
1400 avatar.RemoveNeighbourRegion(RegionInfo.RegionHandle);
1401
1402 if (!avatar.IsChildAgent)
1403 avatar.ControllingClient.Kick("The simulator is going down.");
1404
1405 avatar.ControllingClient.SendShutdownConnectionNotice();
1406 });
1407
1408 // Stop updating the scene objects and agents.
1409 m_shuttingDown = true;
1410
1411 // Wait here, or the kick messages won't actually get to the agents before the scene terminates.
1412 // We also need to wait to avoid a race condition with the scene update loop which might not yet
1413 // have checked ShuttingDown.
1414 Thread.Sleep(500);
1415
1416 // Stop all client threads.
1417 ForEachScenePresence(delegate(ScenePresence avatar) { CloseAgent(avatar.UUID, false); });
1418
1419 m_log.Debug("[SCENE]: Persisting changed objects");
1420 EventManager.TriggerSceneShuttingDown(this);
1421 Backup(false);
1422 m_sceneGraph.Close();
1423
1424 if (!GridService.DeregisterRegion(RegionInfo.RegionID))
1425 m_log.WarnFormat("[SCENE]: Deregister from grid failed for region {0}", Name);
1426
1427 base.Close();
1428
1429 // XEngine currently listens to the EventManager.OnShutdown event to trigger script stop and persistence.
1430 // Therefore. we must dispose of the PhysicsScene after this to prevent a window where script code can
1431 // attempt to reference a null or disposed physics scene.
1432 if (PhysicsScene != null)
1433 {
1434 PhysicsScene phys = PhysicsScene;
1435 // remove the physics engine from both Scene and SceneGraph
1436 PhysicsScene = null;
1437 phys.Dispose();
1438 phys = null;
1439 }
1440 }
1441
1442 public override void Start()
1443 {
1444 Start(true);
1445 }
1446
1447 /// <summary>
1448 /// Start the scene
1449 /// </summary>
1450 /// <param name='startScripts'>
1451 /// Start the scripts within the scene.
1452 /// </param>
1453 public void Start(bool startScripts)
1454 {
1455 if (IsRunning)
1456 return;
1457
1458 m_isRunning = true;
1459 m_active = true;
1460
1461 // m_log.DebugFormat("[SCENE]: Starting Heartbeat timer for {0}", RegionInfo.RegionName);
1462 if (m_heartbeatThread != null)
1463 {
1464 m_heartbeatThread.Abort();
1465 m_heartbeatThread = null;
1466 }
1467
1468 m_heartbeatThread
1469 = WorkManager.StartThread(
1470 Heartbeat, string.Format("Heartbeat-({0})", RegionInfo.RegionName.Replace(" ", "_")), ThreadPriority.Normal, false, false);
1471
1472 StartScripts();
1473 }
1474
1475 /// <summary>
1476 /// Sets up references to modules required by the scene
1477 /// </summary>
1478 public void SetModuleInterfaces()
1479 {
1480 m_xmlrpcModule = RequestModuleInterface<IXMLRPC>();
1481 m_worldCommModule = RequestModuleInterface<IWorldComm>();
1482 XferManager = RequestModuleInterface<IXfer>();
1483 m_AvatarFactory = RequestModuleInterface<IAvatarFactoryModule>();
1484 AttachmentsModule = RequestModuleInterface<IAttachmentsModule>();
1485 m_serialiser = RequestModuleInterface<IRegionSerialiserModule>();
1486 m_dialogModule = RequestModuleInterface<IDialogModule>();
1487 m_capsModule = RequestModuleInterface<ICapabilitiesModule>();
1488 EntityTransferModule = RequestModuleInterface<IEntityTransferModule>();
1489 m_groupsModule = RequestModuleInterface<IGroupsModule>();
1490 AgentTransactionsModule = RequestModuleInterface<IAgentAssetTransactions>();
1491 UserManagementModule = RequestModuleInterface<IUserManagement>();
1492 }
1493
1494 #endregion
1495
1496 #region Update Methods
1497
1498 /// <summary>
1499 /// Activate the various loops necessary to continually update the scene.
1500 /// </summary>
1501 private void Heartbeat()
1502 {
1503 m_eventManager.TriggerOnRegionStarted(this);
1504
1505 // The first frame can take a very long time due to physics actors being added on startup. Therefore,
1506 // don't turn on the watchdog alarm for this thread until the second frame, in order to prevent false
1507 // alarms for scenes with many objects.
1508 Update(1);
1509
1510 WorkManager.StartThread(
1511 Maintenance, string.Format("Maintenance ({0})", RegionInfo.RegionName), ThreadPriority.Normal, false, true);
1512
1513 Watchdog.GetCurrentThreadInfo().AlarmIfTimeout = true;
1514 m_lastFrameTick = Util.EnvironmentTickCount();
1515
1516 if (UpdateOnTimer)
1517 {
1518 m_sceneUpdateTimer = new Timer(MinFrameTicks);
1519 m_sceneUpdateTimer.AutoReset = true;
1520 m_sceneUpdateTimer.Elapsed += Update;
1521 m_sceneUpdateTimer.Start();
1522 }
1523 else
1524 {
1525 Thread.CurrentThread.Priority = ThreadPriority.Highest;
1526 Update(-1);
1527 Watchdog.RemoveThread();
1528 m_isRunning = false;
1529 }
1530 }
1385 1531
1386 m_log.InfoFormat("[SCENE]: Closing down the single simulator: {0}", RegionInfo.RegionName); 1532 private volatile bool m_isTimerUpdateRunning;
1387 1533
1388 StatsReporter.Close(); 1534 private void Update(object sender, ElapsedEventArgs e)
1535 {
1536 if (m_isTimerUpdateRunning)
1537 return;
1389 1538
1390 m_restartTimer.Stop(); 1539 m_isTimerUpdateRunning = true;
1391 m_restartTimer.Close();
1392 1540
1393 // Kick all ROOT agents with the message, 'The simulator is going down' 1541 // If the last frame did not complete on time, then immediately start the next update on the same thread
1394 ForEachScenePresence(delegate(ScenePresence avatar) 1542 // and ignore further timed updates until we have a frame that had spare time.
1395 { 1543 while (!Update(1) && Active) { }
1396 avatar.RemoveNeighbourRegion(RegionInfo.RegionHandle);
1397 1544
1398 if (!avatar.IsChildAgent) 1545 if (!Active || m_shuttingDown)
1399 avatar.ControllingClient.Kick("The simulator is going down."); 1546 {
1547 m_sceneUpdateTimer.Stop();
1548 m_sceneUpdateTimer = null;
1549 m_isRunning = false;
1550 }
1400 1551
1401 avatar.ControllingClient.SendShutdownConnectionNotice(); 1552 m_isTimerUpdateRunning = false;
1402 }); 1553 }
1403 1554
1404 // Stop updating the scene objects and agents. 1555 private void Maintenance()
1405 m_shuttingDown = true; 1556 {
1557 DoMaintenance(-1);
1406 1558
1407 // Wait here, or the kick messages won't actually get to the agents before the scene terminates. 1559 Watchdog.RemoveThread();
1408 // We also need to wait to avoid a race condition with the scene update loop which might not yet 1560 }
1409 // have checked ShuttingDown.
1410 Thread.Sleep(500);
1411 1561
1412 // Stop all client threads. 1562 public void DoMaintenance(int runs)
1413 ForEachScenePresence(delegate(ScenePresence avatar) { CloseAgent(avatar.UUID, false); }); 1563 {
1564 long? endRun = null;
1565 int runtc, tmpMS;
1566 int previousMaintenanceTick;
1414 1567
1415 m_log.Debug("[SCENE]: Persisting changed objects"); 1568 if (runs >= 0)
1416 EventManager.TriggerSceneShuttingDown(this); 1569 endRun = MaintenanceRun + runs;
1417 Backup(false);
1418 m_sceneGraph.Close();
1419 1570
1420 if (!GridService.DeregisterRegion(RegionInfo.RegionID)) 1571 List<Vector3> coarseLocations;
1421 m_log.WarnFormat("[SCENE]: Deregister from grid failed for region {0}", Name); 1572 List<UUID> avatarUUIDs;
1422 1573
1423 base.Close(); 1574 while (!m_shuttingDown && ((endRun == null && Active) || MaintenanceRun < endRun))
1575 {
1576 runtc = Util.EnvironmentTickCount();
1577 ++MaintenanceRun;
1424 1578
1425 // XEngine currently listens to the EventManager.OnShutdown event to trigger script stop and persistence. 1579 // m_log.DebugFormat("[SCENE]: Maintenance run {0} in {1}", MaintenanceRun, Name);
1426 // Therefore. we must dispose of the PhysicsScene after this to prevent a window where script code can 1580
1427 // attempt to reference a null or disposed physics scene. 1581 // Coarse locations relate to positions of green dots on the mini-map (on a SecondLife client)
1428 if (PhysicsScene != null) 1582 if (MaintenanceRun % (m_update_coarse_locations / 10) == 0)
1429 { 1583 {
1430 PhysicsScene phys = PhysicsScene; 1584 SceneGraph.GetCoarseLocations(out coarseLocations, out avatarUUIDs, 60);
1431 // remove the physics engine from both Scene and SceneGraph 1585 // Send coarse locations to clients
1432 PhysicsScene = null; 1586 ForEachScenePresence(delegate(ScenePresence presence)
1433 phys.Dispose(); 1587 {
1434 phys = null; 1588 presence.SendCoarseLocations(coarseLocations, avatarUUIDs);
1435 } 1589 });
1436 } 1590 }
1437
1438 public override void Start()
1439 {
1440 Start(true);
1441 }
1442
1443 /// <summary>
1444 /// Start the scene
1445 /// </summary>
1446 /// <param name='startScripts'>
1447 /// Start the scripts within the scene.
1448 /// </param>
1449 public void Start(bool startScripts)
1450 {
1451 if (IsRunning)
1452 return;
1453
1454 m_isRunning = true;
1455 m_active = true;
1456
1457// m_log.DebugFormat("[SCENE]: Starting Heartbeat timer for {0}", RegionInfo.RegionName);
1458 if (m_heartbeatThread != null)
1459 {
1460 m_heartbeatThread.Abort();
1461 m_heartbeatThread = null;
1462 }
1463
1464 m_heartbeatThread
1465 = WorkManager.StartThread(
1466 Heartbeat, string.Format("Heartbeat-({0})", RegionInfo.RegionName.Replace(" ", "_")), ThreadPriority.Normal, false, false);
1467
1468 StartScripts();
1469 }
1470
1471 /// <summary>
1472 /// Sets up references to modules required by the scene
1473 /// </summary>
1474 public void SetModuleInterfaces()
1475 {
1476 m_xmlrpcModule = RequestModuleInterface<IXMLRPC>();
1477 m_worldCommModule = RequestModuleInterface<IWorldComm>();
1478 XferManager = RequestModuleInterface<IXfer>();
1479 m_AvatarFactory = RequestModuleInterface<IAvatarFactoryModule>();
1480 AttachmentsModule = RequestModuleInterface<IAttachmentsModule>();
1481 m_serialiser = RequestModuleInterface<IRegionSerialiserModule>();
1482 m_dialogModule = RequestModuleInterface<IDialogModule>();
1483 m_capsModule = RequestModuleInterface<ICapabilitiesModule>();
1484 EntityTransferModule = RequestModuleInterface<IEntityTransferModule>();
1485 m_groupsModule = RequestModuleInterface<IGroupsModule>();
1486 AgentTransactionsModule = RequestModuleInterface<IAgentAssetTransactions>();
1487 UserManagementModule = RequestModuleInterface<IUserManagement>();
1488 }
1489
1490 #endregion
1491
1492 #region Update Methods
1493
1494 /// <summary>
1495 /// Activate the various loops necessary to continually update the scene.
1496 /// </summary>
1497 private void Heartbeat()
1498 {
1499 m_eventManager.TriggerOnRegionStarted(this);
1500
1501 // The first frame can take a very long time due to physics actors being added on startup. Therefore,
1502 // don't turn on the watchdog alarm for this thread until the second frame, in order to prevent false
1503 // alarms for scenes with many objects.
1504 Update(1);
1505
1506 WorkManager.StartThread(
1507 Maintenance, string.Format("Maintenance ({0})", RegionInfo.RegionName), ThreadPriority.Normal, false, true);
1508
1509 Watchdog.GetCurrentThreadInfo().AlarmIfTimeout = true;
1510 m_lastFrameTick = Util.EnvironmentTickCount();
1511 1591
1512 if (UpdateOnTimer) 1592 if (SendPeriodicAppearanceUpdates && MaintenanceRun % 60 == 0)
1513 { 1593 {
1514 m_sceneUpdateTimer = new Timer(MinFrameTicks); 1594 // m_log.DebugFormat("[SCENE]: Sending periodic appearance updates");
1515 m_sceneUpdateTimer.AutoReset = true; 1595
1516 m_sceneUpdateTimer.Elapsed += Update; 1596 if (AvatarFactory != null)
1517 m_sceneUpdateTimer.Start(); 1597 {
1598 ForEachRootScenePresence(sp => AvatarFactory.SendAppearance(sp.UUID));
1599 }
1518 } 1600 }
1519 else 1601
1602 // Delete temp-on-rez stuff
1603 if (MaintenanceRun % m_update_temp_cleaning == 0 && !m_cleaningTemps)
1520 { 1604 {
1521 Thread.CurrentThread.Priority = ThreadPriority.Highest; 1605 // m_log.DebugFormat("[SCENE]: Running temp-on-rez cleaning in {0}", Name);
1522 Update(-1); 1606 tmpMS = Util.EnvironmentTickCount();
1523 Watchdog.RemoveThread(); 1607 m_cleaningTemps = true;
1524 m_isRunning = false; 1608
1609 WorkManager.RunInThread(
1610 delegate { CleanTempObjects(); m_cleaningTemps = false; },
1611 null,
1612 string.Format("CleanTempObjects ({0})", Name));
1613
1614 tempOnRezMS = Util.EnvironmentTickCountSubtract(tmpMS);
1525 } 1615 }
1526 }
1527 1616
1528 private volatile bool m_isTimerUpdateRunning; 1617 Watchdog.UpdateThread();
1529 1618
1530 private void Update(object sender, ElapsedEventArgs e) 1619 previousMaintenanceTick = m_lastMaintenanceTick;
1531 { 1620 m_lastMaintenanceTick = Util.EnvironmentTickCount();
1532 if (m_isTimerUpdateRunning) 1621 runtc = Util.EnvironmentTickCountSubtract(m_lastMaintenanceTick, runtc);
1533 return; 1622 runtc = MinMaintenanceTicks - runtc;
1534 1623
1535 m_isTimerUpdateRunning = true; 1624 if (runtc > 0)
1625 m_maintenanceWaitEvent.WaitOne(runtc);
1536 1626
1537 // If the last frame did not complete on time, then immediately start the next update on the same thread 1627 // Optionally warn if a frame takes double the amount of time that it should.
1538 // and ignore further timed updates until we have a frame that had spare time. 1628 if (DebugUpdates
1539 while (!Update(1) && Active) {} 1629 && Util.EnvironmentTickCountSubtract(
1630 m_lastMaintenanceTick, previousMaintenanceTick) > MinMaintenanceTicks * 2)
1631 m_log.WarnFormat(
1632 "[SCENE]: Maintenance took {0} ms (desired max {1} ms) in {2}",
1633 Util.EnvironmentTickCountSubtract(m_lastMaintenanceTick, previousMaintenanceTick),
1634 MinMaintenanceTicks,
1635 RegionInfo.RegionName);
1636 }
1637 }
1540 1638
1541 if (!Active || m_shuttingDown) 1639 public override bool Update(int frames)
1542 { 1640 {
1543 m_sceneUpdateTimer.Stop(); 1641 long? endFrame = null;
1544 m_sceneUpdateTimer = null;
1545 m_isRunning = false;
1546 }
1547 1642
1548 m_isTimerUpdateRunning = false; 1643 if (frames >= 0)
1549 } 1644 endFrame = Frame + frames;
1550 1645
1551 private void Maintenance() 1646 float physicsFPS = 0f;
1552 { 1647 int previousFrameTick, tmpMS;
1553 DoMaintenance(-1);
1554 1648
1555 Watchdog.RemoveThread(); 1649 // These variables will be used to save the precise frame time using the
1556 } 1650 // Stopwatch class of Microsoft SDK; the times are recorded at the start
1557 1651 // and end of a parcticular section of code, and then used to calculate
1558 public void DoMaintenance(int runs) 1652 // the frame times, which are the sums of the sections for each given name
1559 { 1653 double preciseTotalFrameTime = 0.0;
1560 long? endRun = null; 1654 double preciseSimFrameTime = 0.0;
1561 int runtc, tmpMS; 1655 double precisePhysicsFrameTime = 0.0;
1562 int previousMaintenanceTick; 1656 Stopwatch totalFrameStopwatch = new Stopwatch();
1563 1657 Stopwatch simFrameStopwatch = new Stopwatch();
1564 if (runs >= 0) 1658 Stopwatch physicsFrameStopwatch = new Stopwatch();
1565 endRun = MaintenanceRun + runs; 1659
1566 1660 // Begin the stopwatch to keep track of the time that the frame
1567 List<Vector3> coarseLocations; 1661 // started running to determine how long the frame took to complete
1568 List<UUID> avatarUUIDs; 1662 totalFrameStopwatch.Start();
1569 1663
1570 while (!m_shuttingDown && ((endRun == null && Active) || MaintenanceRun < endRun)) 1664 while (!m_shuttingDown && ((endFrame == null && Active) || Frame < endFrame))
1571 { 1665 {
1572 runtc = Util.EnvironmentTickCount(); 1666 ++Frame;
1573 ++MaintenanceRun; 1667
1574 1668 // m_log.DebugFormat("[SCENE]: Processing frame {0} in {1}", Frame, RegionInfo.RegionName);
1575// m_log.DebugFormat("[SCENE]: Maintenance run {0} in {1}", MaintenanceRun, Name); 1669
1576 1670 agentMS = eventMS = backupMS = terrainMS = landMS = spareMS = 0;
1577 // Coarse locations relate to positions of green dots on the mini-map (on a SecondLife client)
1578 if (MaintenanceRun % (m_update_coarse_locations / 10) == 0)
1579 {
1580 SceneGraph.GetCoarseLocations(out coarseLocations, out avatarUUIDs, 60);
1581 // Send coarse locations to clients
1582 ForEachScenePresence(delegate(ScenePresence presence)
1583 {
1584 presence.SendCoarseLocations(coarseLocations, avatarUUIDs);
1585 });
1586 }
1587
1588 if (SendPeriodicAppearanceUpdates && MaintenanceRun % 60 == 0)
1589 {
1590// m_log.DebugFormat("[SCENE]: Sending periodic appearance updates");
1591
1592 if (AvatarFactory != null)
1593 {
1594 ForEachRootScenePresence(sp => AvatarFactory.SendAppearance(sp.UUID));
1595 }
1596 }
1597
1598 // Delete temp-on-rez stuff
1599 if (MaintenanceRun % m_update_temp_cleaning == 0 && !m_cleaningTemps)
1600 {
1601// m_log.DebugFormat("[SCENE]: Running temp-on-rez cleaning in {0}", Name);
1602 tmpMS = Util.EnvironmentTickCount();
1603 m_cleaningTemps = true;
1604
1605 WorkManager.RunInThread(
1606 delegate { CleanTempObjects(); m_cleaningTemps = false; },
1607 null,
1608 string.Format("CleanTempObjects ({0})", Name));
1609
1610 tempOnRezMS = Util.EnvironmentTickCountSubtract(tmpMS);
1611 }
1612
1613 Watchdog.UpdateThread();
1614
1615 previousMaintenanceTick = m_lastMaintenanceTick;
1616 m_lastMaintenanceTick = Util.EnvironmentTickCount();
1617 runtc = Util.EnvironmentTickCountSubtract(m_lastMaintenanceTick, runtc);
1618 runtc = MinMaintenanceTicks - runtc;
1619
1620 if (runtc > 0)
1621 m_maintenanceWaitEvent.WaitOne(runtc);
1622
1623 // Optionally warn if a frame takes double the amount of time that it should.
1624 if (DebugUpdates
1625 && Util.EnvironmentTickCountSubtract(
1626 m_lastMaintenanceTick, previousMaintenanceTick) > MinMaintenanceTicks * 2)
1627 m_log.WarnFormat(
1628 "[SCENE]: Maintenance took {0} ms (desired max {1} ms) in {2}",
1629 Util.EnvironmentTickCountSubtract(m_lastMaintenanceTick, previousMaintenanceTick),
1630 MinMaintenanceTicks,
1631 RegionInfo.RegionName);
1632 }
1633 }
1634
1635 public override bool Update(int frames)
1636 {
1637 long? endFrame = null;
1638
1639 if (frames >= 0)
1640 endFrame = Frame + frames;
1641
1642 float physicsFPS = 0f;
1643 int previousFrameTick, tmpMS;
1644
1645 // These variables will be used to save the precise frame time using the
1646 // Stopwatch class of Microsoft SDK; the times are recorded at the start
1647 // and end of a parcticular section of code, and then used to calculate
1648 // the frame times, which are the sums of the sections for each given name
1649 double preciseTotalFrameTime = 0.0;
1650 double preciseSimFrameTime = 0.0;
1651 double precisePhysicsFrameTime = 0.0;
1652 Stopwatch totalFrameStopwatch = new Stopwatch();
1653 Stopwatch simFrameStopwatch = new Stopwatch();
1654 Stopwatch physicsFrameStopwatch = new Stopwatch();
1655
1656 // Begin the stopwatch to keep track of the time that the frame
1657 // started running to determine how long the frame took to complete
1658 totalFrameStopwatch.Start();
1659
1660 while (!m_shuttingDown && ((endFrame == null && Active) || Frame < endFrame))
1661 {
1662 ++Frame;
1663
1664// m_log.DebugFormat("[SCENE]: Processing frame {0} in {1}", Frame, RegionInfo.RegionName);
1665
1666 agentMS = eventMS = backupMS = terrainMS = landMS = spareMS = 0;
1667
1668 try
1669 {
1670 EventManager.TriggerRegionHeartbeatStart(this);
1671
1672 // Apply taints in terrain module to terrain in physics scene
1673 if (Frame % m_update_terrain == 0)
1674 {
1675 tmpMS = Util.EnvironmentTickCount();
1676 UpdateTerrain();
1677 terrainMS = Util.EnvironmentTickCountSubtract(tmpMS);
1678 }
1679
1680 // At several points inside the code there was a need to
1681 // create a more precise measurement of time elapsed. This
1682 // led to the addition of variables that have a similar
1683 // function and thus remain tightly connected to their
1684 // original counterparts. However, the original code is
1685 // not receiving comments from our group because we don't
1686 // feel right modifying the code to that degree at this
1687 // point in time, the precise values all begin with the
1688 // keyword precise
1689
1690 tmpMS = Util.EnvironmentTickCount();
1691
1692 // Begin the stopwatch to track the time to prepare physics
1693 physicsFrameStopwatch.Start();
1694 if (PhysicsEnabled && Frame % m_update_physics == 0)
1695 m_sceneGraph.UpdatePreparePhysics();
1696
1697 // Get the time it took to prepare the physics, this
1698 // would report the most precise time that physics was
1699 // running on the machine and should the physics not be
1700 // enabled will report the time it took to check if physics
1701 // was enabled
1702 physicsFrameStopwatch.Stop();
1703 precisePhysicsFrameTime = physicsFrameStopwatch.Elapsed.TotalMilliseconds;
1704 physicsMS2 = Util.EnvironmentTickCountSubtract(tmpMS);
1705
1706 // Apply any pending avatar force input to the avatar's velocity
1707 tmpMS = Util.EnvironmentTickCount();
1708 simFrameStopwatch.Start();
1709 if (Frame % m_update_entitymovement == 0)
1710 m_sceneGraph.UpdateScenePresenceMovement();
1711
1712 // Get the simulation frame time that the avatar force input took
1713 simFrameStopwatch.Stop();
1714 preciseSimFrameTime = simFrameStopwatch.Elapsed.TotalMilliseconds;
1715 agentMS = Util.EnvironmentTickCountSubtract(tmpMS);
1716
1717 // Perform the main physics update. This will do the actual work of moving objects and avatars according to their
1718 // velocity
1719 tmpMS = Util.EnvironmentTickCount();
1720 physicsFrameStopwatch.Restart();
1721 if (Frame % m_update_physics == 0)
1722 {
1723 if (PhysicsEnabled)
1724 physicsFPS = m_sceneGraph.UpdatePhysics(MinFrameSeconds);
1725
1726 if (SynchronizeScene != null)
1727 SynchronizeScene(this);
1728 }
1729
1730 // Add the main physics update time to the prepare physics time
1731 physicsFrameStopwatch.Stop();
1732 precisePhysicsFrameTime += physicsFrameStopwatch.Elapsed.TotalMilliseconds;
1733 physicsMS = Util.EnvironmentTickCountSubtract(tmpMS);
1734
1735 // Start the stopwatch for the remainder of the simulation
1736 simFrameStopwatch.Restart();
1737 tmpMS = Util.EnvironmentTickCount();
1738
1739 // Check if any objects have reached their targets
1740 CheckAtTargets();
1741
1742 // Update SceneObjectGroups that have scheduled themselves for updates
1743 // Objects queue their updates onto all scene presences
1744 if (Frame % m_update_objects == 0)
1745 m_sceneGraph.UpdateObjectGroups();
1746
1747 // Run through all ScenePresences looking for updates
1748 // Presence updates and queued object updates for each presence are sent to clients
1749 if (Frame % m_update_presences == 0)
1750 m_sceneGraph.UpdatePresences();
1751
1752 agentMS += Util.EnvironmentTickCountSubtract(tmpMS);
1753
1754 if (Frame % m_update_events == 0)
1755 {
1756 tmpMS = Util.EnvironmentTickCount();
1757 UpdateEvents();
1758 eventMS = Util.EnvironmentTickCountSubtract(tmpMS);
1759 }
1760
1761 if (PeriodicBackup && Frame % m_update_backup == 0)
1762 {
1763 tmpMS = Util.EnvironmentTickCount();
1764 UpdateStorageBackup();
1765 backupMS = Util.EnvironmentTickCountSubtract(tmpMS);
1766 }
1767
1768 //if (Frame % m_update_land == 0)
1769 //{
1770 // int ldMS = Util.EnvironmentTickCount();
1771 // UpdateLand();
1772 // landMS = Util.EnvironmentTickCountSubtract(ldMS);
1773 //}
1774
1775 if (!LoginsEnabled && Frame == 20)
1776 {
1777 // m_log.DebugFormat("{0} {1} {2}", LoginsDisabled, m_sceneGraph.GetActiveScriptsCount(), LoginLock);
1778
1779 // In 99.9% of cases it is a bad idea to manually force garbage collection. However,
1780 // this is a rare case where we know we have just went through a long cycle of heap
1781 // allocations, and there is no more work to be done until someone logs in
1782 GC.Collect();
1783
1784 if (!LoginLock)
1785 {
1786 if (!StartDisabled)
1787 {
1788 m_log.InfoFormat("[REGION]: Enabling logins for {0}", RegionInfo.RegionName);
1789 LoginsEnabled = true;
1790 }
1791
1792 m_sceneGridService.InformNeighborsThatRegionisUp(
1793 RequestModuleInterface<INeighbourService>(), RegionInfo);
1794
1795 // Region ready should always be set
1796 Ready = true;
1797 }
1798 else
1799 {
1800 // This handles a case of a region having no scripts for the RegionReady module
1801 if (m_sceneGraph.GetActiveScriptsCount() == 0)
1802 {
1803 // In this case, we leave it to the IRegionReadyModule to enable logins
1804
1805 // LoginLock can currently only be set by a region module implementation.
1806 // If somehow this hasn't been done then the quickest way to bugfix is to see the
1807 // NullReferenceException
1808 IRegionReadyModule rrm = RequestModuleInterface<IRegionReadyModule>();
1809 rrm.TriggerRegionReady(this);
1810 }
1811 }
1812 }
1813 }
1814 catch (Exception e)
1815 {
1816 m_log.ErrorFormat(
1817 "[SCENE]: Failed on region {0} with exception {1}{2}",
1818 RegionInfo.RegionName, e.Message, e.StackTrace);
1819 }
1820
1821 EventManager.TriggerRegionHeartbeatEnd(this);
1822 otherMS = eventMS + backupMS + terrainMS + landMS;
1823
1824 if (!UpdateOnTimer)
1825 {
1826 Watchdog.UpdateThread();
1827
1828 spareMS = MinFrameTicks - Util.EnvironmentTickCountSubtract(m_lastFrameTick);
1829
1830 if (spareMS > 0)
1831 m_updateWaitEvent.WaitOne(spareMS);
1832 else
1833 spareMS = 0;
1834 }
1835 else
1836 {
1837 spareMS = Math.Max(0, MinFrameTicks - physicsMS2 - agentMS - physicsMS - otherMS);
1838 }
1839
1840 // Get the elapsed time for the simulation frame
1841 simFrameStopwatch.Stop();
1842 preciseSimFrameTime += simFrameStopwatch.Elapsed.TotalMilliseconds;
1843
1844 previousFrameTick = m_lastFrameTick;
1845 frameMS = Util.EnvironmentTickCountSubtract(m_lastFrameTick);
1846 m_lastFrameTick = Util.EnvironmentTickCount();
1847
1848 // if (Frame%m_update_avatars == 0)
1849 // UpdateInWorldTime();
1850 StatsReporter.AddPhysicsFPS(physicsFPS);
1851 StatsReporter.AddTimeDilation(TimeDilation);
1852 StatsReporter.AddFPS(1);
1853
1854 StatsReporter.addFrameMS(frameMS);
1855 StatsReporter.addAgentMS(agentMS);
1856 StatsReporter.addPhysicsMS(physicsMS + physicsMS2);
1857 StatsReporter.addOtherMS(otherMS);
1858 StatsReporter.AddSpareMS(spareMS);
1859 StatsReporter.addScriptLines(m_sceneGraph.GetScriptLPS());
1860
1861 // Send the correct time values to the stats reporter for the
1862 // frame times
1863 StatsReporter.addFrameTimeMilliseconds(preciseTotalFrameTime,
1864 preciseSimFrameTime, precisePhysicsFrameTime, 0.0);
1865
1866 // Send the correct number of frames that the physics library
1867 // has processed to the stats reporter
1868 StatsReporter.addPhysicsFrame(1);
1869
1870 // Optionally warn if a frame takes double the amount of time that it should.
1871 if (DebugUpdates
1872 && Util.EnvironmentTickCountSubtract(
1873 m_lastFrameTick, previousFrameTick) > MinFrameTicks * 2)
1874 m_log.WarnFormat(
1875 "[SCENE]: Frame took {0} ms (desired max {1} ms) in {2}",
1876 Util.EnvironmentTickCountSubtract(m_lastFrameTick, previousFrameTick),
1877 MinFrameTicks,
1878 RegionInfo.RegionName);
1879 }
1880
1881 // Finished updating scene frame, so stop the total frame's Stopwatch
1882 totalFrameStopwatch.Stop();
1883 1671
1884 return spareMS >= 0;
1885 }
1886
1887 public void AddGroupTarget(SceneObjectGroup grp)
1888 {
1889 lock (m_groupsWithTargets)
1890 m_groupsWithTargets[grp.UUID] = grp;
1891 }
1892
1893 public void RemoveGroupTarget(SceneObjectGroup grp)
1894 {
1895 lock (m_groupsWithTargets)
1896 m_groupsWithTargets.Remove(grp.UUID);
1897 }
1898
1899 private void CheckAtTargets()
1900 {
1901 List<SceneObjectGroup> objs = null;
1902
1903 lock (m_groupsWithTargets)
1904 {
1905 if (m_groupsWithTargets.Count != 0)
1906 objs = new List<SceneObjectGroup>(m_groupsWithTargets.Values);
1907 }
1908
1909 if (objs != null)
1910 {
1911 foreach (SceneObjectGroup entry in objs)
1912 entry.checkAtTargets();
1913 }
1914 }
1915
1916 /// <summary>
1917 /// Send out simstats data to all clients
1918 /// </summary>
1919 /// <param name="stats">Stats on the Simulator's performance</param>
1920 private void SendSimStatsPackets(SimStats stats)
1921 {
1922 ForEachRootClient(delegate(IClientAPI client)
1923 {
1924 client.SendSimStats(stats);
1925 });
1926 }
1927
1928 /// <summary>
1929 /// Update the terrain if it needs to be updated.
1930 /// </summary>
1931 private void UpdateTerrain()
1932 {
1933 EventManager.TriggerTerrainTick();
1934 }
1935
1936 /// <summary>
1937 /// Back up queued up changes
1938 /// </summary>
1939 private void UpdateStorageBackup()
1940 {
1941 if (!m_backingup)
1942 {
1943 m_backingup = true;
1944 WorkManager.RunInThread(o => Backup(false), null, string.Format("BackupWaitCallback ({0})", Name));
1945 }
1946 }
1947
1948 /// <summary>
1949 /// Sends out the OnFrame event to the modules
1950 /// </summary>
1951 private void UpdateEvents()
1952 {
1953 m_eventManager.TriggerOnFrame();
1954 }
1955
1956 /// <summary>
1957 /// Backup the scene.
1958 /// </summary>
1959 /// <remarks>
1960 /// This acts as the main method of the backup thread. In a regression test whether the backup thread is not
1961 /// running independently this can be invoked directly.
1962 /// </remarks>
1963 /// <param name="forced">
1964 /// If true, then any changes that have not yet been persisted are persisted. If false,
1965 /// then the persistence decision is left to the backup code (in some situations, such as object persistence,
1966 /// it's much more efficient to backup multiple changes at once rather than every single one).
1967 /// <returns></returns>
1968 public void Backup(bool forced)
1969 {
1970 lock (m_returns)
1971 {
1972 EventManager.TriggerOnBackup(SimulationDataService, forced);
1973 m_backingup = false;
1974
1975 foreach (KeyValuePair<UUID, ReturnInfo> ret in m_returns)
1976 {
1977 UUID transaction = UUID.Random();
1978
1979 GridInstantMessage msg = new GridInstantMessage();
1980 msg.fromAgentID = new Guid(UUID.Zero.ToString()); // From server
1981 msg.toAgentID = new Guid(ret.Key.ToString());
1982 msg.imSessionID = new Guid(transaction.ToString());
1983 msg.timestamp = (uint)Util.UnixTimeSinceEpoch();
1984 msg.fromAgentName = "Server";
1985 msg.dialog = (byte)19; // Object msg
1986 msg.fromGroup = false;
1987 msg.offline = (byte)0;
1988 msg.ParentEstateID = RegionInfo.EstateSettings.ParentEstateID;
1989 msg.Position = Vector3.Zero;
1990 msg.RegionID = RegionInfo.RegionID.Guid;
1991
1992 // We must fill in a null-terminated 'empty' string here since bytes[0] will crash viewer 3.
1993 msg.binaryBucket = Util.StringToBytes256("\0");
1994 if (ret.Value.count > 1)
1995 msg.message = string.Format("Your {0} objects were returned from {1} in region {2} due to {3}", ret.Value.count, ret.Value.location.ToString(), RegionInfo.RegionName, ret.Value.reason);
1996 else
1997 msg.message = string.Format("Your object {0} was returned from {1} in region {2} due to {3}", ret.Value.objectName, ret.Value.location.ToString(), RegionInfo.RegionName, ret.Value.reason);
1998
1999 IMessageTransferModule tr = RequestModuleInterface<IMessageTransferModule>();
2000 if (tr != null)
2001 tr.SendInstantMessage(msg, delegate(bool success) {});
2002 }
2003 m_returns.Clear();
2004 }
2005 }
2006
2007 /// <summary>
2008 /// Synchronous force backup. For deletes and links/unlinks
2009 /// </summary>
2010 /// <param name="group">Object to be backed up</param>
2011 public void ForceSceneObjectBackup(SceneObjectGroup group)
2012 {
2013 if (group != null)
2014 {
2015 group.HasGroupChanged = true;
2016 group.ProcessBackup(SimulationDataService, true);
2017 }
2018 }
2019
2020 /// <summary>
2021 /// Tell an agent that their object has been returned.
2022 /// </summary>
2023 /// <remarks>
2024 /// The actual return is handled by the caller.
2025 /// </remarks>
2026 /// <param name="agentID">Avatar Unique Id</param>
2027 /// <param name="objectName">Name of object returned</param>
2028 /// <param name="location">Location of object returned</param>
2029 /// <param name="reason">Reasion for object return</param>
2030 public void AddReturn(UUID agentID, string objectName, Vector3 location, string reason)
2031 {
2032 lock (m_returns)
2033 {
2034 if (m_returns.ContainsKey(agentID))
2035 {
2036 ReturnInfo info = m_returns[agentID];
2037 info.count++;
2038 m_returns[agentID] = info;
2039 }
2040 else
2041 {
2042 ReturnInfo info = new ReturnInfo();
2043 info.count = 1;
2044 info.objectName = objectName;
2045 info.location = location;
2046 info.reason = reason;
2047 m_returns[agentID] = info;
2048 }
2049 }
2050 }
2051
2052 #endregion
2053
2054 #region Load Terrain
2055
2056 /// <summary>
2057 /// Store the terrain in the persistant data store
2058 /// </summary>
2059 public void SaveTerrain()
2060 {
2061 SimulationDataService.StoreTerrain(Heightmap.GetDoubles(), RegionInfo.RegionID);
2062 }
2063
2064 public void StoreWindlightProfile(RegionLightShareData wl)
2065 {
2066 RegionInfo.WindlightSettings = wl;
2067 SimulationDataService.StoreRegionWindlightSettings(wl);
2068 m_eventManager.TriggerOnSaveNewWindlightProfile();
2069 }
2070
2071 public void LoadWindlightProfile()
2072 {
2073 RegionInfo.WindlightSettings = SimulationDataService.LoadRegionWindlightSettings(RegionInfo.RegionID);
2074 m_eventManager.TriggerOnSaveNewWindlightProfile();
2075 }
2076
2077 /// <summary>
2078 /// Loads the World heightmap
2079 /// </summary>
2080 public override void LoadWorldMap()
2081 {
2082 try 1672 try
2083 { 1673 {
2084 TerrainData map = SimulationDataService.LoadTerrain(RegionInfo.RegionID, (int)RegionInfo.RegionSizeX, (int)RegionInfo.RegionSizeY, (int)RegionInfo.RegionSizeZ); 1674 EventManager.TriggerRegionHeartbeatStart(this);
2085 if (map == null) 1675
2086 { 1676 // Apply taints in terrain module to terrain in physics scene
2087 // This should be in the Terrain module, but it isn't because 1677 if (Frame % m_update_terrain == 0)
2088 // the heightmap is needed _way_ before the modules are initialized... 1678 {
2089 IConfig terrainConfig = m_config.Configs["Terrain"]; 1679 tmpMS = Util.EnvironmentTickCount();
2090 String m_InitialTerrain = "pinhead-island"; 1680 simFrameStopwatch.Start();
2091 if (terrainConfig != null) 1681 UpdateTerrain();
2092 m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain); 1682
2093 1683 // Get the simulation frame time that the avatar force
2094 m_log.InfoFormat("[TERRAIN]: No default terrain. Generating a new terrain {0}.", m_InitialTerrain); 1684 // input took
2095 Heightmap = new TerrainChannel(m_InitialTerrain, (int)RegionInfo.RegionSizeX, (int)RegionInfo.RegionSizeY, (int)RegionInfo.RegionSizeZ); 1685 simFrameStopwatch.Stop();
2096 1686 preciseSimFrameTime =
2097 SimulationDataService.StoreTerrain(Heightmap.GetDoubles(), RegionInfo.RegionID); 1687 simFrameStopwatch.Elapsed.TotalMilliseconds;
2098 } 1688 terrainMS = Util.EnvironmentTickCountSubtract(tmpMS);
2099 else 1689 }
2100 { 1690
2101 Heightmap = new TerrainChannel(map); 1691 // At several points inside the code there was a need to
2102 } 1692 // create a more precise measurement of time elapsed. This
2103 } 1693 // led to the addition of variables that have a similar
2104 catch (IOException e) 1694 // function and thus remain tightly connected to their
2105 { 1695 // original counterparts. However, the original code is
2106 m_log.WarnFormat( 1696 // not receiving comments from our group because we don't
2107 "[TERRAIN]: Scene.cs: LoadWorldMap() - Regenerating as failed with exception {0}{1}", 1697 // feel right modifying the code to that degree at this
2108 e.Message, e.StackTrace); 1698 // point in time, the precise values all begin with the
2109 1699 // keyword precise
2110 // Non standard region size. If there's an old terrain in the database, it might read past the buffer 1700
2111 #pragma warning disable 0162 1701 tmpMS = Util.EnvironmentTickCount();
2112 if ((int)Constants.RegionSize != 256) 1702
2113 { 1703 // Begin the stopwatch to track the time to prepare physics
2114 Heightmap = new TerrainChannel(); 1704 physicsFrameStopwatch.Start();
2115 1705 if (PhysicsEnabled && Frame % m_update_physics == 0)
2116 SimulationDataService.StoreTerrain(Heightmap.GetDoubles(), RegionInfo.RegionID); 1706 m_sceneGraph.UpdatePreparePhysics();
2117 } 1707
1708 // Get the time it took to prepare the physics, this
1709 // would report the most precise time that physics was
1710 // running on the machine and should the physics not be
1711 // enabled will report the time it took to check if physics
1712 // was enabled
1713 physicsFrameStopwatch.Stop();
1714 precisePhysicsFrameTime = physicsFrameStopwatch.Elapsed.TotalMilliseconds;
1715 physicsMS2 = Util.EnvironmentTickCountSubtract(tmpMS);
1716
1717 // Apply any pending avatar force input to the avatar's velocity
1718 tmpMS = Util.EnvironmentTickCount();
1719 simFrameStopwatch.Restart();
1720 if (Frame % m_update_entitymovement == 0)
1721 m_sceneGraph.UpdateScenePresenceMovement();
1722
1723 // Get the simulation frame time that the avatar force input
1724 // took
1725 simFrameStopwatch.Stop();
1726 preciseSimFrameTime +=
1727 simFrameStopwatch.Elapsed.TotalMilliseconds;
1728 agentMS = Util.EnvironmentTickCountSubtract(tmpMS);
1729
1730 // Perform the main physics update. This will do the actual work of moving objects and avatars according to their
1731 // velocity
1732 tmpMS = Util.EnvironmentTickCount();
1733 physicsFrameStopwatch.Restart();
1734 if (Frame % m_update_physics == 0)
1735 {
1736 if (PhysicsEnabled)
1737 physicsFPS = m_sceneGraph.UpdatePhysics(MinFrameSeconds);
1738
1739 if (SynchronizeScene != null)
1740 SynchronizeScene(this);
1741 }
1742
1743 // Add the main physics update time to the prepare physics time
1744 physicsFrameStopwatch.Stop();
1745 precisePhysicsFrameTime += physicsFrameStopwatch.Elapsed.TotalMilliseconds;
1746 physicsMS = Util.EnvironmentTickCountSubtract(tmpMS);
1747
1748 // Start the stopwatch for the remainder of the simulation
1749 simFrameStopwatch.Restart();
1750 tmpMS = Util.EnvironmentTickCount();
1751
1752 // Check if any objects have reached their targets
1753 CheckAtTargets();
1754
1755 // Update SceneObjectGroups that have scheduled themselves for updates
1756 // Objects queue their updates onto all scene presences
1757 if (Frame % m_update_objects == 0)
1758 m_sceneGraph.UpdateObjectGroups();
1759
1760 // Run through all ScenePresences looking for updates
1761 // Presence updates and queued object updates for each presence are sent to clients
1762 if (Frame % m_update_presences == 0)
1763 m_sceneGraph.UpdatePresences();
1764
1765 agentMS += Util.EnvironmentTickCountSubtract(tmpMS);
1766
1767 if (Frame % m_update_events == 0)
1768 {
1769 tmpMS = Util.EnvironmentTickCount();
1770 UpdateEvents();
1771 eventMS = Util.EnvironmentTickCountSubtract(tmpMS);
1772 }
1773
1774 if (PeriodicBackup && Frame % m_update_backup == 0)
1775 {
1776 tmpMS = Util.EnvironmentTickCount();
1777 UpdateStorageBackup();
1778 backupMS = Util.EnvironmentTickCountSubtract(tmpMS);
1779 }
1780
1781 //if (Frame % m_update_land == 0)
1782 //{
1783 // int ldMS = Util.EnvironmentTickCount();
1784 // UpdateLand();
1785 // landMS = Util.EnvironmentTickCountSubtract(ldMS);
1786 //}
1787
1788 if (!LoginsEnabled && Frame == 20)
1789 {
1790 // m_log.DebugFormat("{0} {1} {2}", LoginsDisabled, m_sceneGraph.GetActiveScriptsCount(), LoginLock);
1791
1792 // In 99.9% of cases it is a bad idea to manually force garbage collection. However,
1793 // this is a rare case where we know we have just went through a long cycle of heap
1794 // allocations, and there is no more work to be done until someone logs in
1795 GC.Collect();
1796
1797 if (!LoginLock)
1798 {
1799 if (!StartDisabled)
1800 {
1801 m_log.InfoFormat("[REGION]: Enabling logins for {0}", RegionInfo.RegionName);
1802 LoginsEnabled = true;
1803 }
1804
1805 m_sceneGridService.InformNeighborsThatRegionisUp(
1806 RequestModuleInterface<INeighbourService>(), RegionInfo);
1807
1808 // Region ready should always be set
1809 Ready = true;
1810 }
1811 else
1812 {
1813 // This handles a case of a region having no scripts for the RegionReady module
1814 if (m_sceneGraph.GetActiveScriptsCount() == 0)
1815 {
1816 // In this case, we leave it to the IRegionReadyModule to enable logins
1817
1818 // LoginLock can currently only be set by a region module implementation.
1819 // If somehow this hasn't been done then the quickest way to bugfix is to see the
1820 // NullReferenceException
1821 IRegionReadyModule rrm = RequestModuleInterface<IRegionReadyModule>();
1822 rrm.TriggerRegionReady(this);
1823 }
1824 }
1825 }
2118 } 1826 }
2119 catch (Exception e) 1827 catch (Exception e)
2120 { 1828 {
2121 m_log.WarnFormat( 1829 m_log.ErrorFormat(
2122 "[TERRAIN]: Scene.cs: LoadWorldMap() - Failed with exception {0}{1}", e.Message, e.StackTrace); 1830 "[SCENE]: Failed on region {0} with exception {1}{2}",
1831 RegionInfo.RegionName, e.Message, e.StackTrace);
2123 } 1832 }
2124 }
2125 1833
2126 /// <summary> 1834 EventManager.TriggerRegionHeartbeatEnd(this);
2127 /// Register this region with a grid service 1835 otherMS = eventMS + backupMS + terrainMS + landMS;
2128 /// </summary>
2129 /// <exception cref="System.Exception">Thrown if registration of the region itself fails.</exception>
2130 public void RegisterRegionWithGrid()
2131 {
2132 m_sceneGridService.SetScene(this);
2133 1836
2134 //// Unfortunately this needs to be here and it can't be async. 1837 // Get the elapsed time for the simulation frame
2135 //// The map tile image is stored in RegionSettings, but it also needs to be 1838 simFrameStopwatch.Stop();
2136 //// stored in the GridService, because that's what the world map module uses 1839 preciseSimFrameTime +=
2137 //// to send the map image UUIDs (of other regions) to the viewer... 1840 simFrameStopwatch.Elapsed.TotalMilliseconds;
2138 if (m_generateMaptiles) 1841
2139 RegenerateMaptile(); 1842 if (!UpdateOnTimer)
2140
2141 GridRegion region = new GridRegion(RegionInfo);
2142 string error = GridService.RegisterRegion(RegionInfo.ScopeID, region);
2143// m_log.DebugFormat("[SCENE]: RegisterRegionWithGrid. name={0},id={1},loc=<{2},{3}>,size=<{4},{5}>",
2144// m_regionName,
2145// RegionInfo.RegionID,
2146// RegionInfo.RegionLocX, RegionInfo.RegionLocY,
2147// RegionInfo.RegionSizeX, RegionInfo.RegionSizeY);
2148
2149 if (error != String.Empty)
2150 throw new Exception(error);
2151 }
2152
2153 #endregion
2154
2155 #region Load Land
2156
2157 /// <summary>
2158 /// Loads all Parcel data from the datastore for region identified by regionID
2159 /// </summary>
2160 /// <param name="regionID">Unique Identifier of the Region to load parcel data for</param>
2161 public void loadAllLandObjectsFromStorage(UUID regionID)
2162 {
2163 m_log.Info("[SCENE]: Loading land objects from storage");
2164 List<LandData> landData = SimulationDataService.LoadLandObjects(regionID);
2165
2166 if (LandChannel != null)
2167 {
2168 if (landData.Count == 0)
2169 {
2170 EventManager.TriggerNoticeNoLandDataFromStorage();
2171 }
2172 else
2173 {
2174 EventManager.TriggerIncomingLandDataFromStorage(landData);
2175 }
2176 }
2177 else
2178 { 1843 {
2179 m_log.Error("[SCENE]: Land Channel is not defined. Cannot load from storage!"); 1844 Watchdog.UpdateThread();
2180 }
2181 }
2182 1845
2183 #endregion 1846 spareMS = MinFrameTicks - Util.EnvironmentTickCountSubtract(m_lastFrameTick);
2184 1847
2185 #region Primitives Methods 1848 if (spareMS > 0)
2186 1849 m_updateWaitEvent.WaitOne(spareMS);
2187 /// <summary> 1850 else
2188 /// Loads the World's objects 1851 spareMS = 0;
2189 /// </summary>
2190 /// <param name="regionID"></param>
2191 public virtual void LoadPrimsFromStorage(UUID regionID)
2192 {
2193 LoadingPrims = true;
2194 m_log.Info("[SCENE]: Loading objects from datastore");
2195
2196 List<SceneObjectGroup> PrimsFromDB = SimulationDataService.LoadObjects(regionID);
2197
2198 m_log.InfoFormat("[SCENE]: Loaded {0} objects from the datastore", PrimsFromDB.Count);
2199
2200 foreach (SceneObjectGroup group in PrimsFromDB)
2201 {
2202 AddRestoredSceneObject(group, true, true);
2203 EventManager.TriggerOnSceneObjectLoaded(group);
2204 SceneObjectPart rootPart = group.GetPart(group.UUID);
2205 rootPart.Flags &= ~PrimFlags.Scripted;
2206 rootPart.TrimPermissions();
2207
2208 // Don't do this here - it will get done later on when sculpt data is loaded.
2209// group.CheckSculptAndLoad();
2210 }
2211
2212 LoadingPrims = false;
2213 EventManager.TriggerPrimsLoaded(this);
2214 }
2215
2216 public bool SupportsRayCastFiltered()
2217 {
2218 if (PhysicsScene == null)
2219 return false;
2220 return PhysicsScene.SupportsRaycastWorldFiltered();
2221 }
2222
2223 public object RayCastFiltered(Vector3 position, Vector3 direction, float length, int Count, RayFilterFlags filter)
2224 {
2225 if (PhysicsScene == null)
2226 return null;
2227 return PhysicsScene.RaycastWorld(position, direction, length, Count,filter);
2228 }
2229
2230 /// <summary>
2231 /// Gets a new rez location based on the raycast and the size of the object that is being rezzed.
2232 /// </summary>
2233 /// <param name="RayStart"></param>
2234 /// <param name="RayEnd"></param>
2235 /// <param name="RayTargetID"></param>
2236 /// <param name="rot"></param>
2237 /// <param name="bypassRayCast"></param>
2238 /// <param name="RayEndIsIntersection"></param>
2239 /// <param name="frontFacesOnly"></param>
2240 /// <param name="scale"></param>
2241 /// <param name="FaceCenter"></param>
2242 /// <returns></returns>
2243 public Vector3 GetNewRezLocation(Vector3 RayStart, Vector3 RayEnd, UUID RayTargetID, Quaternion rot, byte bypassRayCast, byte RayEndIsIntersection, bool frontFacesOnly, Vector3 scale, bool FaceCenter)
2244 {
2245 Vector3 pos = Vector3.Zero;
2246 if (RayEndIsIntersection == (byte)1)
2247 {
2248 pos = RayEnd;
2249 return pos;
2250 }
2251
2252 if (RayTargetID != UUID.Zero)
2253 {
2254 SceneObjectPart target = GetSceneObjectPart(RayTargetID);
2255
2256 Vector3 direction = Vector3.Normalize(RayEnd - RayStart);
2257 Vector3 AXOrigin = RayStart;
2258 Vector3 AXdirection = direction;
2259
2260 if (target != null)
2261 {
2262 pos = target.AbsolutePosition;
2263 //m_log.Info("[OBJECT_REZ]: TargetPos: " + pos.ToString() + ", RayStart: " + RayStart.ToString() + ", RayEnd: " + RayEnd.ToString() + ", Volume: " + Util.GetDistanceTo(RayStart,RayEnd).ToString() + ", mag1: " + Util.GetMagnitude(RayStart).ToString() + ", mag2: " + Util.GetMagnitude(RayEnd).ToString());
2264
2265 // TODO: Raytrace better here
2266
2267 //EntityIntersection ei = m_sceneGraph.GetClosestIntersectingPrim(new Ray(AXOrigin, AXdirection));
2268 Ray NewRay = new Ray(AXOrigin, AXdirection);
2269
2270 // Ray Trace against target here
2271 EntityIntersection ei = target.TestIntersectionOBB(NewRay, Quaternion.Identity, frontFacesOnly, FaceCenter);
2272
2273 // Un-comment out the following line to Get Raytrace results printed to the console.
2274 // m_log.Info("[RAYTRACERESULTS]: Hit:" + ei.HitTF.ToString() + " Point: " + ei.ipoint.ToString() + " Normal: " + ei.normal.ToString());
2275 float ScaleOffset = 0.5f;
2276
2277 // If we hit something
2278 if (ei.HitTF)
2279 {
2280 Vector3 scaleComponent = ei.AAfaceNormal;
2281 if (scaleComponent.X != 0) ScaleOffset = scale.X;
2282 if (scaleComponent.Y != 0) ScaleOffset = scale.Y;
2283 if (scaleComponent.Z != 0) ScaleOffset = scale.Z;
2284 ScaleOffset = Math.Abs(ScaleOffset);
2285 Vector3 intersectionpoint = ei.ipoint;
2286 Vector3 normal = ei.normal;
2287 // Set the position to the intersection point
2288 Vector3 offset = (normal * (ScaleOffset / 2f));
2289 pos = (intersectionpoint + offset);
2290
2291 //Seems to make no sense to do this as this call is used for rezzing from inventory as well, and with inventory items their size is not always 0.5f
2292 //And in cases when we weren't rezzing from inventory we were re-adding the 0.25 straight after calling this method
2293 // Un-offset the prim (it gets offset later by the consumer method)
2294 //pos.Z -= 0.25F;
2295
2296 }
2297
2298 return pos;
2299 }
2300 else
2301 {
2302 // We don't have a target here, so we're going to raytrace all the objects in the scene.
2303
2304 EntityIntersection ei = m_sceneGraph.GetClosestIntersectingPrim(new Ray(AXOrigin, AXdirection), true, false);
2305
2306 // Un-comment the following line to print the raytrace results to the console.
2307 //m_log.Info("[RAYTRACERESULTS]: Hit:" + ei.HitTF.ToString() + " Point: " + ei.ipoint.ToString() + " Normal: " + ei.normal.ToString());
2308
2309 if (ei.HitTF)
2310 {
2311 pos = ei.ipoint;
2312 }
2313 else
2314 {
2315 // fall back to our stupid functionality
2316 pos = RayEnd;
2317 }
2318
2319 return pos;
2320 }
2321 } 1852 }
2322 else 1853 else
2323 { 1854 {
2324 // fall back to our stupid functionality 1855 spareMS = Math.Max(0, MinFrameTicks - physicsMS2 - agentMS - physicsMS - otherMS);
2325 pos = RayEnd;
2326
2327 //increase height so its above the ground.
2328 //should be getting the normal of the ground at the rez point and using that?
2329 pos.Z += scale.Z / 2f;
2330 return pos;
2331 } 1856 }
2332 }
2333 1857
1858 // Get the total frame time
1859 totalFrameStopwatch.Stop();
1860 preciseTotalFrameTime =
1861 totalFrameStopwatch.Elapsed.TotalMilliseconds;
2334 1862
2335 /// <summary> 1863 // Restart the stopwatch for the total time of the next frame
2336 /// Create a New SceneObjectGroup/Part by raycasting 1864 totalFrameStopwatch.Restart();
2337 /// </summary>
2338 /// <param name="ownerID"></param>
2339 /// <param name="groupID"></param>
2340 /// <param name="RayEnd"></param>
2341 /// <param name="rot"></param>
2342 /// <param name="shape"></param>
2343 /// <param name="bypassRaycast"></param>
2344 /// <param name="RayStart"></param>
2345 /// <param name="RayTargetID"></param>
2346 /// <param name="RayEndIsIntersection"></param>
2347 public virtual void AddNewPrim(UUID ownerID, UUID groupID, Vector3 RayEnd, Quaternion rot, PrimitiveBaseShape shape,
2348 byte bypassRaycast, Vector3 RayStart, UUID RayTargetID,
2349 byte RayEndIsIntersection)
2350 {
2351 Vector3 pos = GetNewRezLocation(RayStart, RayEnd, RayTargetID, rot, bypassRaycast, RayEndIsIntersection, true, new Vector3(0.5f, 0.5f, 0.5f), false);
2352 1865
2353 if (Permissions.CanRezObject(1, ownerID, pos)) 1866 previousFrameTick = m_lastFrameTick;
2354 { 1867 frameMS = Util.EnvironmentTickCountSubtract(m_lastFrameTick);
2355 // rez ON the ground, not IN the ground 1868 m_lastFrameTick = Util.EnvironmentTickCount();
2356 // pos.Z += 0.25F; The rez point should now be correct so that its not in the ground
2357 1869
2358 AddNewPrim(ownerID, groupID, pos, rot, shape); 1870 // if (Frame%m_update_avatars == 0)
1871 // UpdateInWorldTime();
1872 StatsReporter.AddPhysicsFPS(physicsFPS);
1873 StatsReporter.AddTimeDilation(TimeDilation);
1874 StatsReporter.AddFPS(1);
1875
1876 StatsReporter.addFrameMS(frameMS);
1877 StatsReporter.addAgentMS(agentMS);
1878 StatsReporter.addPhysicsMS(physicsMS + physicsMS2);
1879 StatsReporter.addOtherMS(otherMS);
1880 StatsReporter.AddSpareMS(spareMS);
1881 StatsReporter.addScriptLines(m_sceneGraph.GetScriptLPS());
1882
1883 // Send the correct time values to the stats reporter for the
1884 // frame times
1885 StatsReporter.addFrameTimeMilliseconds(preciseTotalFrameTime,
1886 preciseSimFrameTime, precisePhysicsFrameTime, 0.0);
1887
1888 // Send the correct number of frames that the physics library
1889 // has processed to the stats reporter
1890 StatsReporter.addPhysicsFrame(1);
1891
1892 // Optionally warn if a frame takes double the amount of time that it should.
1893 if (DebugUpdates
1894 && Util.EnvironmentTickCountSubtract(
1895 m_lastFrameTick, previousFrameTick) > MinFrameTicks * 2)
1896 m_log.WarnFormat(
1897 "[SCENE]: Frame took {0} ms (desired max {1} ms) in {2}",
1898 Util.EnvironmentTickCountSubtract(m_lastFrameTick, previousFrameTick),
1899 MinFrameTicks,
1900 RegionInfo.RegionName);
1901 }
1902
1903 // Finished updating scene frame, so stop the total frame's Stopwatch
1904 totalFrameStopwatch.Stop();
1905
1906 return spareMS >= 0;
1907 }
1908
1909 public void AddGroupTarget(SceneObjectGroup grp)
1910 {
1911 lock (m_groupsWithTargets)
1912 m_groupsWithTargets[grp.UUID] = grp;
1913 }
1914
1915 public void RemoveGroupTarget(SceneObjectGroup grp)
1916 {
1917 lock (m_groupsWithTargets)
1918 m_groupsWithTargets.Remove(grp.UUID);
1919 }
1920
1921 private void CheckAtTargets()
1922 {
1923 List<SceneObjectGroup> objs = null;
1924
1925 lock (m_groupsWithTargets)
1926 {
1927 if (m_groupsWithTargets.Count != 0)
1928 objs = new List<SceneObjectGroup>(m_groupsWithTargets.Values);
1929 }
1930
1931 if (objs != null)
1932 {
1933 foreach (SceneObjectGroup entry in objs)
1934 entry.checkAtTargets();
1935 }
1936 }
1937
1938 /// <summary>
1939 /// Send out simstats data to all clients
1940 /// </summary>
1941 /// <param name="stats">Stats on the Simulator's performance</param>
1942 private void SendSimStatsPackets(SimStats stats)
1943 {
1944 ForEachRootClient(delegate(IClientAPI client)
1945 {
1946 client.SendSimStats(stats);
1947 });
1948 }
1949
1950 /// <summary>
1951 /// Update the terrain if it needs to be updated.
1952 /// </summary>
1953 private void UpdateTerrain()
1954 {
1955 EventManager.TriggerTerrainTick();
1956 }
1957
1958 /// <summary>
1959 /// Back up queued up changes
1960 /// </summary>
1961 private void UpdateStorageBackup()
1962 {
1963 if (!m_backingup)
1964 {
1965 m_backingup = true;
1966 WorkManager.RunInThread(o => Backup(false), null, string.Format("BackupWaitCallback ({0})", Name));
1967 }
1968 }
1969
1970 /// <summary>
1971 /// Sends out the OnFrame event to the modules
1972 /// </summary>
1973 private void UpdateEvents()
1974 {
1975 m_eventManager.TriggerOnFrame();
1976 }
1977
1978 /// <summary>
1979 /// Backup the scene.
1980 /// </summary>
1981 /// <remarks>
1982 /// This acts as the main method of the backup thread. In a regression test whether the backup thread is not
1983 /// running independently this can be invoked directly.
1984 /// </remarks>
1985 /// <param name="forced">
1986 /// If true, then any changes that have not yet been persisted are persisted. If false,
1987 /// then the persistence decision is left to the backup code (in some situations, such as object persistence,
1988 /// it's much more efficient to backup multiple changes at once rather than every single one).
1989 /// <returns></returns>
1990 public void Backup(bool forced)
1991 {
1992 lock (m_returns)
1993 {
1994 EventManager.TriggerOnBackup(SimulationDataService, forced);
1995 m_backingup = false;
1996
1997 foreach (KeyValuePair<UUID, ReturnInfo> ret in m_returns)
1998 {
1999 UUID transaction = UUID.Random();
2000
2001 GridInstantMessage msg = new GridInstantMessage();
2002 msg.fromAgentID = new Guid(UUID.Zero.ToString()); // From server
2003 msg.toAgentID = new Guid(ret.Key.ToString());
2004 msg.imSessionID = new Guid(transaction.ToString());
2005 msg.timestamp = (uint)Util.UnixTimeSinceEpoch();
2006 msg.fromAgentName = "Server";
2007 msg.dialog = (byte)19; // Object msg
2008 msg.fromGroup = false;
2009 msg.offline = (byte)0;
2010 msg.ParentEstateID = RegionInfo.EstateSettings.ParentEstateID;
2011 msg.Position = Vector3.Zero;
2012 msg.RegionID = RegionInfo.RegionID.Guid;
2013
2014 // We must fill in a null-terminated 'empty' string here since bytes[0] will crash viewer 3.
2015 msg.binaryBucket = Util.StringToBytes256("\0");
2016 if (ret.Value.count > 1)
2017 msg.message = string.Format("Your {0} objects were returned from {1} in region {2} due to {3}", ret.Value.count, ret.Value.location.ToString(), RegionInfo.RegionName, ret.Value.reason);
2018 else
2019 msg.message = string.Format("Your object {0} was returned from {1} in region {2} due to {3}", ret.Value.objectName, ret.Value.location.ToString(), RegionInfo.RegionName, ret.Value.reason);
2020
2021 IMessageTransferModule tr = RequestModuleInterface<IMessageTransferModule>();
2022 if (tr != null)
2023 tr.SendInstantMessage(msg, delegate(bool success) { });
2024 }
2025 m_returns.Clear();
2026 }
2027 }
2028
2029 /// <summary>
2030 /// Synchronous force backup. For deletes and links/unlinks
2031 /// </summary>
2032 /// <param name="group">Object to be backed up</param>
2033 public void ForceSceneObjectBackup(SceneObjectGroup group)
2034 {
2035 if (group != null)
2036 {
2037 group.HasGroupChanged = true;
2038 group.ProcessBackup(SimulationDataService, true);
2039 }
2040 }
2041
2042 /// <summary>
2043 /// Tell an agent that their object has been returned.
2044 /// </summary>
2045 /// <remarks>
2046 /// The actual return is handled by the caller.
2047 /// </remarks>
2048 /// <param name="agentID">Avatar Unique Id</param>
2049 /// <param name="objectName">Name of object returned</param>
2050 /// <param name="location">Location of object returned</param>
2051 /// <param name="reason">Reasion for object return</param>
2052 public void AddReturn(UUID agentID, string objectName, Vector3 location, string reason)
2053 {
2054 lock (m_returns)
2055 {
2056 if (m_returns.ContainsKey(agentID))
2057 {
2058 ReturnInfo info = m_returns[agentID];
2059 info.count++;
2060 m_returns[agentID] = info;
2359 } 2061 }
2360 else 2062 else
2361 { 2063 {
2362 IClientAPI client = null; 2064 ReturnInfo info = new ReturnInfo();
2363 if (TryGetClient(ownerID, out client)) 2065 info.count = 1;
2364 client.SendAlertMessage("You cannot create objects here."); 2066 info.objectName = objectName;
2365 } 2067 info.location = location;
2366 } 2068 info.reason = reason;
2367 2069 m_returns[agentID] = info;
2368 public virtual SceneObjectGroup AddNewPrim( 2070 }
2369 UUID ownerID, UUID groupID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 2071 }
2370 { 2072 }
2371 //m_log.DebugFormat( 2073
2372 // "[SCENE]: Scene.AddNewPrim() pcode {0} called for {1} in {2}", shape.PCode, ownerID, RegionInfo.RegionName); 2074 #endregion
2373 2075
2374 SceneObjectGroup sceneObject = null; 2076 #region Load Terrain
2375 2077
2376 // If an entity creator has been registered for this prim type then use that 2078 /// <summary>
2377 if (m_entityCreators.ContainsKey((PCode)shape.PCode)) 2079 /// Store the terrain in the persistant data store
2378 { 2080 /// </summary>
2379 sceneObject = m_entityCreators[(PCode)shape.PCode].CreateEntity(ownerID, groupID, pos, rot, shape); 2081 public void SaveTerrain()
2082 {
2083 SimulationDataService.StoreTerrain(Heightmap.GetDoubles(), RegionInfo.RegionID);
2084 }
2085
2086 public void StoreWindlightProfile(RegionLightShareData wl)
2087 {
2088 RegionInfo.WindlightSettings = wl;
2089 SimulationDataService.StoreRegionWindlightSettings(wl);
2090 m_eventManager.TriggerOnSaveNewWindlightProfile();
2091 }
2092
2093 public void LoadWindlightProfile()
2094 {
2095 RegionInfo.WindlightSettings = SimulationDataService.LoadRegionWindlightSettings(RegionInfo.RegionID);
2096 m_eventManager.TriggerOnSaveNewWindlightProfile();
2097 }
2098
2099 /// <summary>
2100 /// Loads the World heightmap
2101 /// </summary>
2102 public override void LoadWorldMap()
2103 {
2104 try
2105 {
2106 TerrainData map = SimulationDataService.LoadTerrain(RegionInfo.RegionID, (int)RegionInfo.RegionSizeX, (int)RegionInfo.RegionSizeY, (int)RegionInfo.RegionSizeZ);
2107 if (map == null)
2108 {
2109 // This should be in the Terrain module, but it isn't because
2110 // the heightmap is needed _way_ before the modules are initialized...
2111 IConfig terrainConfig = m_config.Configs["Terrain"];
2112 String m_InitialTerrain = "pinhead-island";
2113 if (terrainConfig != null)
2114 m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain);
2115
2116 m_log.InfoFormat("[TERRAIN]: No default terrain. Generating a new terrain {0}.", m_InitialTerrain);
2117 Heightmap = new TerrainChannel(m_InitialTerrain, (int)RegionInfo.RegionSizeX, (int)RegionInfo.RegionSizeY, (int)RegionInfo.RegionSizeZ);
2118
2119 SimulationDataService.StoreTerrain(Heightmap.GetDoubles(), RegionInfo.RegionID);
2380 } 2120 }
2381 else 2121 else
2382 { 2122 {
2383 // Otherwise, use this default creation code; 2123 Heightmap = new TerrainChannel(map);
2384 sceneObject = new SceneObjectGroup(ownerID, pos, rot, shape); 2124 }
2385 AddNewSceneObject(sceneObject, true); 2125 }
2386 sceneObject.SetGroup(groupID, null); 2126 catch (IOException e)
2387 } 2127 {
2388 2128 m_log.WarnFormat(
2389 if (UserManagementModule != null) 2129 "[TERRAIN]: Scene.cs: LoadWorldMap() - Regenerating as failed with exception {0}{1}",
2390 sceneObject.RootPart.CreatorIdentification = UserManagementModule.GetUserUUI(ownerID); 2130 e.Message, e.StackTrace);
2391 2131
2392 sceneObject.ScheduleGroupForFullUpdate(); 2132 // Non standard region size. If there's an old terrain in the database, it might read past the buffer
2393 2133#pragma warning disable 0162
2394 return sceneObject; 2134 if ((int)Constants.RegionSize != 256)
2395 } 2135 {
2396 2136 Heightmap = new TerrainChannel();
2397 /// <summary> 2137
2398 /// Add an object into the scene that has come from storage 2138 SimulationDataService.StoreTerrain(Heightmap.GetDoubles(), RegionInfo.RegionID);
2399 /// </summary> 2139 }
2400 /// 2140 }
2401 /// <param name="sceneObject"></param> 2141 catch (Exception e)
2402 /// <param name="attachToBackup"> 2142 {
2403 /// If true, changes to the object will be reflected in its persisted data 2143 m_log.WarnFormat(
2404 /// If false, the persisted data will not be changed even if the object in the scene is changed 2144 "[TERRAIN]: Scene.cs: LoadWorldMap() - Failed with exception {0}{1}", e.Message, e.StackTrace);
2405 /// </param> 2145 }
2406 /// <param name="alreadyPersisted"> 2146 }
2407 /// If true, we won't persist this object until it changes 2147
2408 /// If false, we'll persist this object immediately 2148 /// <summary>
2409 /// </param> 2149 /// Register this region with a grid service
2410 /// <param name="sendClientUpdates"> 2150 /// </summary>
2411 /// If true, we send updates to the client to tell it about this object 2151 /// <exception cref="System.Exception">Thrown if registration of the region itself fails.</exception>
2412 /// If false, we leave it up to the caller to do this 2152 public void RegisterRegionWithGrid()
2413 /// </param> 2153 {
2414 /// <returns> 2154 m_sceneGridService.SetScene(this);
2415 /// true if the object was added, false if an object with the same uuid was already in the scene 2155
2416 /// </returns> 2156 //// Unfortunately this needs to be here and it can't be async.
2417 public bool AddRestoredSceneObject( 2157 //// The map tile image is stored in RegionSettings, but it also needs to be
2418 SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates) 2158 //// stored in the GridService, because that's what the world map module uses
2419 { 2159 //// to send the map image UUIDs (of other regions) to the viewer...
2420 if (m_sceneGraph.AddRestoredSceneObject(sceneObject, attachToBackup, alreadyPersisted, sendClientUpdates)) 2160 if (m_generateMaptiles)
2421 { 2161 RegenerateMaptile();
2422 EventManager.TriggerObjectAddedToScene(sceneObject);
2423 return true;
2424 }
2425 2162
2426 return false; 2163 GridRegion region = new GridRegion(RegionInfo);
2164 string error = GridService.RegisterRegion(RegionInfo.ScopeID, region);
2165 // m_log.DebugFormat("[SCENE]: RegisterRegionWithGrid. name={0},id={1},loc=<{2},{3}>,size=<{4},{5}>",
2166 // m_regionName,
2167 // RegionInfo.RegionID,
2168 // RegionInfo.RegionLocX, RegionInfo.RegionLocY,
2169 // RegionInfo.RegionSizeX, RegionInfo.RegionSizeY);
2427 2170
2428 } 2171 if (error != String.Empty)
2429 2172 throw new Exception(error);
2430 /// <summary> 2173 }
2431 /// Add an object into the scene that has come from storage
2432 /// </summary>
2433 ///
2434 /// <param name="sceneObject"></param>
2435 /// <param name="attachToBackup">
2436 /// If true, changes to the object will be reflected in its persisted data
2437 /// If false, the persisted data will not be changed even if the object in the scene is changed
2438 /// </param>
2439 /// <param name="alreadyPersisted">
2440 /// If true, we won't persist this object until it changes
2441 /// If false, we'll persist this object immediately
2442 /// </param>
2443 /// <returns>
2444 /// true if the object was added, false if an object with the same uuid was already in the scene
2445 /// </returns>
2446 public bool AddRestoredSceneObject(
2447 SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted)
2448 {
2449 return AddRestoredSceneObject(sceneObject, attachToBackup, alreadyPersisted, true);
2450 }
2451
2452 /// <summary>
2453 /// Add a newly created object to the scene. Updates are also sent to viewers.
2454 /// </summary>
2455 /// <param name="sceneObject"></param>
2456 /// <param name="attachToBackup">
2457 /// If true, the object is made persistent into the scene.
2458 /// If false, the object will not persist over server restarts
2459 /// </param>
2460 /// <returns>true if the object was added. false if not</returns>
2461 public bool AddNewSceneObject(SceneObjectGroup sceneObject, bool attachToBackup)
2462 {
2463 return AddNewSceneObject(sceneObject, attachToBackup, true);
2464 }
2465
2466 /// <summary>
2467 /// Add a newly created object to the scene
2468 /// </summary>
2469 /// <param name="sceneObject"></param>
2470 /// <param name="attachToBackup">
2471 /// If true, the object is made persistent into the scene.
2472 /// If false, the object will not persist over server restarts
2473 /// </param>
2474 /// <param name="sendClientUpdates">
2475 /// If true, updates for the new scene object are sent to all viewers in range.
2476 /// If false, it is left to the caller to schedule the update
2477 /// </param>
2478 /// <returns>true if the object was added. false if not</returns>
2479 public bool AddNewSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates)
2480 {
2481 if (m_sceneGraph.AddNewSceneObject(sceneObject, attachToBackup, sendClientUpdates))
2482 {
2483 EventManager.TriggerObjectAddedToScene(sceneObject);
2484 return true;
2485 }
2486
2487 return false;
2488 }
2489
2490 /// <summary>
2491 /// Add a newly created object to the scene.
2492 /// </summary>
2493 /// <remarks>
2494 /// This method does not send updates to the client - callers need to handle this themselves.
2495 /// </remarks>
2496 /// <param name="sceneObject"></param>
2497 /// <param name="attachToBackup"></param>
2498 /// <param name="pos">Position of the object. If null then the position stored in the object is used.</param>
2499 /// <param name="rot">Rotation of the object. If null then the rotation stored in the object is used.</param>
2500 /// <param name="vel">Velocity of the object. This parameter only has an effect if the object is physical</param>
2501 /// <returns></returns>
2502 public bool AddNewSceneObject(
2503 SceneObjectGroup sceneObject, bool attachToBackup, Vector3? pos, Quaternion? rot, Vector3 vel)
2504 {
2505 if (m_sceneGraph.AddNewSceneObject(sceneObject, attachToBackup, pos, rot, vel))
2506 {
2507 EventManager.TriggerObjectAddedToScene(sceneObject);
2508 return true;
2509 }
2510 2174
2511 return false; 2175 #endregion
2512 }
2513
2514 /// <summary>
2515 /// Delete every object from the scene. This does not include attachments worn by avatars.
2516 /// </summary>
2517 public void DeleteAllSceneObjects()
2518 {
2519 lock (Entities)
2520 {
2521 EntityBase[] entities = Entities.GetEntities();
2522 foreach (EntityBase e in entities)
2523 {
2524 if (e is SceneObjectGroup)
2525 {
2526 SceneObjectGroup sog = (SceneObjectGroup)e;
2527 if (!sog.IsAttachment)
2528 DeleteSceneObject((SceneObjectGroup)e, false);
2529 }
2530 }
2531 }
2532 }
2533
2534 /// <summary>
2535 /// Synchronously delete the given object from the scene.
2536 /// </summary>
2537 /// <remarks>
2538 /// Scripts are also removed.
2539 /// </remarks>
2540 /// <param name="group">Object Id</param>
2541 /// <param name="silent">Suppress broadcasting changes to other clients.</param>
2542 public void DeleteSceneObject(SceneObjectGroup group, bool silent)
2543 {
2544 DeleteSceneObject(group, silent, true);
2545 }
2546
2547 /// <summary>
2548 /// Synchronously delete the given object from the scene.
2549 /// </summary>
2550 /// <param name="group">Object Id</param>
2551 /// <param name="silent">Suppress broadcasting changes to other clients.</param>
2552 /// <param name="removeScripts">If true, then scripts are removed. If false, then they are only stopped.</para>
2553 public void DeleteSceneObject(SceneObjectGroup group, bool silent, bool removeScripts)
2554 {
2555// m_log.DebugFormat("[SCENE]: Deleting scene object {0} {1}", group.Name, group.UUID);
2556
2557 if (removeScripts)
2558 group.RemoveScriptInstances(true);
2559 else
2560 group.StopScriptInstances();
2561 2176
2562 SceneObjectPart[] partList = group.Parts; 2177 #region Load Land
2563 2178
2564 foreach (SceneObjectPart part in partList) 2179 /// <summary>
2565 { 2180 /// Loads all Parcel data from the datastore for region identified by regionID
2566 if (part.KeyframeMotion != null) 2181 /// </summary>
2567 { 2182 /// <param name="regionID">Unique Identifier of the Region to load parcel data for</param>
2568 part.KeyframeMotion.Delete(); 2183 public void loadAllLandObjectsFromStorage(UUID regionID)
2569 part.KeyframeMotion = null; 2184 {
2570 } 2185 m_log.Info("[SCENE]: Loading land objects from storage");
2186 List<LandData> landData = SimulationDataService.LoadLandObjects(regionID);
2571 2187
2572 if (part.IsJoint() && ((part.Flags & PrimFlags.Physics) != 0)) 2188 if (LandChannel != null)
2573 { 2189 {
2574 PhysicsScene.RequestJointDeletion(part.Name); // FIXME: what if the name changed? 2190 if (landData.Count == 0)
2575 } 2191 {
2576 else if (part.PhysActor != null) 2192 EventManager.TriggerNoticeNoLandDataFromStorage();
2577 {
2578 part.RemoveFromPhysics();
2579 }
2580 } 2193 }
2581 2194 else
2582 if (UnlinkSceneObject(group, false))
2583 { 2195 {
2584 EventManager.TriggerObjectBeingRemovedFromScene(group); 2196 EventManager.TriggerIncomingLandDataFromStorage(landData);
2585 EventManager.TriggerParcelPrimCountTainted();
2586 } 2197 }
2198 }
2199 else
2200 {
2201 m_log.Error("[SCENE]: Land Channel is not defined. Cannot load from storage!");
2202 }
2203 }
2587 2204
2588 group.DeleteGroupFromScene(silent); 2205 #endregion
2589 2206
2590// m_log.DebugFormat("[SCENE]: Exit DeleteSceneObject() for {0} {1}", group.Name, group.UUID); 2207 #region Primitives Methods
2591 }
2592 2208
2593 /// <summary> 2209 /// <summary>
2594 /// Unlink the given object from the scene. Unlike delete, this just removes the record of the object - the 2210 /// Loads the World's objects
2595 /// object itself is not destroyed. 2211 /// </summary>
2596 /// </summary> 2212 /// <param name="regionID"></param>
2597 /// <param name="so">The scene object.</param> 2213 public virtual void LoadPrimsFromStorage(UUID regionID)
2598 /// <param name="softDelete">If true, only deletes from scene, but keeps the object in the database.</param> 2214 {
2599 /// <returns>true if the object was in the scene, false if it was not</returns> 2215 LoadingPrims = true;
2600 public bool UnlinkSceneObject(SceneObjectGroup so, bool softDelete) 2216 m_log.Info("[SCENE]: Loading objects from datastore");
2601 {
2602 if (m_sceneGraph.DeleteSceneObject(so.UUID, softDelete))
2603 {
2604 if (!softDelete)
2605 {
2606 // If the group contains prims whose SceneGroupID is incorrect then force a
2607 // database update, because RemoveObject() works by searching on the SceneGroupID.
2608 // This is an expensive thing to do so only do it if absolutely necessary.
2609 if (so.GroupContainsForeignPrims)
2610 ForceSceneObjectBackup(so);
2611 2217
2612 so.DetachFromBackup(); 2218 List<SceneObjectGroup> PrimsFromDB = SimulationDataService.LoadObjects(regionID);
2613 SimulationDataService.RemoveObject(so.UUID, RegionInfo.RegionID);
2614 }
2615
2616 // We need to keep track of this state in case this group is still queued for further backup.
2617 so.IsDeleted = true;
2618 2219
2619 return true; 2220 m_log.InfoFormat("[SCENE]: Loaded {0} objects from the datastore", PrimsFromDB.Count);
2620 } 2221
2222 foreach (SceneObjectGroup group in PrimsFromDB)
2223 {
2224 AddRestoredSceneObject(group, true, true);
2225 EventManager.TriggerOnSceneObjectLoaded(group);
2226 SceneObjectPart rootPart = group.GetPart(group.UUID);
2227 rootPart.Flags &= ~PrimFlags.Scripted;
2228 rootPart.TrimPermissions();
2229
2230 // Don't do this here - it will get done later on when sculpt data is loaded.
2231 // group.CheckSculptAndLoad();
2232 }
2233
2234 LoadingPrims = false;
2235 EventManager.TriggerPrimsLoaded(this);
2236 }
2621 2237
2238 public bool SupportsRayCastFiltered()
2239 {
2240 if (PhysicsScene == null)
2622 return false; 2241 return false;
2623 } 2242 return PhysicsScene.SupportsRaycastWorldFiltered();
2624 2243 }
2625 /// <summary>
2626 /// Move the given scene object into a new region depending on which region its absolute position has moved
2627 /// into.
2628 ///
2629 /// </summary>
2630 /// <param name="attemptedPosition">the attempted out of region position of the scene object</param>
2631 /// <param name="grp">the scene object that we're crossing</param>
2632 public void CrossPrimGroupIntoNewRegion(Vector3 attemptedPosition, SceneObjectGroup grp, bool silent)
2633 {
2634 if (grp == null)
2635 return;
2636 if (grp.IsDeleted)
2637 return;
2638
2639 if (grp.RootPart.DIE_AT_EDGE)
2640 {
2641 // We remove the object here
2642 try
2643 {
2644 DeleteSceneObject(grp, false);
2645 }
2646 catch (Exception)
2647 {
2648 m_log.Warn("[SCENE]: exception when trying to remove the prim that crossed the border.");
2649 }
2650 return;
2651 }
2652
2653 if (grp.RootPart.RETURN_AT_EDGE)
2654 {
2655 // We remove the object here
2656 try
2657 {
2658 List<SceneObjectGroup> objects = new List<SceneObjectGroup>();
2659 objects.Add(grp);
2660 SceneObjectGroup[] objectsArray = objects.ToArray();
2661 returnObjects(objectsArray, UUID.Zero);
2662 }
2663 catch (Exception)
2664 {
2665 m_log.Warn("[SCENE]: exception when trying to return the prim that crossed the border.");
2666 }
2667 return;
2668 }
2669 2244
2670 if (EntityTransferModule != null) 2245 public object RayCastFiltered(Vector3 position, Vector3 direction, float length, int Count, RayFilterFlags filter)
2671 EntityTransferModule.Cross(grp, attemptedPosition, silent); 2246 {
2672 } 2247 if (PhysicsScene == null)
2673 2248 return null;
2674 // Simple test to see if a position is in the current region. 2249 return PhysicsScene.RaycastWorld(position, direction, length, Count, filter);
2675 // This test is mostly used to see if a region crossing is necessary. 2250 }
2676 // Assuming the position is relative to the region so anything outside its bounds. 2251
2677 // Return 'true' if position inside region. 2252 /// <summary>
2678 public bool PositionIsInCurrentRegion(Vector3 pos) 2253 /// Gets a new rez location based on the raycast and the size of the object that is being rezzed.
2679 { 2254 /// </summary>
2680 bool ret = false; 2255 /// <param name="RayStart"></param>
2681 int xx = (int)Math.Floor(pos.X); 2256 /// <param name="RayEnd"></param>
2682 int yy = (int)Math.Floor(pos.Y); 2257 /// <param name="RayTargetID"></param>
2683 if (xx < 0 || yy < 0) 2258 /// <param name="rot"></param>
2684 return false; 2259 /// <param name="bypassRayCast"></param>
2685 2260 /// <param name="RayEndIsIntersection"></param>
2686 IRegionCombinerModule regionCombinerModule = RequestModuleInterface<IRegionCombinerModule>(); 2261 /// <param name="frontFacesOnly"></param>
2687 if (regionCombinerModule == null) 2262 /// <param name="scale"></param>
2688 { 2263 /// <param name="FaceCenter"></param>
2689 // Regular region. Just check for region size 2264 /// <returns></returns>
2690 if (xx < RegionInfo.RegionSizeX && yy < RegionInfo.RegionSizeY ) 2265 public Vector3 GetNewRezLocation(Vector3 RayStart, Vector3 RayEnd, UUID RayTargetID, Quaternion rot, byte bypassRayCast, byte RayEndIsIntersection, bool frontFacesOnly, Vector3 scale, bool FaceCenter)
2691 ret = true; 2266 {
2267 Vector3 pos = Vector3.Zero;
2268 if (RayEndIsIntersection == (byte)1)
2269 {
2270 pos = RayEnd;
2271 return pos;
2272 }
2273
2274 if (RayTargetID != UUID.Zero)
2275 {
2276 SceneObjectPart target = GetSceneObjectPart(RayTargetID);
2277
2278 Vector3 direction = Vector3.Normalize(RayEnd - RayStart);
2279 Vector3 AXOrigin = RayStart;
2280 Vector3 AXdirection = direction;
2281
2282 if (target != null)
2283 {
2284 pos = target.AbsolutePosition;
2285 //m_log.Info("[OBJECT_REZ]: TargetPos: " + pos.ToString() + ", RayStart: " + RayStart.ToString() + ", RayEnd: " + RayEnd.ToString() + ", Volume: " + Util.GetDistanceTo(RayStart,RayEnd).ToString() + ", mag1: " + Util.GetMagnitude(RayStart).ToString() + ", mag2: " + Util.GetMagnitude(RayEnd).ToString());
2286
2287 // TODO: Raytrace better here
2288
2289 //EntityIntersection ei = m_sceneGraph.GetClosestIntersectingPrim(new Ray(AXOrigin, AXdirection));
2290 Ray NewRay = new Ray(AXOrigin, AXdirection);
2291
2292 // Ray Trace against target here
2293 EntityIntersection ei = target.TestIntersectionOBB(NewRay, Quaternion.Identity, frontFacesOnly, FaceCenter);
2294
2295 // Un-comment out the following line to Get Raytrace results printed to the console.
2296 // m_log.Info("[RAYTRACERESULTS]: Hit:" + ei.HitTF.ToString() + " Point: " + ei.ipoint.ToString() + " Normal: " + ei.normal.ToString());
2297 float ScaleOffset = 0.5f;
2298
2299 // If we hit something
2300 if (ei.HitTF)
2301 {
2302 Vector3 scaleComponent = ei.AAfaceNormal;
2303 if (scaleComponent.X != 0) ScaleOffset = scale.X;
2304 if (scaleComponent.Y != 0) ScaleOffset = scale.Y;
2305 if (scaleComponent.Z != 0) ScaleOffset = scale.Z;
2306 ScaleOffset = Math.Abs(ScaleOffset);
2307 Vector3 intersectionpoint = ei.ipoint;
2308 Vector3 normal = ei.normal;
2309 // Set the position to the intersection point
2310 Vector3 offset = (normal * (ScaleOffset / 2f));
2311 pos = (intersectionpoint + offset);
2312
2313 //Seems to make no sense to do this as this call is used for rezzing from inventory as well, and with inventory items their size is not always 0.5f
2314 //And in cases when we weren't rezzing from inventory we were re-adding the 0.25 straight after calling this method
2315 // Un-offset the prim (it gets offset later by the consumer method)
2316 //pos.Z -= 0.25F;
2317
2318 }
2319
2320 return pos;
2692 } 2321 }
2693 else 2322 else
2694 { 2323 {
2695 // We're in a mega-region so see if we are still in that larger region 2324 // We don't have a target here, so we're going to raytrace all the objects in the scene.
2696 ret = regionCombinerModule.PositionIsInMegaregion(this.RegionInfo.RegionID, xx, yy); 2325
2697 } 2326 EntityIntersection ei = m_sceneGraph.GetClosestIntersectingPrim(new Ray(AXOrigin, AXdirection), true, false);
2698 2327
2699 return ret; 2328 // Un-comment the following line to print the raytrace results to the console.
2700 2329 //m_log.Info("[RAYTRACERESULTS]: Hit:" + ei.HitTF.ToString() + " Point: " + ei.ipoint.ToString() + " Normal: " + ei.normal.ToString());
2701 } 2330
2702 2331 if (ei.HitTF)
2703 /// <summary> 2332 {
2704 /// Called when objects or attachments cross the border, or teleport, between regions. 2333 pos = ei.ipoint;
2705 /// </summary> 2334 }
2706 /// <param name="sog"></param> 2335 else
2707 /// <returns></returns> 2336 {
2708 public bool IncomingCreateObject(Vector3 newPosition, ISceneObject sog) 2337 // fall back to our stupid functionality
2709 { 2338 pos = RayEnd;
2710 //m_log.DebugFormat(" >>> IncomingCreateObject(sog) <<< {0} deleted? {1} isAttach? {2}", ((SceneObjectGroup)sog).AbsolutePosition, 2339 }
2711 // ((SceneObjectGroup)sog).IsDeleted, ((SceneObjectGroup)sog).RootPart.IsAttachment); 2340
2341 return pos;
2342 }
2343 }
2344 else
2345 {
2346 // fall back to our stupid functionality
2347 pos = RayEnd;
2348
2349 //increase height so its above the ground.
2350 //should be getting the normal of the ground at the rez point and using that?
2351 pos.Z += scale.Z / 2f;
2352 return pos;
2353 }
2354 }
2355
2356
2357 /// <summary>
2358 /// Create a New SceneObjectGroup/Part by raycasting
2359 /// </summary>
2360 /// <param name="ownerID"></param>
2361 /// <param name="groupID"></param>
2362 /// <param name="RayEnd"></param>
2363 /// <param name="rot"></param>
2364 /// <param name="shape"></param>
2365 /// <param name="bypassRaycast"></param>
2366 /// <param name="RayStart"></param>
2367 /// <param name="RayTargetID"></param>
2368 /// <param name="RayEndIsIntersection"></param>
2369 public virtual void AddNewPrim(UUID ownerID, UUID groupID, Vector3 RayEnd, Quaternion rot, PrimitiveBaseShape shape,
2370 byte bypassRaycast, Vector3 RayStart, UUID RayTargetID,
2371 byte RayEndIsIntersection)
2372 {
2373 Vector3 pos = GetNewRezLocation(RayStart, RayEnd, RayTargetID, rot, bypassRaycast, RayEndIsIntersection, true, new Vector3(0.5f, 0.5f, 0.5f), false);
2374
2375 if (Permissions.CanRezObject(1, ownerID, pos))
2376 {
2377 // rez ON the ground, not IN the ground
2378 // pos.Z += 0.25F; The rez point should now be correct so that its not in the ground
2379
2380 AddNewPrim(ownerID, groupID, pos, rot, shape);
2381 }
2382 else
2383 {
2384 IClientAPI client = null;
2385 if (TryGetClient(ownerID, out client))
2386 client.SendAlertMessage("You cannot create objects here.");
2387 }
2388 }
2389
2390 public virtual SceneObjectGroup AddNewPrim(
2391 UUID ownerID, UUID groupID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
2392 {
2393 //m_log.DebugFormat(
2394 // "[SCENE]: Scene.AddNewPrim() pcode {0} called for {1} in {2}", shape.PCode, ownerID, RegionInfo.RegionName);
2395
2396 SceneObjectGroup sceneObject = null;
2397
2398 // If an entity creator has been registered for this prim type then use that
2399 if (m_entityCreators.ContainsKey((PCode)shape.PCode))
2400 {
2401 sceneObject = m_entityCreators[(PCode)shape.PCode].CreateEntity(ownerID, groupID, pos, rot, shape);
2402 }
2403 else
2404 {
2405 // Otherwise, use this default creation code;
2406 sceneObject = new SceneObjectGroup(ownerID, pos, rot, shape);
2407 AddNewSceneObject(sceneObject, true);
2408 sceneObject.SetGroup(groupID, null);
2409 }
2410
2411 if (UserManagementModule != null)
2412 sceneObject.RootPart.CreatorIdentification = UserManagementModule.GetUserUUI(ownerID);
2413
2414 sceneObject.ScheduleGroupForFullUpdate();
2415
2416 return sceneObject;
2417 }
2418
2419 /// <summary>
2420 /// Add an object into the scene that has come from storage
2421 /// </summary>
2422 ///
2423 /// <param name="sceneObject"></param>
2424 /// <param name="attachToBackup">
2425 /// If true, changes to the object will be reflected in its persisted data
2426 /// If false, the persisted data will not be changed even if the object in the scene is changed
2427 /// </param>
2428 /// <param name="alreadyPersisted">
2429 /// If true, we won't persist this object until it changes
2430 /// If false, we'll persist this object immediately
2431 /// </param>
2432 /// <param name="sendClientUpdates">
2433 /// If true, we send updates to the client to tell it about this object
2434 /// If false, we leave it up to the caller to do this
2435 /// </param>
2436 /// <returns>
2437 /// true if the object was added, false if an object with the same uuid was already in the scene
2438 /// </returns>
2439 public bool AddRestoredSceneObject(
2440 SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates)
2441 {
2442 if (m_sceneGraph.AddRestoredSceneObject(sceneObject, attachToBackup, alreadyPersisted, sendClientUpdates))
2443 {
2444 EventManager.TriggerObjectAddedToScene(sceneObject);
2445 return true;
2446 }
2447
2448 return false;
2449
2450 }
2451
2452 /// <summary>
2453 /// Add an object into the scene that has come from storage
2454 /// </summary>
2455 ///
2456 /// <param name="sceneObject"></param>
2457 /// <param name="attachToBackup">
2458 /// If true, changes to the object will be reflected in its persisted data
2459 /// If false, the persisted data will not be changed even if the object in the scene is changed
2460 /// </param>
2461 /// <param name="alreadyPersisted">
2462 /// If true, we won't persist this object until it changes
2463 /// If false, we'll persist this object immediately
2464 /// </param>
2465 /// <returns>
2466 /// true if the object was added, false if an object with the same uuid was already in the scene
2467 /// </returns>
2468 public bool AddRestoredSceneObject(
2469 SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted)
2470 {
2471 return AddRestoredSceneObject(sceneObject, attachToBackup, alreadyPersisted, true);
2472 }
2473
2474 /// <summary>
2475 /// Add a newly created object to the scene. Updates are also sent to viewers.
2476 /// </summary>
2477 /// <param name="sceneObject"></param>
2478 /// <param name="attachToBackup">
2479 /// If true, the object is made persistent into the scene.
2480 /// If false, the object will not persist over server restarts
2481 /// </param>
2482 /// <returns>true if the object was added. false if not</returns>
2483 public bool AddNewSceneObject(SceneObjectGroup sceneObject, bool attachToBackup)
2484 {
2485 return AddNewSceneObject(sceneObject, attachToBackup, true);
2486 }
2487
2488 /// <summary>
2489 /// Add a newly created object to the scene
2490 /// </summary>
2491 /// <param name="sceneObject"></param>
2492 /// <param name="attachToBackup">
2493 /// If true, the object is made persistent into the scene.
2494 /// If false, the object will not persist over server restarts
2495 /// </param>
2496 /// <param name="sendClientUpdates">
2497 /// If true, updates for the new scene object are sent to all viewers in range.
2498 /// If false, it is left to the caller to schedule the update
2499 /// </param>
2500 /// <returns>true if the object was added. false if not</returns>
2501 public bool AddNewSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates)
2502 {
2503 if (m_sceneGraph.AddNewSceneObject(sceneObject, attachToBackup, sendClientUpdates))
2504 {
2505 EventManager.TriggerObjectAddedToScene(sceneObject);
2506 return true;
2507 }
2508
2509 return false;
2510 }
2511
2512 /// <summary>
2513 /// Add a newly created object to the scene.
2514 /// </summary>
2515 /// <remarks>
2516 /// This method does not send updates to the client - callers need to handle this themselves.
2517 /// </remarks>
2518 /// <param name="sceneObject"></param>
2519 /// <param name="attachToBackup"></param>
2520 /// <param name="pos">Position of the object. If null then the position stored in the object is used.</param>
2521 /// <param name="rot">Rotation of the object. If null then the rotation stored in the object is used.</param>
2522 /// <param name="vel">Velocity of the object. This parameter only has an effect if the object is physical</param>
2523 /// <returns></returns>
2524 public bool AddNewSceneObject(
2525 SceneObjectGroup sceneObject, bool attachToBackup, Vector3? pos, Quaternion? rot, Vector3 vel)
2526 {
2527 if (m_sceneGraph.AddNewSceneObject(sceneObject, attachToBackup, pos, rot, vel))
2528 {
2529 EventManager.TriggerObjectAddedToScene(sceneObject);
2530 return true;
2531 }
2532
2533 return false;
2534 }
2535
2536 /// <summary>
2537 /// Delete every object from the scene. This does not include attachments worn by avatars.
2538 /// </summary>
2539 public void DeleteAllSceneObjects()
2540 {
2541 lock (Entities)
2542 {
2543 EntityBase[] entities = Entities.GetEntities();
2544 foreach (EntityBase e in entities)
2545 {
2546 if (e is SceneObjectGroup)
2547 {
2548 SceneObjectGroup sog = (SceneObjectGroup)e;
2549 if (!sog.IsAttachment)
2550 DeleteSceneObject((SceneObjectGroup)e, false);
2551 }
2552 }
2553 }
2554 }
2555
2556 /// <summary>
2557 /// Synchronously delete the given object from the scene.
2558 /// </summary>
2559 /// <remarks>
2560 /// Scripts are also removed.
2561 /// </remarks>
2562 /// <param name="group">Object Id</param>
2563 /// <param name="silent">Suppress broadcasting changes to other clients.</param>
2564 public void DeleteSceneObject(SceneObjectGroup group, bool silent)
2565 {
2566 DeleteSceneObject(group, silent, true);
2567 }
2568
2569 /// <summary>
2570 /// Synchronously delete the given object from the scene.
2571 /// </summary>
2572 /// <param name="group">Object Id</param>
2573 /// <param name="silent">Suppress broadcasting changes to other clients.</param>
2574 /// <param name="removeScripts">If true, then scripts are removed. If false, then they are only stopped.</para>
2575 public void DeleteSceneObject(SceneObjectGroup group, bool silent, bool removeScripts)
2576 {
2577 // m_log.DebugFormat("[SCENE]: Deleting scene object {0} {1}", group.Name, group.UUID);
2578
2579 if (removeScripts)
2580 group.RemoveScriptInstances(true);
2581 else
2582 group.StopScriptInstances();
2583
2584 SceneObjectPart[] partList = group.Parts;
2585
2586 foreach (SceneObjectPart part in partList)
2587 {
2588 if (part.KeyframeMotion != null)
2589 {
2590 part.KeyframeMotion.Delete();
2591 part.KeyframeMotion = null;
2592 }
2593
2594 if (part.IsJoint() && ((part.Flags & PrimFlags.Physics) != 0))
2595 {
2596 PhysicsScene.RequestJointDeletion(part.Name); // FIXME: what if the name changed?
2597 }
2598 else if (part.PhysActor != null)
2599 {
2600 part.RemoveFromPhysics();
2601 }
2602 }
2603
2604 if (UnlinkSceneObject(group, false))
2605 {
2606 EventManager.TriggerObjectBeingRemovedFromScene(group);
2607 EventManager.TriggerParcelPrimCountTainted();
2608 }
2609
2610 group.DeleteGroupFromScene(silent);
2611
2612 // m_log.DebugFormat("[SCENE]: Exit DeleteSceneObject() for {0} {1}", group.Name, group.UUID);
2613 }
2614
2615 /// <summary>
2616 /// Unlink the given object from the scene. Unlike delete, this just removes the record of the object - the
2617 /// object itself is not destroyed.
2618 /// </summary>
2619 /// <param name="so">The scene object.</param>
2620 /// <param name="softDelete">If true, only deletes from scene, but keeps the object in the database.</param>
2621 /// <returns>true if the object was in the scene, false if it was not</returns>
2622 public bool UnlinkSceneObject(SceneObjectGroup so, bool softDelete)
2623 {
2624 if (m_sceneGraph.DeleteSceneObject(so.UUID, softDelete))
2625 {
2626 if (!softDelete)
2627 {
2628 // If the group contains prims whose SceneGroupID is incorrect then force a
2629 // database update, because RemoveObject() works by searching on the SceneGroupID.
2630 // This is an expensive thing to do so only do it if absolutely necessary.
2631 if (so.GroupContainsForeignPrims)
2632 ForceSceneObjectBackup(so);
2633
2634 so.DetachFromBackup();
2635 SimulationDataService.RemoveObject(so.UUID, RegionInfo.RegionID);
2636 }
2637
2638 // We need to keep track of this state in case this group is still queued for further backup.
2639 so.IsDeleted = true;
2712 2640
2713 SceneObjectGroup newObject; 2641 return true;
2642 }
2643
2644 return false;
2645 }
2646
2647 /// <summary>
2648 /// Move the given scene object into a new region depending on which region its absolute position has moved
2649 /// into.
2650 ///
2651 /// </summary>
2652 /// <param name="attemptedPosition">the attempted out of region position of the scene object</param>
2653 /// <param name="grp">the scene object that we're crossing</param>
2654 public void CrossPrimGroupIntoNewRegion(Vector3 attemptedPosition, SceneObjectGroup grp, bool silent)
2655 {
2656 if (grp == null)
2657 return;
2658 if (grp.IsDeleted)
2659 return;
2660
2661 if (grp.RootPart.DIE_AT_EDGE)
2662 {
2663 // We remove the object here
2714 try 2664 try
2715 { 2665 {
2716 newObject = (SceneObjectGroup)sog; 2666 DeleteSceneObject(grp, false);
2717 } 2667 }
2718 catch (Exception e) 2668 catch (Exception)
2719 { 2669 {
2720 m_log.WarnFormat("[INTERREGION]: Problem casting object, exception {0}{1}", e.Message, e.StackTrace); 2670 m_log.Warn("[SCENE]: exception when trying to remove the prim that crossed the border.");
2721 return false;
2722 } 2671 }
2672 return;
2673 }
2723 2674
2724 if (!EntityTransferModule.HandleIncomingSceneObject(newObject, newPosition)) 2675 if (grp.RootPart.RETURN_AT_EDGE)
2725 return false; 2676 {
2726 2677 // We remove the object here
2727 // Do this as late as possible so that listeners have full access to the incoming object 2678 try
2728 EventManager.TriggerOnIncomingSceneObject(newObject); 2679 {
2729 2680 List<SceneObjectGroup> objects = new List<SceneObjectGroup>();
2730 return true; 2681 objects.Add(grp);
2731 } 2682 SceneObjectGroup[] objectsArray = objects.ToArray();
2732 2683 returnObjects(objectsArray, UUID.Zero);
2733 /// <summary>
2734 /// Adds a Scene Object group to the Scene.
2735 /// Verifies that the creator of the object is not banned from the simulator.
2736 /// Checks if the item is an Attachment
2737 /// </summary>
2738 /// <param name="sceneObject"></param>
2739 /// <returns>True if the SceneObjectGroup was added, False if it was not</returns>
2740 public bool AddSceneObject(SceneObjectGroup sceneObject)
2741 {
2742 // Force allocation of new LocalId
2743 //
2744 SceneObjectPart[] parts = sceneObject.Parts;
2745 for (int i = 0; i < parts.Length; i++)
2746 parts[i].LocalId = 0;
2747
2748 if (sceneObject.IsAttachmentCheckFull()) // Attachment
2749 {
2750 sceneObject.RootPart.AddFlag(PrimFlags.TemporaryOnRez);
2751 sceneObject.RootPart.AddFlag(PrimFlags.Phantom);
2752
2753 // Don't sent a full update here because this will cause full updates to be sent twice for
2754 // attachments on region crossings, resulting in viewer glitches.
2755 AddRestoredSceneObject(sceneObject, false, false, false);
2756
2757 // Handle attachment special case
2758 SceneObjectPart RootPrim = sceneObject.RootPart;
2759
2760 // Fix up attachment Parent Local ID
2761 ScenePresence sp = GetScenePresence(sceneObject.OwnerID);
2762
2763 if (sp != null)
2764 {
2765 SceneObjectGroup grp = sceneObject;
2766
2767// m_log.DebugFormat(
2768// "[ATTACHMENT]: Received attachment {0}, inworld asset id {1}", grp.FromItemID, grp.UUID);
2769// m_log.DebugFormat(
2770// "[ATTACHMENT]: Attach to avatar {0} at position {1}", sp.UUID, grp.AbsolutePosition);
2771
2772 RootPrim.RemFlag(PrimFlags.TemporaryOnRez);
2773
2774 // We must currently not resume scripts at this stage since AttachmentsModule does not have the
2775 // information that this is due to a teleport/border cross rather than an ordinary attachment.
2776 // We currently do this in Scene.MakeRootAgent() instead.
2777 if (AttachmentsModule != null)
2778 AttachmentsModule.AttachObject(sp, grp, 0, false, false, true);
2779 }
2780 else
2781 {
2782 RootPrim.RemFlag(PrimFlags.TemporaryOnRez);
2783 RootPrim.AddFlag(PrimFlags.TemporaryOnRez);
2784 }
2785 } 2684 }
2786 else 2685 catch (Exception)
2787 { 2686 {
2788 AddRestoredSceneObject(sceneObject, true, false); 2687 m_log.Warn("[SCENE]: exception when trying to return the prim that crossed the border.");
2789 } 2688 }
2689 return;
2690 }
2790 2691
2791 return true; 2692 if (EntityTransferModule != null)
2792 } 2693 EntityTransferModule.Cross(grp, attemptedPosition, silent);
2694 }
2695
2696 // Simple test to see if a position is in the current region.
2697 // This test is mostly used to see if a region crossing is necessary.
2698 // Assuming the position is relative to the region so anything outside its bounds.
2699 // Return 'true' if position inside region.
2700 public bool PositionIsInCurrentRegion(Vector3 pos)
2701 {
2702 bool ret = false;
2703 int xx = (int)Math.Floor(pos.X);
2704 int yy = (int)Math.Floor(pos.Y);
2705 if (xx < 0 || yy < 0)
2706 return false;
2793 2707
2794 #endregion 2708 IRegionCombinerModule regionCombinerModule = RequestModuleInterface<IRegionCombinerModule>();
2709 if (regionCombinerModule == null)
2710 {
2711 // Regular region. Just check for region size
2712 if (xx < RegionInfo.RegionSizeX && yy < RegionInfo.RegionSizeY)
2713 ret = true;
2714 }
2715 else
2716 {
2717 // We're in a mega-region so see if we are still in that larger region
2718 ret = regionCombinerModule.PositionIsInMegaregion(this.RegionInfo.RegionID, xx, yy);
2719 }
2720
2721 return ret;
2722
2723 }
2724
2725 /// <summary>
2726 /// Called when objects or attachments cross the border, or teleport, between regions.
2727 /// </summary>
2728 /// <param name="sog"></param>
2729 /// <returns></returns>
2730 public bool IncomingCreateObject(Vector3 newPosition, ISceneObject sog)
2731 {
2732 //m_log.DebugFormat(" >>> IncomingCreateObject(sog) <<< {0} deleted? {1} isAttach? {2}", ((SceneObjectGroup)sog).AbsolutePosition,
2733 // ((SceneObjectGroup)sog).IsDeleted, ((SceneObjectGroup)sog).RootPart.IsAttachment);
2734
2735 SceneObjectGroup newObject;
2736 try
2737 {
2738 newObject = (SceneObjectGroup)sog;
2739 }
2740 catch (Exception e)
2741 {
2742 m_log.WarnFormat("[INTERREGION]: Problem casting object, exception {0}{1}", e.Message, e.StackTrace);
2743 return false;
2744 }
2795 2745
2796 #region Add/Remove Avatar Methods 2746 if (!EntityTransferModule.HandleIncomingSceneObject(newObject, newPosition))
2747 return false;
2797 2748
2798 public override ISceneAgent AddNewAgent(IClientAPI client, PresenceType type) 2749 // Do this as late as possible so that listeners have full access to the incoming object
2799 { 2750 EventManager.TriggerOnIncomingSceneObject(newObject);
2800 ScenePresence sp; 2751
2801 bool vialogin; 2752 return true;
2802 bool reallyNew = true; 2753 }
2754
2755 /// <summary>
2756 /// Adds a Scene Object group to the Scene.
2757 /// Verifies that the creator of the object is not banned from the simulator.
2758 /// Checks if the item is an Attachment
2759 /// </summary>
2760 /// <param name="sceneObject"></param>
2761 /// <returns>True if the SceneObjectGroup was added, False if it was not</returns>
2762 public bool AddSceneObject(SceneObjectGroup sceneObject)
2763 {
2764 // Force allocation of new LocalId
2765 //
2766 SceneObjectPart[] parts = sceneObject.Parts;
2767 for (int i = 0; i < parts.Length; i++)
2768 parts[i].LocalId = 0;
2769
2770 if (sceneObject.IsAttachmentCheckFull()) // Attachment
2771 {
2772 sceneObject.RootPart.AddFlag(PrimFlags.TemporaryOnRez);
2773 sceneObject.RootPart.AddFlag(PrimFlags.Phantom);
2774
2775 // Don't sent a full update here because this will cause full updates to be sent twice for
2776 // attachments on region crossings, resulting in viewer glitches.
2777 AddRestoredSceneObject(sceneObject, false, false, false);
2778
2779 // Handle attachment special case
2780 SceneObjectPart RootPrim = sceneObject.RootPart;
2781
2782 // Fix up attachment Parent Local ID
2783 ScenePresence sp = GetScenePresence(sceneObject.OwnerID);
2803 2784
2804 // Update the number of users attempting to login 2785 if (sp != null)
2805 StatsReporter.UpdateUsersLoggingIn(true); 2786 {
2787 SceneObjectGroup grp = sceneObject;
2806 2788
2807 // Validation occurs in LLUDPServer 2789 // m_log.DebugFormat(
2808 // 2790 // "[ATTACHMENT]: Received attachment {0}, inworld asset id {1}", grp.FromItemID, grp.UUID);
2809 // XXX: A race condition exists here where two simultaneous calls to AddNewAgent can interfere with 2791 // m_log.DebugFormat(
2810 // each other. In practice, this does not currently occur in the code. 2792 // "[ATTACHMENT]: Attach to avatar {0} at position {1}", sp.UUID, grp.AbsolutePosition);
2811 AgentCircuitData aCircuit = m_authenticateHandler.GetAgentCircuitData(client.CircuitCode);
2812 2793
2813 // We lock here on AgentCircuitData to prevent a race condition between the thread adding a new connection 2794 RootPrim.RemFlag(PrimFlags.TemporaryOnRez);
2814 // and a simultaneous one that removes it (as can happen if the client is closed at a particular point
2815 // whilst connecting).
2816 //
2817 // It would be easier to lock across all NewUserConnection(), AddNewAgent() and
2818 // RemoveClient() calls for all agents, but this would allow a slow call (e.g. because of slow service
2819 // response in some module listening to AddNewAgent()) from holding up unrelated agent calls.
2820 //
2821 // In practice, the lock (this) in LLUDPServer.AddNewClient() currently lock across all
2822 // AddNewClient() operations (though not other ops).
2823 // In the future this can be relieved once locking per agent (not necessarily on AgentCircuitData) is improved.
2824 lock (aCircuit)
2825 {
2826 vialogin
2827 = (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0
2828 || (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaLogin) != 0;
2829
2830 // CheckHeartbeat();
2831
2832 sp = GetScenePresence(client.AgentId);
2833
2834 // XXX: Not sure how good it is to add a new client if a scene presence already exists. Possibly this
2835 // could occur if a viewer crashes and relogs before the old client is kicked out. But this could cause
2836 // other problems, and possibly the code calling AddNewAgent() should ensure that no client is already
2837 // connected.
2838 if (sp == null)
2839 {
2840 m_log.DebugFormat(
2841 "[SCENE]: Adding new child scene presence {0} {1} to scene {2} at pos {3}",
2842 client.Name, client.AgentId, RegionInfo.RegionName, client.StartPos);
2843
2844 sp = m_sceneGraph.CreateAndAddChildScenePresence(client, aCircuit.Appearance, type);
2845
2846 // We must set this here so that TriggerOnNewClient and TriggerOnClientLogin can determine whether the
2847 // client is for a root or child agent.
2848 // We must also set this before adding the client to the client manager so that an exception later on
2849 // does not leave a client manager entry without the scene agent set, which will cause other code
2850 // to fail since any entry in the client manager should have a ScenePresence
2851 //
2852 // XXX: This may be better set for a new client before that client is added to the client manager.
2853 // But need to know what happens in the case where a ScenePresence is already present (and if this
2854 // actually occurs).
2855 client.SceneAgent = sp;
2856
2857 m_clientManager.Add(client);
2858 SubscribeToClientEvents(client);
2859 m_eventManager.TriggerOnNewPresence(sp);
2860
2861 sp.TeleportFlags = (TPFlags)aCircuit.teleportFlags;
2862 }
2863 else
2864 {
2865 // We must set this here so that TriggerOnNewClient and TriggerOnClientLogin can determine whether the
2866 // client is for a root or child agent.
2867 // XXX: This may be better set for a new client before that client is added to the client manager.
2868 // But need to know what happens in the case where a ScenePresence is already present (and if this
2869 // actually occurs).
2870 client.SceneAgent = sp;
2871
2872 m_log.WarnFormat(
2873 "[SCENE]: Already found {0} scene presence for {1} in {2} when asked to add new scene presence",
2874 sp.IsChildAgent ? "child" : "root", sp.Name, RegionInfo.RegionName);
2875
2876 reallyNew = false;
2877 }
2878
2879 // This is currently also being done earlier in NewUserConnection for real users to see if this
2880 // resolves problems where HG agents are occasionally seen by others as "Unknown user" in chat and other
2881 // places. However, we still need to do it here for NPCs.
2882 CacheUserName(sp, aCircuit);
2883
2884 if (reallyNew)
2885 EventManager.TriggerOnNewClient(client);
2886
2887 if (vialogin)
2888 EventManager.TriggerOnClientLogin(client);
2889 }
2890
2891 // User has logged into the scene so update the list of users logging
2892 // in
2893 StatsReporter.UpdateUsersLoggingIn(false);
2894
2895 m_LastLogin = Util.EnvironmentTickCount();
2896
2897 return sp;
2898 }
2899
2900 /// <summary>
2901 /// Returns the Home URI of the agent, or null if unknown.
2902 /// </summary>
2903 public string GetAgentHomeURI(UUID agentID)
2904 {
2905 AgentCircuitData circuit = AuthenticateHandler.GetAgentCircuitData(agentID);
2906 if (circuit != null && circuit.ServiceURLs != null && circuit.ServiceURLs.ContainsKey("HomeURI"))
2907 return circuit.ServiceURLs["HomeURI"].ToString();
2908 else
2909 return null;
2910 }
2911
2912 /// <summary>
2913 /// Cache the user name for later use.
2914 /// </summary>
2915 /// <param name="sp"></param>
2916 /// <param name="aCircuit"></param>
2917 private void CacheUserName(ScenePresence sp, AgentCircuitData aCircuit)
2918 {
2919 if (UserManagementModule != null)
2920 {
2921 string first = aCircuit.firstname, last = aCircuit.lastname;
2922
2923 if (sp != null && sp.PresenceType == PresenceType.Npc)
2924 {
2925 UserManagementModule.AddUser(aCircuit.AgentID, first, last);
2926 }
2927 else
2928 {
2929 string homeURL = string.Empty;
2930
2931 if (aCircuit.ServiceURLs.ContainsKey("HomeURI"))
2932 homeURL = aCircuit.ServiceURLs["HomeURI"].ToString();
2933
2934 if (aCircuit.lastname.StartsWith("@"))
2935 {
2936 string[] parts = aCircuit.firstname.Split('.');
2937 if (parts.Length >= 2)
2938 {
2939 first = parts[0];
2940 last = parts[1];
2941 }
2942 }
2943
2944 UserManagementModule.AddUser(aCircuit.AgentID, first, last, homeURL);
2945 }
2946 }
2947 }
2948
2949 private bool VerifyClient(AgentCircuitData aCircuit, System.Net.IPEndPoint ep, out bool vialogin)
2950 {
2951 vialogin = false;
2952
2953 // Do the verification here
2954 if ((aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0)
2955 {
2956 m_log.DebugFormat("[SCENE]: Incoming client {0} {1} in region {2} via HG login", aCircuit.firstname, aCircuit.lastname, RegionInfo.RegionName);
2957 vialogin = true;
2958 IUserAgentVerificationModule userVerification = RequestModuleInterface<IUserAgentVerificationModule>();
2959 if (userVerification != null && ep != null)
2960 {
2961 if (!userVerification.VerifyClient(aCircuit, ep.Address.ToString()))
2962 {
2963 // uh-oh, this is fishy
2964 m_log.DebugFormat("[SCENE]: User Client Verification for {0} {1} in {2} returned false", aCircuit.firstname, aCircuit.lastname, RegionInfo.RegionName);
2965 return false;
2966 }
2967 else
2968 m_log.DebugFormat("[SCENE]: User Client Verification for {0} {1} in {2} returned true", aCircuit.firstname, aCircuit.lastname, RegionInfo.RegionName);
2969 2795
2970 } 2796 // We must currently not resume scripts at this stage since AttachmentsModule does not have the
2797 // information that this is due to a teleport/border cross rather than an ordinary attachment.
2798 // We currently do this in Scene.MakeRootAgent() instead.
2799 if (AttachmentsModule != null)
2800 AttachmentsModule.AttachObject(sp, grp, 0, false, false, true);
2971 } 2801 }
2972 2802 else
2973 else if ((aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaLogin) != 0) 2803 {
2804 RootPrim.RemFlag(PrimFlags.TemporaryOnRez);
2805 RootPrim.AddFlag(PrimFlags.TemporaryOnRez);
2806 }
2807 }
2808 else
2809 {
2810 AddRestoredSceneObject(sceneObject, true, false);
2811 }
2812
2813 return true;
2814 }
2815
2816 #endregion
2817
2818 #region Add/Remove Avatar Methods
2819
2820 public override ISceneAgent AddNewAgent(IClientAPI client, PresenceType type)
2821 {
2822 ScenePresence sp;
2823 bool vialogin;
2824 bool reallyNew = true;
2825
2826 // Update the number of users attempting to login
2827 StatsReporter.UpdateUsersLoggingIn(true);
2828
2829 // Validation occurs in LLUDPServer
2830 //
2831 // XXX: A race condition exists here where two simultaneous calls to AddNewAgent can interfere with
2832 // each other. In practice, this does not currently occur in the code.
2833 AgentCircuitData aCircuit = m_authenticateHandler.GetAgentCircuitData(client.CircuitCode);
2834
2835 // We lock here on AgentCircuitData to prevent a race condition between the thread adding a new connection
2836 // and a simultaneous one that removes it (as can happen if the client is closed at a particular point
2837 // whilst connecting).
2838 //
2839 // It would be easier to lock across all NewUserConnection(), AddNewAgent() and
2840 // RemoveClient() calls for all agents, but this would allow a slow call (e.g. because of slow service
2841 // response in some module listening to AddNewAgent()) from holding up unrelated agent calls.
2842 //
2843 // In practice, the lock (this) in LLUDPServer.AddNewClient() currently lock across all
2844 // AddNewClient() operations (though not other ops).
2845 // In the future this can be relieved once locking per agent (not necessarily on AgentCircuitData) is improved.
2846 lock (aCircuit)
2847 {
2848 vialogin
2849 = (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0
2850 || (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaLogin) != 0;
2851
2852 // CheckHeartbeat();
2853
2854 sp = GetScenePresence(client.AgentId);
2855
2856 // XXX: Not sure how good it is to add a new client if a scene presence already exists. Possibly this
2857 // could occur if a viewer crashes and relogs before the old client is kicked out. But this could cause
2858 // other problems, and possibly the code calling AddNewAgent() should ensure that no client is already
2859 // connected.
2860 if (sp == null)
2974 { 2861 {
2975 m_log.DebugFormat("[SCENE]: Incoming client {0} {1} in region {2} via regular login. Client IP verification not performed.", 2862 m_log.DebugFormat(
2976 aCircuit.firstname, aCircuit.lastname, RegionInfo.RegionName); 2863 "[SCENE]: Adding new child scene presence {0} {1} to scene {2} at pos {3}",
2977 vialogin = true; 2864 client.Name, client.AgentId, RegionInfo.RegionName, client.StartPos);
2865
2866 sp = m_sceneGraph.CreateAndAddChildScenePresence(client, aCircuit.Appearance, type);
2867
2868 // We must set this here so that TriggerOnNewClient and TriggerOnClientLogin can determine whether the
2869 // client is for a root or child agent.
2870 // We must also set this before adding the client to the client manager so that an exception later on
2871 // does not leave a client manager entry without the scene agent set, which will cause other code
2872 // to fail since any entry in the client manager should have a ScenePresence
2873 //
2874 // XXX: This may be better set for a new client before that client is added to the client manager.
2875 // But need to know what happens in the case where a ScenePresence is already present (and if this
2876 // actually occurs).
2877 client.SceneAgent = sp;
2878
2879 m_clientManager.Add(client);
2880 SubscribeToClientEvents(client);
2881 m_eventManager.TriggerOnNewPresence(sp);
2882
2883 sp.TeleportFlags = (TPFlags)aCircuit.teleportFlags;
2978 } 2884 }
2885 else
2886 {
2887 // We must set this here so that TriggerOnNewClient and TriggerOnClientLogin can determine whether the
2888 // client is for a root or child agent.
2889 // XXX: This may be better set for a new client before that client is added to the client manager.
2890 // But need to know what happens in the case where a ScenePresence is already present (and if this
2891 // actually occurs).
2892 client.SceneAgent = sp;
2979 2893
2980 return true; 2894 m_log.WarnFormat(
2981 } 2895 "[SCENE]: Already found {0} scene presence for {1} in {2} when asked to add new scene presence",
2982 2896 sp.IsChildAgent ? "child" : "root", sp.Name, RegionInfo.RegionName);
2983 // Called by Caps, on the first HTTP contact from the client
2984 public override bool CheckClient(UUID agentID, System.Net.IPEndPoint ep)
2985 {
2986 AgentCircuitData aCircuit = m_authenticateHandler.GetAgentCircuitData(agentID);
2987 if (aCircuit != null)
2988 {
2989 bool vialogin = false;
2990 if (!VerifyClient(aCircuit, ep, out vialogin))
2991 {
2992 // if it doesn't pass, we remove the agentcircuitdata altogether
2993 // and the scene presence and the client, if they exist
2994 try
2995 {
2996 // We need to wait for the client to make UDP contact first.
2997 // It's the UDP contact that creates the scene presence
2998 ScenePresence sp = WaitGetScenePresence(agentID);
2999 if (sp != null)
3000 {
3001 PresenceService.LogoutAgent(sp.ControllingClient.SessionId);
3002
3003 CloseAgent(sp.UUID, false);
3004 }
3005 else
3006 {
3007 m_log.WarnFormat("[SCENE]: Could not find scene presence for {0}", agentID);
3008 }
3009 // BANG! SLASH!
3010 m_authenticateHandler.RemoveCircuit(agentID);
3011 2897
3012 return false; 2898 reallyNew = false;
3013 }
3014 catch (Exception e)
3015 {
3016 m_log.DebugFormat("[SCENE]: Exception while closing aborted client: {0}", e.StackTrace);
3017 }
3018 }
3019 else
3020 return true;
3021 } 2899 }
3022 2900
3023 return false; 2901 // This is currently also being done earlier in NewUserConnection for real users to see if this
3024 } 2902 // resolves problems where HG agents are occasionally seen by others as "Unknown user" in chat and other
3025 2903 // places. However, we still need to do it here for NPCs.
3026 /// <summary> 2904 CacheUserName(sp, aCircuit);
3027 /// Register for events from the client 2905
3028 /// </summary> 2906 if (reallyNew)
3029 /// <param name="client">The IClientAPI of the connected client</param> 2907 EventManager.TriggerOnNewClient(client);
3030 public virtual void SubscribeToClientEvents(IClientAPI client) 2908
3031 { 2909 if (vialogin)
3032 SubscribeToClientTerrainEvents(client); 2910 EventManager.TriggerOnClientLogin(client);
3033 SubscribeToClientPrimEvents(client); 2911 }
3034 SubscribeToClientPrimRezEvents(client); 2912
3035 SubscribeToClientInventoryEvents(client); 2913 // User has logged into the scene so update the list of users logging
3036 SubscribeToClientTeleportEvents(client); 2914 // in
3037 SubscribeToClientScriptEvents(client); 2915 StatsReporter.UpdateUsersLoggingIn(false);
3038 SubscribeToClientParcelEvents(client); 2916
3039 SubscribeToClientGridEvents(client); 2917 m_LastLogin = Util.EnvironmentTickCount();
3040 SubscribeToClientNetworkEvents(client); 2918
3041 } 2919 return sp;
3042 2920 }
3043 public virtual void SubscribeToClientTerrainEvents(IClientAPI client) 2921
3044 { 2922 /// <summary>
3045 client.OnRegionHandShakeReply += SendLayerData; 2923 /// Returns the Home URI of the agent, or null if unknown.
3046 } 2924 /// </summary>
3047 2925 public string GetAgentHomeURI(UUID agentID)
3048 public virtual void SubscribeToClientPrimEvents(IClientAPI client) 2926 {
3049 { 2927 AgentCircuitData circuit = AuthenticateHandler.GetAgentCircuitData(agentID);
3050 client.OnUpdatePrimGroupPosition += m_sceneGraph.UpdatePrimGroupPosition; 2928 if (circuit != null && circuit.ServiceURLs != null && circuit.ServiceURLs.ContainsKey("HomeURI"))
3051 client.OnUpdatePrimSinglePosition += m_sceneGraph.UpdatePrimSinglePosition; 2929 return circuit.ServiceURLs["HomeURI"].ToString();
3052 2930 else
3053 client.OnUpdatePrimGroupRotation += m_sceneGraph.UpdatePrimGroupRotation; 2931 return null;
3054 client.OnUpdatePrimGroupMouseRotation += m_sceneGraph.UpdatePrimGroupRotation; 2932 }
3055 client.OnUpdatePrimSingleRotation += m_sceneGraph.UpdatePrimSingleRotation; 2933
3056 client.OnUpdatePrimSingleRotationPosition += m_sceneGraph.UpdatePrimSingleRotationPosition; 2934 /// <summary>
3057 2935 /// Cache the user name for later use.
3058 client.OnUpdatePrimScale += m_sceneGraph.UpdatePrimScale; 2936 /// </summary>
3059 client.OnUpdatePrimGroupScale += m_sceneGraph.UpdatePrimGroupScale; 2937 /// <param name="sp"></param>
3060 client.OnUpdateExtraParams += m_sceneGraph.UpdateExtraParam; 2938 /// <param name="aCircuit"></param>
3061 client.OnUpdatePrimShape += m_sceneGraph.UpdatePrimShape; 2939 private void CacheUserName(ScenePresence sp, AgentCircuitData aCircuit)
3062 client.OnUpdatePrimTexture += m_sceneGraph.UpdatePrimTexture; 2940 {
3063 client.OnObjectRequest += RequestPrim; 2941 if (UserManagementModule != null)
3064 client.OnObjectSelect += SelectPrim; 2942 {
3065 client.OnObjectDeselect += DeselectPrim; 2943 string first = aCircuit.firstname, last = aCircuit.lastname;
3066 client.OnGrabUpdate += m_sceneGraph.MoveObject; 2944
3067 client.OnSpinStart += m_sceneGraph.SpinStart; 2945 if (sp != null && sp.PresenceType == PresenceType.Npc)
3068 client.OnSpinUpdate += m_sceneGraph.SpinObject;
3069 client.OnDeRezObject += DeRezObjects;
3070
3071 client.OnObjectName += m_sceneGraph.PrimName;
3072 client.OnObjectClickAction += m_sceneGraph.PrimClickAction;
3073 client.OnObjectMaterial += m_sceneGraph.PrimMaterial;
3074 client.OnLinkObjects += LinkObjects;
3075 client.OnDelinkObjects += DelinkObjects;
3076 client.OnObjectDuplicate += DuplicateObject;
3077 client.OnObjectDuplicateOnRay += doObjectDuplicateOnRay;
3078 client.OnUpdatePrimFlags += m_sceneGraph.UpdatePrimFlags;
3079 client.OnRequestObjectPropertiesFamily += m_sceneGraph.RequestObjectPropertiesFamily;
3080 client.OnObjectPermissions += HandleObjectPermissionsUpdate;
3081 client.OnGrabObject += ProcessObjectGrab;
3082 client.OnGrabUpdate += ProcessObjectGrabUpdate;
3083 client.OnDeGrabObject += ProcessObjectDeGrab;
3084 client.OnUndo += m_sceneGraph.HandleUndo;
3085 client.OnRedo += m_sceneGraph.HandleRedo;
3086 client.OnObjectDescription += m_sceneGraph.PrimDescription;
3087 client.OnObjectIncludeInSearch += m_sceneGraph.MakeObjectSearchable;
3088 client.OnObjectOwner += ObjectOwner;
3089 client.OnObjectGroupRequest += HandleObjectGroupUpdate;
3090 }
3091
3092 public virtual void SubscribeToClientPrimRezEvents(IClientAPI client)
3093 {
3094 client.OnAddPrim += AddNewPrim;
3095 client.OnRezObject += RezObject;
3096 }
3097
3098 public virtual void SubscribeToClientInventoryEvents(IClientAPI client)
3099 {
3100 client.OnLinkInventoryItem += HandleLinkInventoryItem;
3101 client.OnCreateNewInventoryFolder += HandleCreateInventoryFolder;
3102 client.OnUpdateInventoryFolder += HandleUpdateInventoryFolder;
3103 client.OnMoveInventoryFolder += HandleMoveInventoryFolder; // 2; //!!
3104 client.OnFetchInventoryDescendents += HandleFetchInventoryDescendents;
3105 client.OnPurgeInventoryDescendents += HandlePurgeInventoryDescendents; // 2; //!!
3106 client.OnFetchInventory += m_asyncInventorySender.HandleFetchInventory;
3107 client.OnUpdateInventoryItem += UpdateInventoryItemAsset;
3108 client.OnCopyInventoryItem += CopyInventoryItem;
3109 client.OnMoveInventoryItem += MoveInventoryItem;
3110 client.OnRemoveInventoryItem += RemoveInventoryItem;
3111 client.OnRemoveInventoryFolder += RemoveInventoryFolder;
3112 client.OnRezScript += RezScript;
3113 client.OnRequestTaskInventory += RequestTaskInventory;
3114 client.OnRemoveTaskItem += RemoveTaskInventory;
3115 client.OnUpdateTaskInventory += UpdateTaskInventory;
3116 client.OnMoveTaskItem += ClientMoveTaskInventoryItem;
3117 }
3118
3119 public virtual void SubscribeToClientTeleportEvents(IClientAPI client)
3120 {
3121 client.OnTeleportLocationRequest += RequestTeleportLocation;
3122 }
3123
3124 public virtual void SubscribeToClientScriptEvents(IClientAPI client)
3125 {
3126 client.OnScriptReset += ProcessScriptReset;
3127 client.OnGetScriptRunning += GetScriptRunning;
3128 client.OnSetScriptRunning += SetScriptRunning;
3129 }
3130
3131 public virtual void SubscribeToClientParcelEvents(IClientAPI client)
3132 {
3133 client.OnParcelReturnObjectsRequest += LandChannel.ReturnObjectsInParcel;
3134 client.OnParcelSetOtherCleanTime += LandChannel.SetParcelOtherCleanTime;
3135 client.OnParcelBuy += ProcessParcelBuy;
3136 }
3137
3138 public virtual void SubscribeToClientGridEvents(IClientAPI client)
3139 {
3140 //client.OnNameFromUUIDRequest += HandleUUIDNameRequest;
3141 client.OnMoneyTransferRequest += ProcessMoneyTransferRequest;
3142 }
3143
3144 public virtual void SubscribeToClientNetworkEvents(IClientAPI client)
3145 {
3146 client.OnNetworkStatsUpdate += StatsReporter.AddPacketsStats;
3147 client.OnViewerEffect += ProcessViewerEffect;
3148 }
3149
3150 /// <summary>
3151 /// Unsubscribe the client from events.
3152 /// </summary>
3153 /// FIXME: Not called anywhere!
3154 /// <param name="client">The IClientAPI of the client</param>
3155 public virtual void UnSubscribeToClientEvents(IClientAPI client)
3156 {
3157 UnSubscribeToClientTerrainEvents(client);
3158 UnSubscribeToClientPrimEvents(client);
3159 UnSubscribeToClientPrimRezEvents(client);
3160 UnSubscribeToClientInventoryEvents(client);
3161 UnSubscribeToClientTeleportEvents(client);
3162 UnSubscribeToClientScriptEvents(client);
3163 UnSubscribeToClientParcelEvents(client);
3164 UnSubscribeToClientGridEvents(client);
3165 UnSubscribeToClientNetworkEvents(client);
3166 }
3167
3168 public virtual void UnSubscribeToClientTerrainEvents(IClientAPI client)
3169 {
3170 client.OnRegionHandShakeReply -= SendLayerData;
3171 }
3172
3173 public virtual void UnSubscribeToClientPrimEvents(IClientAPI client)
3174 {
3175 client.OnUpdatePrimGroupPosition -= m_sceneGraph.UpdatePrimGroupPosition;
3176 client.OnUpdatePrimSinglePosition -= m_sceneGraph.UpdatePrimSinglePosition;
3177
3178 client.OnUpdatePrimGroupRotation -= m_sceneGraph.UpdatePrimGroupRotation;
3179 client.OnUpdatePrimGroupMouseRotation -= m_sceneGraph.UpdatePrimGroupRotation;
3180 client.OnUpdatePrimSingleRotation -= m_sceneGraph.UpdatePrimSingleRotation;
3181 client.OnUpdatePrimSingleRotationPosition -= m_sceneGraph.UpdatePrimSingleRotationPosition;
3182
3183 client.OnUpdatePrimScale -= m_sceneGraph.UpdatePrimScale;
3184 client.OnUpdatePrimGroupScale -= m_sceneGraph.UpdatePrimGroupScale;
3185 client.OnUpdateExtraParams -= m_sceneGraph.UpdateExtraParam;
3186 client.OnUpdatePrimShape -= m_sceneGraph.UpdatePrimShape;
3187 client.OnUpdatePrimTexture -= m_sceneGraph.UpdatePrimTexture;
3188 client.OnObjectRequest -= RequestPrim;
3189 client.OnObjectSelect -= SelectPrim;
3190 client.OnObjectDeselect -= DeselectPrim;
3191 client.OnGrabUpdate -= m_sceneGraph.MoveObject;
3192 client.OnSpinStart -= m_sceneGraph.SpinStart;
3193 client.OnSpinUpdate -= m_sceneGraph.SpinObject;
3194 client.OnDeRezObject -= DeRezObjects;
3195 client.OnObjectName -= m_sceneGraph.PrimName;
3196 client.OnObjectClickAction -= m_sceneGraph.PrimClickAction;
3197 client.OnObjectMaterial -= m_sceneGraph.PrimMaterial;
3198 client.OnLinkObjects -= LinkObjects;
3199 client.OnDelinkObjects -= DelinkObjects;
3200 client.OnObjectDuplicate -= DuplicateObject;
3201 client.OnObjectDuplicateOnRay -= doObjectDuplicateOnRay;
3202 client.OnUpdatePrimFlags -= m_sceneGraph.UpdatePrimFlags;
3203 client.OnRequestObjectPropertiesFamily -= m_sceneGraph.RequestObjectPropertiesFamily;
3204 client.OnObjectPermissions -= HandleObjectPermissionsUpdate;
3205 client.OnGrabObject -= ProcessObjectGrab;
3206 client.OnDeGrabObject -= ProcessObjectDeGrab;
3207 client.OnUndo -= m_sceneGraph.HandleUndo;
3208 client.OnRedo -= m_sceneGraph.HandleRedo;
3209 client.OnObjectDescription -= m_sceneGraph.PrimDescription;
3210 client.OnObjectIncludeInSearch -= m_sceneGraph.MakeObjectSearchable;
3211 client.OnObjectOwner -= ObjectOwner;
3212 }
3213
3214 public virtual void UnSubscribeToClientPrimRezEvents(IClientAPI client)
3215 {
3216 client.OnAddPrim -= AddNewPrim;
3217 client.OnRezObject -= RezObject;
3218 }
3219
3220 public virtual void UnSubscribeToClientInventoryEvents(IClientAPI client)
3221 {
3222 client.OnCreateNewInventoryFolder -= HandleCreateInventoryFolder;
3223 client.OnUpdateInventoryFolder -= HandleUpdateInventoryFolder;
3224 client.OnMoveInventoryFolder -= HandleMoveInventoryFolder; // 2; //!!
3225 client.OnFetchInventoryDescendents -= HandleFetchInventoryDescendents;
3226 client.OnPurgeInventoryDescendents -= HandlePurgeInventoryDescendents; // 2; //!!
3227 client.OnFetchInventory -= m_asyncInventorySender.HandleFetchInventory;
3228 client.OnUpdateInventoryItem -= UpdateInventoryItemAsset;
3229 client.OnCopyInventoryItem -= CopyInventoryItem;
3230 client.OnMoveInventoryItem -= MoveInventoryItem;
3231 client.OnRemoveInventoryItem -= RemoveInventoryItem;
3232 client.OnRemoveInventoryFolder -= RemoveInventoryFolder;
3233 client.OnRezScript -= RezScript;
3234 client.OnRequestTaskInventory -= RequestTaskInventory;
3235 client.OnRemoveTaskItem -= RemoveTaskInventory;
3236 client.OnUpdateTaskInventory -= UpdateTaskInventory;
3237 client.OnMoveTaskItem -= ClientMoveTaskInventoryItem;
3238 }
3239
3240 public virtual void UnSubscribeToClientTeleportEvents(IClientAPI client)
3241 {
3242 client.OnTeleportLocationRequest -= RequestTeleportLocation;
3243 //client.OnTeleportLandmarkRequest -= RequestTeleportLandmark;
3244 //client.OnTeleportHomeRequest -= TeleportClientHome;
3245 }
3246
3247 public virtual void UnSubscribeToClientScriptEvents(IClientAPI client)
3248 {
3249 client.OnScriptReset -= ProcessScriptReset;
3250 client.OnGetScriptRunning -= GetScriptRunning;
3251 client.OnSetScriptRunning -= SetScriptRunning;
3252 }
3253
3254 public virtual void UnSubscribeToClientParcelEvents(IClientAPI client)
3255 {
3256 client.OnParcelReturnObjectsRequest -= LandChannel.ReturnObjectsInParcel;
3257 client.OnParcelSetOtherCleanTime -= LandChannel.SetParcelOtherCleanTime;
3258 client.OnParcelBuy -= ProcessParcelBuy;
3259 }
3260
3261 public virtual void UnSubscribeToClientGridEvents(IClientAPI client)
3262 {
3263 //client.OnNameFromUUIDRequest -= HandleUUIDNameRequest;
3264 client.OnMoneyTransferRequest -= ProcessMoneyTransferRequest;
3265 }
3266
3267 public virtual void UnSubscribeToClientNetworkEvents(IClientAPI client)
3268 {
3269 client.OnNetworkStatsUpdate -= StatsReporter.AddPacketsStats;
3270 client.OnViewerEffect -= ProcessViewerEffect;
3271 }
3272
3273 /// <summary>
3274 /// Teleport an avatar to their home region
3275 /// </summary>
3276 /// <param name="agentId">The avatar's Unique ID</param>
3277 /// <param name="client">The IClientAPI for the client</param>
3278 public virtual bool TeleportClientHome(UUID agentId, IClientAPI client)
3279 {
3280 if (EntityTransferModule != null)
3281 { 2946 {
3282 return EntityTransferModule.TeleportHome(agentId, client); 2947 UserManagementModule.AddUser(aCircuit.AgentID, first, last);
3283 } 2948 }
3284 else 2949 else
3285 { 2950 {
3286 m_log.DebugFormat("[SCENE]: Unable to teleport user home: no AgentTransferModule is active"); 2951 string homeURL = string.Empty;
3287 client.SendTeleportFailed("Unable to perform teleports on this simulator."); 2952
2953 if (aCircuit.ServiceURLs.ContainsKey("HomeURI"))
2954 homeURL = aCircuit.ServiceURLs["HomeURI"].ToString();
2955
2956 if (aCircuit.lastname.StartsWith("@"))
2957 {
2958 string[] parts = aCircuit.firstname.Split('.');
2959 if (parts.Length >= 2)
2960 {
2961 first = parts[0];
2962 last = parts[1];
2963 }
2964 }
2965
2966 UserManagementModule.AddUser(aCircuit.AgentID, first, last, homeURL);
2967 }
2968 }
2969 }
2970
2971 private bool VerifyClient(AgentCircuitData aCircuit, System.Net.IPEndPoint ep, out bool vialogin)
2972 {
2973 vialogin = false;
2974
2975 // Do the verification here
2976 if ((aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0)
2977 {
2978 m_log.DebugFormat("[SCENE]: Incoming client {0} {1} in region {2} via HG login", aCircuit.firstname, aCircuit.lastname, RegionInfo.RegionName);
2979 vialogin = true;
2980 IUserAgentVerificationModule userVerification = RequestModuleInterface<IUserAgentVerificationModule>();
2981 if (userVerification != null && ep != null)
2982 {
2983 if (!userVerification.VerifyClient(aCircuit, ep.Address.ToString()))
2984 {
2985 // uh-oh, this is fishy
2986 m_log.DebugFormat("[SCENE]: User Client Verification for {0} {1} in {2} returned false", aCircuit.firstname, aCircuit.lastname, RegionInfo.RegionName);
2987 return false;
2988 }
2989 else
2990 m_log.DebugFormat("[SCENE]: User Client Verification for {0} {1} in {2} returned true", aCircuit.firstname, aCircuit.lastname, RegionInfo.RegionName);
2991
2992 }
2993 }
2994
2995 else if ((aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaLogin) != 0)
2996 {
2997 m_log.DebugFormat("[SCENE]: Incoming client {0} {1} in region {2} via regular login. Client IP verification not performed.",
2998 aCircuit.firstname, aCircuit.lastname, RegionInfo.RegionName);
2999 vialogin = true;
3000 }
3001
3002 return true;
3003 }
3004
3005 // Called by Caps, on the first HTTP contact from the client
3006 public override bool CheckClient(UUID agentID, System.Net.IPEndPoint ep)
3007 {
3008 AgentCircuitData aCircuit = m_authenticateHandler.GetAgentCircuitData(agentID);
3009 if (aCircuit != null)
3010 {
3011 bool vialogin = false;
3012 if (!VerifyClient(aCircuit, ep, out vialogin))
3013 {
3014 // if it doesn't pass, we remove the agentcircuitdata altogether
3015 // and the scene presence and the client, if they exist
3016 try
3017 {
3018 // We need to wait for the client to make UDP contact first.
3019 // It's the UDP contact that creates the scene presence
3020 ScenePresence sp = WaitGetScenePresence(agentID);
3021 if (sp != null)
3022 {
3023 PresenceService.LogoutAgent(sp.ControllingClient.SessionId);
3024
3025 CloseAgent(sp.UUID, false);
3026 }
3027 else
3028 {
3029 m_log.WarnFormat("[SCENE]: Could not find scene presence for {0}", agentID);
3030 }
3031 // BANG! SLASH!
3032 m_authenticateHandler.RemoveCircuit(agentID);
3033
3034 return false;
3035 }
3036 catch (Exception e)
3037 {
3038 m_log.DebugFormat("[SCENE]: Exception while closing aborted client: {0}", e.StackTrace);
3039 }
3288 } 3040 }
3289 return false; 3041 else
3290 } 3042 return true;
3291 3043 }
3292 /// <summary> 3044
3293 /// Duplicates object specified by localID. This is the event handler for IClientAPI. 3045 return false;
3294 /// </summary> 3046 }
3295 /// <param name="originalPrim">ID of object to duplicate</param> 3047
3296 /// <param name="offset"></param> 3048 /// <summary>
3297 /// <param name="flags"></param> 3049 /// Register for events from the client
3298 /// <param name="AgentID">Agent doing the duplication</param> 3050 /// </summary>
3299 /// <param name="GroupID">Group of new object</param> 3051 /// <param name="client">The IClientAPI of the connected client</param>
3300 public void DuplicateObject(uint originalPrim, Vector3 offset, uint flags, UUID AgentID, UUID GroupID) 3052 public virtual void SubscribeToClientEvents(IClientAPI client)
3301 { 3053 {
3302 SceneObjectGroup copy = SceneGraph.DuplicateObject(originalPrim, offset, flags, AgentID, GroupID, Quaternion.Identity); 3054 SubscribeToClientTerrainEvents(client);
3303 if (copy != null) 3055 SubscribeToClientPrimEvents(client);
3304 EventManager.TriggerObjectAddedToScene(copy); 3056 SubscribeToClientPrimRezEvents(client);
3305 } 3057 SubscribeToClientInventoryEvents(client);
3306 3058 SubscribeToClientTeleportEvents(client);
3307 /// <summary> 3059 SubscribeToClientScriptEvents(client);
3308 /// Duplicates object specified by localID at position raycasted against RayTargetObject using 3060 SubscribeToClientParcelEvents(client);
3309 /// RayEnd and RayStart to determine what the angle of the ray is 3061 SubscribeToClientGridEvents(client);
3310 /// </summary> 3062 SubscribeToClientNetworkEvents(client);
3311 /// <param name="localID">ID of object to duplicate</param> 3063 }
3312 /// <param name="dupeFlags"></param> 3064
3313 /// <param name="AgentID">Agent doing the duplication</param> 3065 public virtual void SubscribeToClientTerrainEvents(IClientAPI client)
3314 /// <param name="GroupID">Group of new object</param> 3066 {
3315 /// <param name="RayTargetObj">The target of the Ray</param> 3067 client.OnRegionHandShakeReply += SendLayerData;
3316 /// <param name="RayEnd">The ending of the ray (farthest away point)</param> 3068 }
3317 /// <param name="RayStart">The Beginning of the ray (closest point)</param> 3069
3318 /// <param name="BypassRaycast">Bool to bypass raycasting</param> 3070 public virtual void SubscribeToClientPrimEvents(IClientAPI client)
3319 /// <param name="RayEndIsIntersection">The End specified is the place to add the object</param> 3071 {
3320 /// <param name="CopyCenters">Position the object at the center of the face that it's colliding with</param> 3072 client.OnUpdatePrimGroupPosition += m_sceneGraph.UpdatePrimGroupPosition;
3321 /// <param name="CopyRotates">Rotate the object the same as the localID object</param> 3073 client.OnUpdatePrimSinglePosition += m_sceneGraph.UpdatePrimSinglePosition;
3322 public void doObjectDuplicateOnRay(uint localID, uint dupeFlags, UUID AgentID, UUID GroupID, 3074
3323 UUID RayTargetObj, Vector3 RayEnd, Vector3 RayStart, 3075 client.OnUpdatePrimGroupRotation += m_sceneGraph.UpdatePrimGroupRotation;
3324 bool BypassRaycast, bool RayEndIsIntersection, bool CopyCenters, bool CopyRotates) 3076 client.OnUpdatePrimGroupMouseRotation += m_sceneGraph.UpdatePrimGroupRotation;
3325 { 3077 client.OnUpdatePrimSingleRotation += m_sceneGraph.UpdatePrimSingleRotation;
3326 Vector3 pos; 3078 client.OnUpdatePrimSingleRotationPosition += m_sceneGraph.UpdatePrimSingleRotationPosition;
3327 const bool frontFacesOnly = true; 3079
3328 //m_log.Info("HITTARGET: " + RayTargetObj.ToString() + ", COPYTARGET: " + localID.ToString()); 3080 client.OnUpdatePrimScale += m_sceneGraph.UpdatePrimScale;
3329 SceneObjectPart target = GetSceneObjectPart(localID); 3081 client.OnUpdatePrimGroupScale += m_sceneGraph.UpdatePrimGroupScale;
3330 SceneObjectPart target2 = GetSceneObjectPart(RayTargetObj); 3082 client.OnUpdateExtraParams += m_sceneGraph.UpdateExtraParam;
3331 3083 client.OnUpdatePrimShape += m_sceneGraph.UpdatePrimShape;
3332 if (target != null && target2 != null) 3084 client.OnUpdatePrimTexture += m_sceneGraph.UpdatePrimTexture;
3333 { 3085 client.OnObjectRequest += RequestPrim;
3334 Vector3 direction = Vector3.Normalize(RayEnd - RayStart); 3086 client.OnObjectSelect += SelectPrim;
3335 Vector3 AXOrigin = RayStart; 3087 client.OnObjectDeselect += DeselectPrim;
3336 Vector3 AXdirection = direction; 3088 client.OnGrabUpdate += m_sceneGraph.MoveObject;
3337 3089 client.OnSpinStart += m_sceneGraph.SpinStart;
3338 pos = target2.AbsolutePosition; 3090 client.OnSpinUpdate += m_sceneGraph.SpinObject;
3339 //m_log.Info("[OBJECT_REZ]: TargetPos: " + pos.ToString() + ", RayStart: " + RayStart.ToString() + ", RayEnd: " + RayEnd.ToString() + ", Volume: " + Util.GetDistanceTo(RayStart,RayEnd).ToString() + ", mag1: " + Util.GetMagnitude(RayStart).ToString() + ", mag2: " + Util.GetMagnitude(RayEnd).ToString()); 3091 client.OnDeRezObject += DeRezObjects;
3340 3092
3341 // TODO: Raytrace better here 3093 client.OnObjectName += m_sceneGraph.PrimName;
3342 3094 client.OnObjectClickAction += m_sceneGraph.PrimClickAction;
3343 //EntityIntersection ei = m_sceneGraph.GetClosestIntersectingPrim(new Ray(AXOrigin, AXdirection)); 3095 client.OnObjectMaterial += m_sceneGraph.PrimMaterial;
3344 Ray NewRay = new Ray(AXOrigin, AXdirection); 3096 client.OnLinkObjects += LinkObjects;
3345 3097 client.OnDelinkObjects += DelinkObjects;
3346 // Ray Trace against target here 3098 client.OnObjectDuplicate += DuplicateObject;
3347 EntityIntersection ei = target2.TestIntersectionOBB(NewRay, Quaternion.Identity, frontFacesOnly, CopyCenters); 3099 client.OnObjectDuplicateOnRay += doObjectDuplicateOnRay;
3348 3100 client.OnUpdatePrimFlags += m_sceneGraph.UpdatePrimFlags;
3349 // Un-comment out the following line to Get Raytrace results printed to the console. 3101 client.OnRequestObjectPropertiesFamily += m_sceneGraph.RequestObjectPropertiesFamily;
3350 //m_log.Info("[RAYTRACERESULTS]: Hit:" + ei.HitTF.ToString() + " Point: " + ei.ipoint.ToString() + " Normal: " + ei.normal.ToString()); 3102 client.OnObjectPermissions += HandleObjectPermissionsUpdate;
3351 float ScaleOffset = 0.5f; 3103 client.OnGrabObject += ProcessObjectGrab;
3352 3104 client.OnGrabUpdate += ProcessObjectGrabUpdate;
3353 // If we hit something 3105 client.OnDeGrabObject += ProcessObjectDeGrab;
3354 if (ei.HitTF) 3106 client.OnUndo += m_sceneGraph.HandleUndo;
3355 { 3107 client.OnRedo += m_sceneGraph.HandleRedo;
3356 Vector3 scale = target.Scale; 3108 client.OnObjectDescription += m_sceneGraph.PrimDescription;
3357 Vector3 scaleComponent = ei.AAfaceNormal; 3109 client.OnObjectIncludeInSearch += m_sceneGraph.MakeObjectSearchable;
3358 if (scaleComponent.X != 0) ScaleOffset = scale.X; 3110 client.OnObjectOwner += ObjectOwner;
3359 if (scaleComponent.Y != 0) ScaleOffset = scale.Y; 3111 client.OnObjectGroupRequest += HandleObjectGroupUpdate;
3360 if (scaleComponent.Z != 0) ScaleOffset = scale.Z; 3112 }
3361 ScaleOffset = Math.Abs(ScaleOffset); 3113
3362 Vector3 intersectionpoint = ei.ipoint; 3114 public virtual void SubscribeToClientPrimRezEvents(IClientAPI client)
3363 Vector3 normal = ei.normal; 3115 {
3364 Vector3 offset = normal * (ScaleOffset / 2f); 3116 client.OnAddPrim += AddNewPrim;
3365 pos = intersectionpoint + offset; 3117 client.OnRezObject += RezObject;
3366 3118 }
3367 // stick in offset format from the original prim 3119
3368 pos = pos - target.ParentGroup.AbsolutePosition; 3120 public virtual void SubscribeToClientInventoryEvents(IClientAPI client)
3369 SceneObjectGroup copy; 3121 {
3370 if (CopyRotates) 3122 client.OnLinkInventoryItem += HandleLinkInventoryItem;
3371 { 3123 client.OnCreateNewInventoryFolder += HandleCreateInventoryFolder;
3372 Quaternion worldRot = target2.GetWorldRotation(); 3124 client.OnUpdateInventoryFolder += HandleUpdateInventoryFolder;
3373 3125 client.OnMoveInventoryFolder += HandleMoveInventoryFolder; // 2; //!!
3374 // SceneObjectGroup obj = m_sceneGraph.DuplicateObject(localID, pos, target.GetEffectiveObjectFlags(), AgentID, GroupID, worldRot); 3126 client.OnFetchInventoryDescendents += HandleFetchInventoryDescendents;
3375 copy = m_sceneGraph.DuplicateObject(localID, pos, target.GetEffectiveObjectFlags(), AgentID, GroupID, worldRot); 3127 client.OnPurgeInventoryDescendents += HandlePurgeInventoryDescendents; // 2; //!!
3376 //obj.Rotation = worldRot; 3128 client.OnFetchInventory += m_asyncInventorySender.HandleFetchInventory;
3377 //obj.UpdateGroupRotationR(worldRot); 3129 client.OnUpdateInventoryItem += UpdateInventoryItemAsset;
3378 } 3130 client.OnCopyInventoryItem += CopyInventoryItem;
3379 else 3131 client.OnMoveInventoryItem += MoveInventoryItem;
3380 { 3132 client.OnRemoveInventoryItem += RemoveInventoryItem;
3381 copy = m_sceneGraph.DuplicateObject(localID, pos, target.GetEffectiveObjectFlags(), AgentID, GroupID, Quaternion.Identity); 3133 client.OnRemoveInventoryFolder += RemoveInventoryFolder;
3382 } 3134 client.OnRezScript += RezScript;
3383 3135 client.OnRequestTaskInventory += RequestTaskInventory;
3384 if (copy != null) 3136 client.OnRemoveTaskItem += RemoveTaskInventory;
3385 EventManager.TriggerObjectAddedToScene(copy); 3137 client.OnUpdateTaskInventory += UpdateTaskInventory;
3386 } 3138 client.OnMoveTaskItem += ClientMoveTaskInventoryItem;
3387 } 3139 }
3388 } 3140
3389 3141 public virtual void SubscribeToClientTeleportEvents(IClientAPI client)
3390 /// <summary> 3142 {
3391 /// Get the avatar apperance for the given client. 3143 client.OnTeleportLocationRequest += RequestTeleportLocation;
3392 /// </summary> 3144 }
3393 /// <param name="client"></param> 3145
3394 /// <param name="appearance"></param> 3146 public virtual void SubscribeToClientScriptEvents(IClientAPI client)
3395 public void GetAvatarAppearance(IClientAPI client, out AvatarAppearance appearance) 3147 {
3396 { 3148 client.OnScriptReset += ProcessScriptReset;
3397 AgentCircuitData aCircuit = m_authenticateHandler.GetAgentCircuitData(client.CircuitCode); 3149 client.OnGetScriptRunning += GetScriptRunning;
3398 3150 client.OnSetScriptRunning += SetScriptRunning;
3399 if (aCircuit == null) 3151 }
3400 { 3152
3401 m_log.DebugFormat("[APPEARANCE] Client did not supply a circuit. Non-Linden? Creating default appearance."); 3153 public virtual void SubscribeToClientParcelEvents(IClientAPI client)
3402 appearance = new AvatarAppearance(); 3154 {
3403 return; 3155 client.OnParcelReturnObjectsRequest += LandChannel.ReturnObjectsInParcel;
3404 } 3156 client.OnParcelSetOtherCleanTime += LandChannel.SetParcelOtherCleanTime;
3405 3157 client.OnParcelBuy += ProcessParcelBuy;
3406 appearance = aCircuit.Appearance; 3158 }
3407 if (appearance == null) 3159
3408 { 3160 public virtual void SubscribeToClientGridEvents(IClientAPI client)
3409 m_log.DebugFormat("[APPEARANCE]: Appearance not found in {0}, returning default", RegionInfo.RegionName); 3161 {
3410 appearance = new AvatarAppearance(); 3162 //client.OnNameFromUUIDRequest += HandleUUIDNameRequest;
3411 } 3163 client.OnMoneyTransferRequest += ProcessMoneyTransferRequest;
3412 } 3164 }
3413 3165
3414 /// <summary> 3166 public virtual void SubscribeToClientNetworkEvents(IClientAPI client)
3415 /// Remove the given client from the scene. 3167 {
3416 /// </summary> 3168 client.OnNetworkStatsUpdate += StatsReporter.AddPacketsStats;
3417 /// <remarks> 3169 client.OnViewerEffect += ProcessViewerEffect;
3418 /// Only clientstack code should call this directly. All other code should call IncomingCloseAgent() instead 3170 }
3419 /// to properly operate the state machine and avoid race conditions with other close requests (such as directly 3171
3420 /// from viewers). 3172 /// <summary>
3421 /// </remarks> 3173 /// Unsubscribe the client from events.
3422 /// <param name='agentID'>ID of agent to close</param> 3174 /// </summary>
3423 /// <param name='closeChildAgents'> 3175 /// FIXME: Not called anywhere!
3424 /// Close the neighbour child agents associated with this client. 3176 /// <param name="client">The IClientAPI of the client</param>
3425 /// </param> 3177 public virtual void UnSubscribeToClientEvents(IClientAPI client)
3426 public void RemoveClient(UUID agentID, bool closeChildAgents) 3178 {
3427 { 3179 UnSubscribeToClientTerrainEvents(client);
3428 AgentCircuitData acd = m_authenticateHandler.GetAgentCircuitData(agentID); 3180 UnSubscribeToClientPrimEvents(client);
3181 UnSubscribeToClientPrimRezEvents(client);
3182 UnSubscribeToClientInventoryEvents(client);
3183 UnSubscribeToClientTeleportEvents(client);
3184 UnSubscribeToClientScriptEvents(client);
3185 UnSubscribeToClientParcelEvents(client);
3186 UnSubscribeToClientGridEvents(client);
3187 UnSubscribeToClientNetworkEvents(client);
3188 }
3189
3190 public virtual void UnSubscribeToClientTerrainEvents(IClientAPI client)
3191 {
3192 client.OnRegionHandShakeReply -= SendLayerData;
3193 }
3194
3195 public virtual void UnSubscribeToClientPrimEvents(IClientAPI client)
3196 {
3197 client.OnUpdatePrimGroupPosition -= m_sceneGraph.UpdatePrimGroupPosition;
3198 client.OnUpdatePrimSinglePosition -= m_sceneGraph.UpdatePrimSinglePosition;
3199
3200 client.OnUpdatePrimGroupRotation -= m_sceneGraph.UpdatePrimGroupRotation;
3201 client.OnUpdatePrimGroupMouseRotation -= m_sceneGraph.UpdatePrimGroupRotation;
3202 client.OnUpdatePrimSingleRotation -= m_sceneGraph.UpdatePrimSingleRotation;
3203 client.OnUpdatePrimSingleRotationPosition -= m_sceneGraph.UpdatePrimSingleRotationPosition;
3204
3205 client.OnUpdatePrimScale -= m_sceneGraph.UpdatePrimScale;
3206 client.OnUpdatePrimGroupScale -= m_sceneGraph.UpdatePrimGroupScale;
3207 client.OnUpdateExtraParams -= m_sceneGraph.UpdateExtraParam;
3208 client.OnUpdatePrimShape -= m_sceneGraph.UpdatePrimShape;
3209 client.OnUpdatePrimTexture -= m_sceneGraph.UpdatePrimTexture;
3210 client.OnObjectRequest -= RequestPrim;
3211 client.OnObjectSelect -= SelectPrim;
3212 client.OnObjectDeselect -= DeselectPrim;
3213 client.OnGrabUpdate -= m_sceneGraph.MoveObject;
3214 client.OnSpinStart -= m_sceneGraph.SpinStart;
3215 client.OnSpinUpdate -= m_sceneGraph.SpinObject;
3216 client.OnDeRezObject -= DeRezObjects;
3217 client.OnObjectName -= m_sceneGraph.PrimName;
3218 client.OnObjectClickAction -= m_sceneGraph.PrimClickAction;
3219 client.OnObjectMaterial -= m_sceneGraph.PrimMaterial;
3220 client.OnLinkObjects -= LinkObjects;
3221 client.OnDelinkObjects -= DelinkObjects;
3222 client.OnObjectDuplicate -= DuplicateObject;
3223 client.OnObjectDuplicateOnRay -= doObjectDuplicateOnRay;
3224 client.OnUpdatePrimFlags -= m_sceneGraph.UpdatePrimFlags;
3225 client.OnRequestObjectPropertiesFamily -= m_sceneGraph.RequestObjectPropertiesFamily;
3226 client.OnObjectPermissions -= HandleObjectPermissionsUpdate;
3227 client.OnGrabObject -= ProcessObjectGrab;
3228 client.OnDeGrabObject -= ProcessObjectDeGrab;
3229 client.OnUndo -= m_sceneGraph.HandleUndo;
3230 client.OnRedo -= m_sceneGraph.HandleRedo;
3231 client.OnObjectDescription -= m_sceneGraph.PrimDescription;
3232 client.OnObjectIncludeInSearch -= m_sceneGraph.MakeObjectSearchable;
3233 client.OnObjectOwner -= ObjectOwner;
3234 }
3235
3236 public virtual void UnSubscribeToClientPrimRezEvents(IClientAPI client)
3237 {
3238 client.OnAddPrim -= AddNewPrim;
3239 client.OnRezObject -= RezObject;
3240 }
3241
3242 public virtual void UnSubscribeToClientInventoryEvents(IClientAPI client)
3243 {
3244 client.OnCreateNewInventoryFolder -= HandleCreateInventoryFolder;
3245 client.OnUpdateInventoryFolder -= HandleUpdateInventoryFolder;
3246 client.OnMoveInventoryFolder -= HandleMoveInventoryFolder; // 2; //!!
3247 client.OnFetchInventoryDescendents -= HandleFetchInventoryDescendents;
3248 client.OnPurgeInventoryDescendents -= HandlePurgeInventoryDescendents; // 2; //!!
3249 client.OnFetchInventory -= m_asyncInventorySender.HandleFetchInventory;
3250 client.OnUpdateInventoryItem -= UpdateInventoryItemAsset;
3251 client.OnCopyInventoryItem -= CopyInventoryItem;
3252 client.OnMoveInventoryItem -= MoveInventoryItem;
3253 client.OnRemoveInventoryItem -= RemoveInventoryItem;
3254 client.OnRemoveInventoryFolder -= RemoveInventoryFolder;
3255 client.OnRezScript -= RezScript;
3256 client.OnRequestTaskInventory -= RequestTaskInventory;
3257 client.OnRemoveTaskItem -= RemoveTaskInventory;
3258 client.OnUpdateTaskInventory -= UpdateTaskInventory;
3259 client.OnMoveTaskItem -= ClientMoveTaskInventoryItem;
3260 }
3261
3262 public virtual void UnSubscribeToClientTeleportEvents(IClientAPI client)
3263 {
3264 client.OnTeleportLocationRequest -= RequestTeleportLocation;
3265 //client.OnTeleportLandmarkRequest -= RequestTeleportLandmark;
3266 //client.OnTeleportHomeRequest -= TeleportClientHome;
3267 }
3268
3269 public virtual void UnSubscribeToClientScriptEvents(IClientAPI client)
3270 {
3271 client.OnScriptReset -= ProcessScriptReset;
3272 client.OnGetScriptRunning -= GetScriptRunning;
3273 client.OnSetScriptRunning -= SetScriptRunning;
3274 }
3275
3276 public virtual void UnSubscribeToClientParcelEvents(IClientAPI client)
3277 {
3278 client.OnParcelReturnObjectsRequest -= LandChannel.ReturnObjectsInParcel;
3279 client.OnParcelSetOtherCleanTime -= LandChannel.SetParcelOtherCleanTime;
3280 client.OnParcelBuy -= ProcessParcelBuy;
3281 }
3282
3283 public virtual void UnSubscribeToClientGridEvents(IClientAPI client)
3284 {
3285 //client.OnNameFromUUIDRequest -= HandleUUIDNameRequest;
3286 client.OnMoneyTransferRequest -= ProcessMoneyTransferRequest;
3287 }
3288
3289 public virtual void UnSubscribeToClientNetworkEvents(IClientAPI client)
3290 {
3291 client.OnNetworkStatsUpdate -= StatsReporter.AddPacketsStats;
3292 client.OnViewerEffect -= ProcessViewerEffect;
3293 }
3294
3295 /// <summary>
3296 /// Teleport an avatar to their home region
3297 /// </summary>
3298 /// <param name="agentId">The avatar's Unique ID</param>
3299 /// <param name="client">The IClientAPI for the client</param>
3300 public virtual bool TeleportClientHome(UUID agentId, IClientAPI client)
3301 {
3302 if (EntityTransferModule != null)
3303 {
3304 return EntityTransferModule.TeleportHome(agentId, client);
3305 }
3306 else
3307 {
3308 m_log.DebugFormat("[SCENE]: Unable to teleport user home: no AgentTransferModule is active");
3309 client.SendTeleportFailed("Unable to perform teleports on this simulator.");
3310 }
3311 return false;
3312 }
3313
3314 /// <summary>
3315 /// Duplicates object specified by localID. This is the event handler for IClientAPI.
3316 /// </summary>
3317 /// <param name="originalPrim">ID of object to duplicate</param>
3318 /// <param name="offset"></param>
3319 /// <param name="flags"></param>
3320 /// <param name="AgentID">Agent doing the duplication</param>
3321 /// <param name="GroupID">Group of new object</param>
3322 public void DuplicateObject(uint originalPrim, Vector3 offset, uint flags, UUID AgentID, UUID GroupID)
3323 {
3324 SceneObjectGroup copy = SceneGraph.DuplicateObject(originalPrim, offset, flags, AgentID, GroupID, Quaternion.Identity);
3325 if (copy != null)
3326 EventManager.TriggerObjectAddedToScene(copy);
3327 }
3328
3329 /// <summary>
3330 /// Duplicates object specified by localID at position raycasted against RayTargetObject using
3331 /// RayEnd and RayStart to determine what the angle of the ray is
3332 /// </summary>
3333 /// <param name="localID">ID of object to duplicate</param>
3334 /// <param name="dupeFlags"></param>
3335 /// <param name="AgentID">Agent doing the duplication</param>
3336 /// <param name="GroupID">Group of new object</param>
3337 /// <param name="RayTargetObj">The target of the Ray</param>
3338 /// <param name="RayEnd">The ending of the ray (farthest away point)</param>
3339 /// <param name="RayStart">The Beginning of the ray (closest point)</param>
3340 /// <param name="BypassRaycast">Bool to bypass raycasting</param>
3341 /// <param name="RayEndIsIntersection">The End specified is the place to add the object</param>
3342 /// <param name="CopyCenters">Position the object at the center of the face that it's colliding with</param>
3343 /// <param name="CopyRotates">Rotate the object the same as the localID object</param>
3344 public void doObjectDuplicateOnRay(uint localID, uint dupeFlags, UUID AgentID, UUID GroupID,
3345 UUID RayTargetObj, Vector3 RayEnd, Vector3 RayStart,
3346 bool BypassRaycast, bool RayEndIsIntersection, bool CopyCenters, bool CopyRotates)
3347 {
3348 Vector3 pos;
3349 const bool frontFacesOnly = true;
3350 //m_log.Info("HITTARGET: " + RayTargetObj.ToString() + ", COPYTARGET: " + localID.ToString());
3351 SceneObjectPart target = GetSceneObjectPart(localID);
3352 SceneObjectPart target2 = GetSceneObjectPart(RayTargetObj);
3353
3354 if (target != null && target2 != null)
3355 {
3356 Vector3 direction = Vector3.Normalize(RayEnd - RayStart);
3357 Vector3 AXOrigin = RayStart;
3358 Vector3 AXdirection = direction;
3359
3360 pos = target2.AbsolutePosition;
3361 //m_log.Info("[OBJECT_REZ]: TargetPos: " + pos.ToString() + ", RayStart: " + RayStart.ToString() + ", RayEnd: " + RayEnd.ToString() + ", Volume: " + Util.GetDistanceTo(RayStart,RayEnd).ToString() + ", mag1: " + Util.GetMagnitude(RayStart).ToString() + ", mag2: " + Util.GetMagnitude(RayEnd).ToString());
3362
3363 // TODO: Raytrace better here
3364
3365 //EntityIntersection ei = m_sceneGraph.GetClosestIntersectingPrim(new Ray(AXOrigin, AXdirection));
3366 Ray NewRay = new Ray(AXOrigin, AXdirection);
3367
3368 // Ray Trace against target here
3369 EntityIntersection ei = target2.TestIntersectionOBB(NewRay, Quaternion.Identity, frontFacesOnly, CopyCenters);
3370
3371 // Un-comment out the following line to Get Raytrace results printed to the console.
3372 //m_log.Info("[RAYTRACERESULTS]: Hit:" + ei.HitTF.ToString() + " Point: " + ei.ipoint.ToString() + " Normal: " + ei.normal.ToString());
3373 float ScaleOffset = 0.5f;
3374
3375 // If we hit something
3376 if (ei.HitTF)
3377 {
3378 Vector3 scale = target.Scale;
3379 Vector3 scaleComponent = ei.AAfaceNormal;
3380 if (scaleComponent.X != 0) ScaleOffset = scale.X;
3381 if (scaleComponent.Y != 0) ScaleOffset = scale.Y;
3382 if (scaleComponent.Z != 0) ScaleOffset = scale.Z;
3383 ScaleOffset = Math.Abs(ScaleOffset);
3384 Vector3 intersectionpoint = ei.ipoint;
3385 Vector3 normal = ei.normal;
3386 Vector3 offset = normal * (ScaleOffset / 2f);
3387 pos = intersectionpoint + offset;
3388
3389 // stick in offset format from the original prim
3390 pos = pos - target.ParentGroup.AbsolutePosition;
3391 SceneObjectGroup copy;
3392 if (CopyRotates)
3393 {
3394 Quaternion worldRot = target2.GetWorldRotation();
3395
3396 // SceneObjectGroup obj = m_sceneGraph.DuplicateObject(localID, pos, target.GetEffectiveObjectFlags(), AgentID, GroupID, worldRot);
3397 copy = m_sceneGraph.DuplicateObject(localID, pos, target.GetEffectiveObjectFlags(), AgentID, GroupID, worldRot);
3398 //obj.Rotation = worldRot;
3399 //obj.UpdateGroupRotationR(worldRot);
3400 }
3401 else
3402 {
3403 copy = m_sceneGraph.DuplicateObject(localID, pos, target.GetEffectiveObjectFlags(), AgentID, GroupID, Quaternion.Identity);
3404 }
3405
3406 if (copy != null)
3407 EventManager.TriggerObjectAddedToScene(copy);
3408 }
3409 }
3410 }
3411
3412 /// <summary>
3413 /// Get the avatar apperance for the given client.
3414 /// </summary>
3415 /// <param name="client"></param>
3416 /// <param name="appearance"></param>
3417 public void GetAvatarAppearance(IClientAPI client, out AvatarAppearance appearance)
3418 {
3419 AgentCircuitData aCircuit = m_authenticateHandler.GetAgentCircuitData(client.CircuitCode);
3420
3421 if (aCircuit == null)
3422 {
3423 m_log.DebugFormat("[APPEARANCE] Client did not supply a circuit. Non-Linden? Creating default appearance.");
3424 appearance = new AvatarAppearance();
3425 return;
3426 }
3427
3428 appearance = aCircuit.Appearance;
3429 if (appearance == null)
3430 {
3431 m_log.DebugFormat("[APPEARANCE]: Appearance not found in {0}, returning default", RegionInfo.RegionName);
3432 appearance = new AvatarAppearance();
3433 }
3434 }
3435
3436 /// <summary>
3437 /// Remove the given client from the scene.
3438 /// </summary>
3439 /// <remarks>
3440 /// Only clientstack code should call this directly. All other code should call IncomingCloseAgent() instead
3441 /// to properly operate the state machine and avoid race conditions with other close requests (such as directly
3442 /// from viewers).
3443 /// </remarks>
3444 /// <param name='agentID'>ID of agent to close</param>
3445 /// <param name='closeChildAgents'>
3446 /// Close the neighbour child agents associated with this client.
3447 /// </param>
3448 public void RemoveClient(UUID agentID, bool closeChildAgents)
3449 {
3450 AgentCircuitData acd = m_authenticateHandler.GetAgentCircuitData(agentID);
3451
3452 // Shouldn't be necessary since RemoveClient() is currently only called by IClientAPI.Close() which
3453 // in turn is only called by Scene.IncomingCloseAgent() which checks whether the presence exists or not
3454 // However, will keep for now just in case.
3455 if (acd == null)
3456 {
3457 m_log.ErrorFormat(
3458 "[SCENE]: No agent circuit found for {0} in {1}, aborting Scene.RemoveClient", agentID, Name);
3459
3460 return;
3461 }
3462
3463 // TODO: Can we now remove this lock?
3464 lock (acd)
3465 {
3466 bool isChildAgent = false;
3467
3468 ScenePresence avatar = GetScenePresence(agentID);
3429 3469
3430 // Shouldn't be necessary since RemoveClient() is currently only called by IClientAPI.Close() which 3470 // Shouldn't be necessary since RemoveClient() is currently only called by IClientAPI.Close() which
3431 // in turn is only called by Scene.IncomingCloseAgent() which checks whether the presence exists or not 3471 // in turn is only called by Scene.IncomingCloseAgent() which checks whether the presence exists or not
3432 // However, will keep for now just in case. 3472 // However, will keep for now just in case.
3433 if (acd == null) 3473 if (avatar == null)
3434 { 3474 {
3435 m_log.ErrorFormat( 3475 m_log.ErrorFormat(
3436 "[SCENE]: No agent circuit found for {0} in {1}, aborting Scene.RemoveClient", agentID, Name); 3476 "[SCENE]: Called RemoveClient() with agent ID {0} but no such presence is in the scene.", agentID);
3437 3477 m_authenticateHandler.RemoveCircuit(agentID);
3438 return;
3439 }
3440
3441 // TODO: Can we now remove this lock?
3442 lock (acd)
3443 {
3444 bool isChildAgent = false;
3445
3446 ScenePresence avatar = GetScenePresence(agentID);
3447
3448 // Shouldn't be necessary since RemoveClient() is currently only called by IClientAPI.Close() which
3449 // in turn is only called by Scene.IncomingCloseAgent() which checks whether the presence exists or not
3450 // However, will keep for now just in case.
3451 if (avatar == null)
3452 {
3453 m_log.ErrorFormat(
3454 "[SCENE]: Called RemoveClient() with agent ID {0} but no such presence is in the scene.", agentID);
3455 m_authenticateHandler.RemoveCircuit(agentID);
3456
3457 return;
3458 }
3459
3460 try
3461 {
3462 isChildAgent = avatar.IsChildAgent;
3463
3464 m_log.DebugFormat(
3465 "[SCENE]: Removing {0} agent {1} {2} from {3}",
3466 isChildAgent ? "child" : "root", avatar.Name, agentID, Name);
3467
3468 // Don't do this to root agents, it's not nice for the viewer
3469 if (closeChildAgents && isChildAgent)
3470 {
3471 // Tell a single agent to disconnect from the region.
3472 // Let's do this via UDP
3473 avatar.ControllingClient.SendShutdownConnectionNotice();
3474 }
3475
3476 // Only applies to root agents.
3477 if (avatar.ParentID != 0)
3478 {
3479 avatar.StandUp();
3480 }
3481
3482 m_sceneGraph.removeUserCount(!isChildAgent);
3483
3484 // TODO: We shouldn't use closeChildAgents here - it's being used by the NPC module to stop
3485 // unnecessary operations. This should go away once NPCs have no accompanying IClientAPI
3486 if (closeChildAgents && CapsModule != null)
3487 CapsModule.RemoveCaps(agentID);
3488
3489 if (closeChildAgents && !isChildAgent)
3490 {
3491 List<ulong> regions = avatar.KnownRegionHandles;
3492 regions.Remove(RegionInfo.RegionHandle);
3493
3494 // This ends up being done asynchronously so that a logout isn't held up where there are many present but unresponsive neighbours.
3495 m_sceneGridService.SendCloseChildAgentConnections(agentID, acd.SessionID.ToString(), regions);
3496 }
3497
3498 m_eventManager.TriggerClientClosed(agentID, this);
3499 m_eventManager.TriggerOnRemovePresence(agentID);
3500
3501 if (!isChildAgent)
3502 {
3503 if (AttachmentsModule != null)
3504 {
3505 AttachmentsModule.DeRezAttachments(avatar);
3506 }
3507
3508 ForEachClient(
3509 delegate(IClientAPI client)
3510 {
3511 //We can safely ignore null reference exceptions. It means the avatar is dead and cleaned up anyway
3512 try { client.SendKillObject(new List<uint> { avatar.LocalId }); }
3513 catch (NullReferenceException) { }
3514 });
3515 }
3516
3517 // It's possible for child agents to have transactions if changes are being made cross-border.
3518 if (AgentTransactionsModule != null)
3519 AgentTransactionsModule.RemoveAgentAssetTransactions(agentID);
3520 }
3521 catch (Exception e)
3522 {
3523 m_log.Error(
3524 string.Format("[SCENE]: Exception removing {0} from {1}. Cleaning up. Exception ", avatar.Name, Name), e);
3525 }
3526 finally
3527 {
3528 try
3529 {
3530 // Always clean these structures up so that any failure above doesn't cause them to remain in the
3531 // scene with possibly bad effects (e.g. continually timing out on unacked packets and triggering
3532 // the same cleanup exception continually.
3533 m_authenticateHandler.RemoveCircuit(agentID);
3534 m_sceneGraph.RemoveScenePresence(agentID);
3535 m_clientManager.Remove(agentID);
3536
3537 avatar.Close();
3538 }
3539 catch (Exception e)
3540 {
3541 m_log.Error(
3542 string.Format("[SCENE]: Exception in final clean up of {0} in {1}. Exception ", avatar.Name, Name), e);
3543 }
3544 }
3545 }
3546
3547 //m_log.InfoFormat("[SCENE] Memory pre GC {0}", System.GC.GetTotalMemory(false));
3548 //m_log.InfoFormat("[SCENE] Memory post GC {0}", System.GC.GetTotalMemory(true));
3549 }
3550
3551 /// <summary>
3552 /// Removes region from an avatar's known region list. This coincides with child agents. For each child agent, there will be a known region entry.
3553 ///
3554 /// </summary>
3555 /// <param name="avatarID"></param>
3556 /// <param name="regionslst"></param>
3557 public void HandleRemoveKnownRegionsFromAvatar(UUID avatarID, List<ulong> regionslst)
3558 {
3559 ScenePresence av = GetScenePresence(avatarID);
3560 if (av != null)
3561 {
3562 lock (av)
3563 {
3564 for (int i = 0; i < regionslst.Count; i++)
3565 {
3566 av.RemoveNeighbourRegion(regionslst[i]);
3567 }
3568 }
3569 }
3570 }
3571
3572 #endregion
3573
3574 #region Entities
3575
3576 public void SendKillObject(List<uint> localIDs)
3577 {
3578 List<uint> deleteIDs = new List<uint>();
3579
3580 foreach (uint localID in localIDs)
3581 {
3582 SceneObjectPart part = GetSceneObjectPart(localID);
3583 if (part != null) // It is a prim
3584 {
3585 if (part.ParentGroup != null && !part.ParentGroup.IsDeleted) // Valid
3586 {
3587 if (part.ParentGroup.RootPart != part) // Child part
3588 continue;
3589 }
3590 }
3591 deleteIDs.Add(localID);
3592 }
3593
3594 ForEachClient(c => c.SendKillObject(deleteIDs));
3595 }
3596
3597 #endregion
3598
3599 #region RegionComms
3600
3601 /// <summary>
3602 /// Do the work necessary to initiate a new user connection for a particular scene.
3603 /// </summary>
3604 /// <param name="agent">CircuitData of the agent who is connecting</param>
3605 /// <param name="teleportFlags"></param>
3606 /// <param name="source">Source region (may be null)</param>
3607 /// <param name="reason">Outputs the reason for the false response on this string</param>
3608 /// <returns>True if the region accepts this agent. False if it does not. False will
3609 /// also return a reason.</returns>
3610 public bool NewUserConnection(AgentCircuitData agent, uint teleportFlags, GridRegion source, out string reason)
3611 {
3612 return NewUserConnection(agent, teleportFlags, source, out reason, true);
3613 }
3614
3615 /// <summary>
3616 /// Do the work necessary to initiate a new user connection for a particular scene.
3617 /// </summary>
3618 /// <remarks>
3619 /// The return bool should allow for connections to be refused, but as not all calling paths
3620 /// take proper notice of it yet, we still allowed banned users in.
3621 ///
3622 /// At the moment this method consists of setting up the caps infrastructure
3623 /// The return bool should allow for connections to be refused, but as not all calling paths
3624 /// take proper notice of it let, we allowed banned users in still.
3625 ///
3626 /// This method is called by the login service (in the case of login) or another simulator (in the case of region
3627 /// cross or teleport) to initiate the connection. It is not triggered by the viewer itself - the connection
3628 /// is activated later when the viewer sends the initial UseCircuitCodePacket UDP packet (in the case of
3629 /// the LLUDP stack).
3630 /// </remarks>
3631 /// <param name="acd">CircuitData of the agent who is connecting</param>
3632 /// <param name="source">Source region (may be null)</param>
3633 /// <param name="reason">Outputs the reason for the false response on this string</param>
3634 /// <param name="requirePresenceLookup">True for normal presence. False for NPC
3635 /// or other applications where a full grid/Hypergrid presence may not be required.</param>
3636 /// <returns>True if the region accepts this agent. False if it does not. False will
3637 /// also return a reason.</returns>
3638 public bool NewUserConnection(AgentCircuitData acd, uint teleportFlags, GridRegion source, out string reason, bool requirePresenceLookup)
3639 {
3640 bool vialogin = ((teleportFlags & (uint)TPFlags.ViaLogin) != 0 ||
3641 (teleportFlags & (uint)TPFlags.ViaHGLogin) != 0);
3642 bool viahome = ((teleportFlags & (uint)TPFlags.ViaHome) != 0);
3643 bool godlike = ((teleportFlags & (uint)TPFlags.Godlike) != 0);
3644
3645 reason = String.Empty;
3646 3478
3647 //Teleport flags: 3479 return;
3648 // 3480 }
3649 // TeleportFlags.ViaGodlikeLure - Border Crossing
3650 // TeleportFlags.ViaLogin - Login
3651 // TeleportFlags.TeleportFlags.ViaLure - Teleport request sent by another user
3652 // TeleportFlags.ViaLandmark | TeleportFlags.ViaLocation | TeleportFlags.ViaLandmark | TeleportFlags.Default - Regular Teleport
3653 3481
3654 // Don't disable this log message - it's too helpful 3482 try
3655 string curViewer = Util.GetViewerName(acd); 3483 {
3656 m_log.DebugFormat( 3484 isChildAgent = avatar.IsChildAgent;
3657 "[SCENE]: Region {0} told of incoming {1} agent {2} {3} {4} (circuit code {5}, IP {6}, viewer {7}, teleportflags ({8}), position {9}. {10}", 3485
3658 RegionInfo.RegionName, 3486 m_log.DebugFormat(
3659 (acd.child ? "child" : "root"), 3487 "[SCENE]: Removing {0} agent {1} {2} from {3}",
3660 acd.firstname, 3488 isChildAgent ? "child" : "root", avatar.Name, agentID, Name);
3661 acd.lastname, 3489
3662 acd.AgentID, 3490 // Don't do this to root agents, it's not nice for the viewer
3663 acd.circuitcode, 3491 if (closeChildAgents && isChildAgent)
3664 acd.IPAddress, 3492 {
3665 curViewer, 3493 // Tell a single agent to disconnect from the region.
3666 ((TPFlags)teleportFlags).ToString(), 3494 // Let's do this via UDP
3667 acd.startpos, 3495 avatar.ControllingClient.SendShutdownConnectionNotice();
3668 (source == null) ? "" : string.Format("From region {0} ({1}){2}", source.RegionName, source.RegionID, (source.RawServerURI == null) ? "" : " @ " + source.ServerURI) 3496 }
3669 ); 3497
3670 3498 // Only applies to root agents.
3671 if (!LoginsEnabled) 3499 if (avatar.ParentID != 0)
3672 { 3500 {
3673 reason = "Logins Disabled"; 3501 avatar.StandUp();
3674 return false; 3502 }
3675 } 3503
3676 3504 m_sceneGraph.removeUserCount(!isChildAgent);
3677 //Check if the viewer is banned or in the viewer access list 3505
3678 //We check if the substring is listed for higher flexebility 3506 // TODO: We shouldn't use closeChildAgents here - it's being used by the NPC module to stop
3679 bool ViewerDenied = true; 3507 // unnecessary operations. This should go away once NPCs have no accompanying IClientAPI
3680 3508 if (closeChildAgents && CapsModule != null)
3681 //Check if the specific viewer is listed in the allowed viewer list 3509 CapsModule.RemoveCaps(agentID);
3682 if (m_AllowedViewers.Count > 0) 3510
3683 { 3511 if (closeChildAgents && !isChildAgent)
3684 foreach (string viewer in m_AllowedViewers) 3512 {
3685 { 3513 List<ulong> regions = avatar.KnownRegionHandles;
3686 if (viewer == curViewer.Substring(0, Math.Min(viewer.Length, curViewer.Length)).Trim().ToLower()) 3514 regions.Remove(RegionInfo.RegionHandle);
3687 { 3515
3688 ViewerDenied = false; 3516 // This ends up being done asynchronously so that a logout isn't held up where there are many present but unresponsive neighbours.
3689 break; 3517 m_sceneGridService.SendCloseChildAgentConnections(agentID, acd.SessionID.ToString(), regions);
3690 } 3518 }
3691 } 3519
3520 m_eventManager.TriggerClientClosed(agentID, this);
3521 m_eventManager.TriggerOnRemovePresence(agentID);
3522
3523 if (!isChildAgent)
3524 {
3525 if (AttachmentsModule != null)
3526 {
3527 AttachmentsModule.DeRezAttachments(avatar);
3528 }
3529
3530 ForEachClient(
3531 delegate(IClientAPI client)
3532 {
3533 //We can safely ignore null reference exceptions. It means the avatar is dead and cleaned up anyway
3534 try { client.SendKillObject(new List<uint> { avatar.LocalId }); }
3535 catch (NullReferenceException) { }
3536 });
3537 }
3538
3539 // It's possible for child agents to have transactions if changes are being made cross-border.
3540 if (AgentTransactionsModule != null)
3541 AgentTransactionsModule.RemoveAgentAssetTransactions(agentID);
3692 } 3542 }
3693 else 3543 catch (Exception e)
3694 { 3544 {
3695 ViewerDenied = false; 3545 m_log.Error(
3696 } 3546 string.Format("[SCENE]: Exception removing {0} from {1}. Cleaning up. Exception ", avatar.Name, Name), e);
3697 3547 }
3698 //Check if the viewer is in the banned list 3548 finally
3699 if (m_BannedViewers.Count > 0) 3549 {
3700 { 3550 try
3701 foreach (string viewer in m_BannedViewers) 3551 {
3702 { 3552 // Always clean these structures up so that any failure above doesn't cause them to remain in the
3703 if (viewer == curViewer.Substring(0, Math.Min(viewer.Length, curViewer.Length)).Trim().ToLower()) 3553 // scene with possibly bad effects (e.g. continually timing out on unacked packets and triggering
3704 { 3554 // the same cleanup exception continually.
3705 ViewerDenied = true; 3555 m_authenticateHandler.RemoveCircuit(agentID);
3706 break; 3556 m_sceneGraph.RemoveScenePresence(agentID);
3707 } 3557 m_clientManager.Remove(agentID);
3708 } 3558
3709 } 3559 avatar.Close();
3710 3560 }
3711 if (ViewerDenied) 3561 catch (Exception e)
3712 { 3562 {
3713 m_log.DebugFormat( 3563 m_log.Error(
3714 "[SCENE]: Access denied for {0} {1} using {2}", 3564 string.Format("[SCENE]: Exception in final clean up of {0} in {1}. Exception ", avatar.Name, Name), e);
3715 acd.firstname, acd.lastname, curViewer); 3565 }
3716 reason = "Access denied, your viewer is banned by the region owner"; 3566 }
3717 return false; 3567 }
3718 } 3568
3719 3569 //m_log.InfoFormat("[SCENE] Memory pre GC {0}", System.GC.GetTotalMemory(false));
3720 ILandObject land; 3570 //m_log.InfoFormat("[SCENE] Memory post GC {0}", System.GC.GetTotalMemory(true));
3721 ScenePresence sp; 3571 }
3722 3572
3723 lock (m_removeClientLock) 3573 /// <summary>
3724 { 3574 /// Removes region from an avatar's known region list. This coincides with child agents. For each child agent, there will be a known region entry.
3725 sp = GetScenePresence(acd.AgentID); 3575 ///
3726 3576 /// </summary>
3727 // We need to ensure that we are not already removing the scene presence before we ask it not to be 3577 /// <param name="avatarID"></param>
3728 // closed. 3578 /// <param name="regionslst"></param>
3729 if (sp != null && sp.IsChildAgent 3579 public void HandleRemoveKnownRegionsFromAvatar(UUID avatarID, List<ulong> regionslst)
3730 && (sp.LifecycleState == ScenePresenceState.Running 3580 {
3731 || sp.LifecycleState == ScenePresenceState.PreRemove)) 3581 ScenePresence av = GetScenePresence(avatarID);
3732 { 3582 if (av != null)
3733 m_log.DebugFormat( 3583 {
3734 "[SCENE]: Reusing existing child scene presence for {0}, state {1} in {2}", 3584 lock (av)
3735 sp.Name, sp.LifecycleState, Name); 3585 {
3736 3586 for (int i = 0; i < regionslst.Count; i++)
3737 // In the case where, for example, an A B C D region layout, an avatar may 3587 {
3738 // teleport from A -> D, but then -> C before A has asked B to close its old child agent. When C 3588 av.RemoveNeighbourRegion(regionslst[i]);
3739 // renews the lease on the child agent at B, we must make sure that the close from A does not succeed. 3589 }
3740 // 3590 }
3741 // XXX: In the end, this should not be necessary if child agents are closed without delay on 3591 }
3742 // teleport, since realistically, the close request should always be processed before any other 3592 }
3743 // region tried to re-establish a child agent. This is much simpler since the logic below is 3593
3744 // vulnerable to an issue when a viewer quits a region without sending a proper logout but then 3594 #endregion
3745 // re-establishes the connection on a relogin. This could wrongly set the DoNotCloseAfterTeleport 3595
3746 // flag when no teleport had taken place (and hence no close was going to come). 3596 #region Entities
3747// if (!acd.ChildrenCapSeeds.ContainsKey(RegionInfo.RegionHandle)) 3597
3748// { 3598 public void SendKillObject(List<uint> localIDs)
3749// m_log.DebugFormat( 3599 {
3750// "[SCENE]: Setting DoNotCloseAfterTeleport for child scene presence {0} in {1} because source will attempt close.", 3600 List<uint> deleteIDs = new List<uint>();
3751// sp.Name, Name); 3601
3752// 3602 foreach (uint localID in localIDs)
3753// sp.DoNotCloseAfterTeleport = true; 3603 {
3754// } 3604 SceneObjectPart part = GetSceneObjectPart(localID);
3755// else if (EntityTransferModule.IsInTransit(sp.UUID)) 3605 if (part != null) // It is a prim
3756 3606 {
3757 sp.LifecycleState = ScenePresenceState.Running; 3607 if (part.ParentGroup != null && !part.ParentGroup.IsDeleted) // Valid
3758 3608 {
3759 if (EntityTransferModule.IsInTransit(sp.UUID)) 3609 if (part.ParentGroup.RootPart != part) // Child part
3760 { 3610 continue;
3761 sp.DoNotCloseAfterTeleport = true; 3611 }
3762 3612 }
3763 m_log.DebugFormat( 3613 deleteIDs.Add(localID);
3764 "[SCENE]: Set DoNotCloseAfterTeleport for child scene presence {0} in {1} because this region will attempt end-of-teleport close from a previous close.", 3614 }
3765 sp.Name, Name); 3615
3766 } 3616 ForEachClient(c => c.SendKillObject(deleteIDs));
3767 } 3617 }
3768 } 3618
3769 3619 #endregion
3770 // Need to poll here in case we are currently deleting an sp. Letting threads run over each other will 3620
3771 // allow unpredictable things to happen. 3621 #region RegionComms
3772 if (sp != null) 3622
3623 /// <summary>
3624 /// Do the work necessary to initiate a new user connection for a particular scene.
3625 /// </summary>
3626 /// <param name="agent">CircuitData of the agent who is connecting</param>
3627 /// <param name="teleportFlags"></param>
3628 /// <param name="source">Source region (may be null)</param>
3629 /// <param name="reason">Outputs the reason for the false response on this string</param>
3630 /// <returns>True if the region accepts this agent. False if it does not. False will
3631 /// also return a reason.</returns>
3632 public bool NewUserConnection(AgentCircuitData agent, uint teleportFlags, GridRegion source, out string reason)
3633 {
3634 return NewUserConnection(agent, teleportFlags, source, out reason, true);
3635 }
3636
3637 /// <summary>
3638 /// Do the work necessary to initiate a new user connection for a particular scene.
3639 /// </summary>
3640 /// <remarks>
3641 /// The return bool should allow for connections to be refused, but as not all calling paths
3642 /// take proper notice of it yet, we still allowed banned users in.
3643 ///
3644 /// At the moment this method consists of setting up the caps infrastructure
3645 /// The return bool should allow for connections to be refused, but as not all calling paths
3646 /// take proper notice of it let, we allowed banned users in still.
3647 ///
3648 /// This method is called by the login service (in the case of login) or another simulator (in the case of region
3649 /// cross or teleport) to initiate the connection. It is not triggered by the viewer itself - the connection
3650 /// is activated later when the viewer sends the initial UseCircuitCodePacket UDP packet (in the case of
3651 /// the LLUDP stack).
3652 /// </remarks>
3653 /// <param name="acd">CircuitData of the agent who is connecting</param>
3654 /// <param name="source">Source region (may be null)</param>
3655 /// <param name="reason">Outputs the reason for the false response on this string</param>
3656 /// <param name="requirePresenceLookup">True for normal presence. False for NPC
3657 /// or other applications where a full grid/Hypergrid presence may not be required.</param>
3658 /// <returns>True if the region accepts this agent. False if it does not. False will
3659 /// also return a reason.</returns>
3660 public bool NewUserConnection(AgentCircuitData acd, uint teleportFlags, GridRegion source, out string reason, bool requirePresenceLookup)
3661 {
3662 bool vialogin = ((teleportFlags & (uint)TPFlags.ViaLogin) != 0 ||
3663 (teleportFlags & (uint)TPFlags.ViaHGLogin) != 0);
3664 bool viahome = ((teleportFlags & (uint)TPFlags.ViaHome) != 0);
3665 bool godlike = ((teleportFlags & (uint)TPFlags.Godlike) != 0);
3666
3667 reason = String.Empty;
3668
3669 //Teleport flags:
3670 //
3671 // TeleportFlags.ViaGodlikeLure - Border Crossing
3672 // TeleportFlags.ViaLogin - Login
3673 // TeleportFlags.TeleportFlags.ViaLure - Teleport request sent by another user
3674 // TeleportFlags.ViaLandmark | TeleportFlags.ViaLocation | TeleportFlags.ViaLandmark | TeleportFlags.Default - Regular Teleport
3675
3676 // Don't disable this log message - it's too helpful
3677 string curViewer = Util.GetViewerName(acd);
3678 m_log.DebugFormat(
3679 "[SCENE]: Region {0} told of incoming {1} agent {2} {3} {4} (circuit code {5}, IP {6}, viewer {7}, teleportflags ({8}), position {9}. {10}",
3680 RegionInfo.RegionName,
3681 (acd.child ? "child" : "root"),
3682 acd.firstname,
3683 acd.lastname,
3684 acd.AgentID,
3685 acd.circuitcode,
3686 acd.IPAddress,
3687 curViewer,
3688 ((TPFlags)teleportFlags).ToString(),
3689 acd.startpos,
3690 (source == null) ? "" : string.Format("From region {0} ({1}){2}", source.RegionName, source.RegionID, (source.RawServerURI == null) ? "" : " @ " + source.ServerURI)
3691 );
3692
3693 if (!LoginsEnabled)
3694 {
3695 reason = "Logins Disabled";
3696 return false;
3697 }
3698
3699 //Check if the viewer is banned or in the viewer access list
3700 //We check if the substring is listed for higher flexebility
3701 bool ViewerDenied = true;
3702
3703 //Check if the specific viewer is listed in the allowed viewer list
3704 if (m_AllowedViewers.Count > 0)
3705 {
3706 foreach (string viewer in m_AllowedViewers)
3707 {
3708 if (viewer == curViewer.Substring(0, Math.Min(viewer.Length, curViewer.Length)).Trim().ToLower())
3709 {
3710 ViewerDenied = false;
3711 break;
3712 }
3713 }
3714 }
3715 else
3716 {
3717 ViewerDenied = false;
3718 }
3719
3720 //Check if the viewer is in the banned list
3721 if (m_BannedViewers.Count > 0)
3722 {
3723 foreach (string viewer in m_BannedViewers)
3724 {
3725 if (viewer == curViewer.Substring(0, Math.Min(viewer.Length, curViewer.Length)).Trim().ToLower())
3726 {
3727 ViewerDenied = true;
3728 break;
3729 }
3730 }
3731 }
3732
3733 if (ViewerDenied)
3734 {
3735 m_log.DebugFormat(
3736 "[SCENE]: Access denied for {0} {1} using {2}",
3737 acd.firstname, acd.lastname, curViewer);
3738 reason = "Access denied, your viewer is banned by the region owner";
3739 return false;
3740 }
3741
3742 ILandObject land;
3743 ScenePresence sp;
3744
3745 lock (m_removeClientLock)
3746 {
3747 sp = GetScenePresence(acd.AgentID);
3748
3749 // We need to ensure that we are not already removing the scene presence before we ask it not to be
3750 // closed.
3751 if (sp != null && sp.IsChildAgent
3752 && (sp.LifecycleState == ScenePresenceState.Running
3753 || sp.LifecycleState == ScenePresenceState.PreRemove))
3754 {
3755 m_log.DebugFormat(
3756 "[SCENE]: Reusing existing child scene presence for {0}, state {1} in {2}",
3757 sp.Name, sp.LifecycleState, Name);
3758
3759 // In the case where, for example, an A B C D region layout, an avatar may
3760 // teleport from A -> D, but then -> C before A has asked B to close its old child agent. When C
3761 // renews the lease on the child agent at B, we must make sure that the close from A does not succeed.
3762 //
3763 // XXX: In the end, this should not be necessary if child agents are closed without delay on
3764 // teleport, since realistically, the close request should always be processed before any other
3765 // region tried to re-establish a child agent. This is much simpler since the logic below is
3766 // vulnerable to an issue when a viewer quits a region without sending a proper logout but then
3767 // re-establishes the connection on a relogin. This could wrongly set the DoNotCloseAfterTeleport
3768 // flag when no teleport had taken place (and hence no close was going to come).
3769 // if (!acd.ChildrenCapSeeds.ContainsKey(RegionInfo.RegionHandle))
3770 // {
3771 // m_log.DebugFormat(
3772 // "[SCENE]: Setting DoNotCloseAfterTeleport for child scene presence {0} in {1} because source will attempt close.",
3773 // sp.Name, Name);
3774 //
3775 // sp.DoNotCloseAfterTeleport = true;
3776 // }
3777 // else if (EntityTransferModule.IsInTransit(sp.UUID))
3778
3779 sp.LifecycleState = ScenePresenceState.Running;
3780
3781 if (EntityTransferModule.IsInTransit(sp.UUID))
3782 {
3783 sp.DoNotCloseAfterTeleport = true;
3784
3785 m_log.DebugFormat(
3786 "[SCENE]: Set DoNotCloseAfterTeleport for child scene presence {0} in {1} because this region will attempt end-of-teleport close from a previous close.",
3787 sp.Name, Name);
3788 }
3789 }
3790 }
3791
3792 // Need to poll here in case we are currently deleting an sp. Letting threads run over each other will
3793 // allow unpredictable things to happen.
3794 if (sp != null)
3795 {
3796 const int polls = 10;
3797 const int pollInterval = 1000;
3798 int pollsLeft = polls;
3799
3800 while (sp.LifecycleState == ScenePresenceState.Removing && pollsLeft-- > 0)
3801 Thread.Sleep(pollInterval);
3802
3803 if (sp.LifecycleState == ScenePresenceState.Removing)
3804 {
3805 m_log.WarnFormat(
3806 "[SCENE]: Agent {0} in {1} was still being removed after {2}s. Aborting NewUserConnection.",
3807 sp.Name, Name, polls * pollInterval / 1000);
3808
3809 return false;
3810 }
3811 else if (polls != pollsLeft)
3812 {
3813 m_log.DebugFormat(
3814 "[SCENE]: NewUserConnection for agent {0} in {1} had to wait {2}s for in-progress removal to complete on an old presence.",
3815 sp.Name, Name, polls * pollInterval / 1000);
3816 }
3817 }
3818
3819 // TODO: can we remove this lock?
3820 lock (acd)
3821 {
3822 if (sp != null && !sp.IsChildAgent)
3823 {
3824 // We have a root agent. Is it in transit?
3825 if (!EntityTransferModule.IsInTransit(sp.UUID))
3826 {
3827 // We have a zombie from a crashed session.
3828 // Or the same user is trying to be root twice here, won't work.
3829 // Kill it.
3830 m_log.WarnFormat(
3831 "[SCENE]: Existing root scene presence detected for {0} {1} in {2} when connecting. Removing existing presence.",
3832 sp.Name, sp.UUID, RegionInfo.RegionName);
3833
3834 if (sp.ControllingClient != null)
3835 CloseAgent(sp.UUID, true);
3836
3837 sp = null;
3838 }
3839 //else
3840 // m_log.WarnFormat("[SCENE]: Existing root scene presence for {0} {1} in {2}, but agent is in trasit", sp.Name, sp.UUID, RegionInfo.RegionName);
3841 }
3842
3843 // Optimistic: add or update the circuit data with the new agent circuit data and teleport flags.
3844 // We need the circuit data here for some of the subsequent checks. (groups, for example)
3845 // If the checks fail, we remove the circuit.
3846 acd.teleportFlags = teleportFlags;
3847 m_authenticateHandler.AddNewCircuit(acd.circuitcode, acd);
3848
3849 land = LandChannel.GetLandObject(acd.startpos.X, acd.startpos.Y);
3850
3851 // On login test land permisions
3852 if (vialogin)
3773 { 3853 {
3774 const int polls = 10; 3854 if (land != null && !TestLandRestrictions(acd.AgentID, out reason, ref acd.startpos.X, ref acd.startpos.Y))
3775 const int pollInterval = 1000; 3855 {
3776 int pollsLeft = polls; 3856 m_authenticateHandler.RemoveCircuit(acd.circuitcode);
3777 3857 return false;
3778 while (sp.LifecycleState == ScenePresenceState.Removing && pollsLeft-- > 0) 3858 }
3779 Thread.Sleep(pollInterval);
3780
3781 if (sp.LifecycleState == ScenePresenceState.Removing)
3782 {
3783 m_log.WarnFormat(
3784 "[SCENE]: Agent {0} in {1} was still being removed after {2}s. Aborting NewUserConnection.",
3785 sp.Name, Name, polls * pollInterval / 1000);
3786
3787 return false;
3788 }
3789 else if (polls != pollsLeft)
3790 {
3791 m_log.DebugFormat(
3792 "[SCENE]: NewUserConnection for agent {0} in {1} had to wait {2}s for in-progress removal to complete on an old presence.",
3793 sp.Name, Name, polls * pollInterval / 1000);
3794 }
3795 }
3796
3797 // TODO: can we remove this lock?
3798 lock (acd)
3799 {
3800 if (sp != null && !sp.IsChildAgent)
3801 {
3802 // We have a root agent. Is it in transit?
3803 if (!EntityTransferModule.IsInTransit(sp.UUID))
3804 {
3805 // We have a zombie from a crashed session.
3806 // Or the same user is trying to be root twice here, won't work.
3807 // Kill it.
3808 m_log.WarnFormat(
3809 "[SCENE]: Existing root scene presence detected for {0} {1} in {2} when connecting. Removing existing presence.",
3810 sp.Name, sp.UUID, RegionInfo.RegionName);
3811
3812 if (sp.ControllingClient != null)
3813 CloseAgent(sp.UUID, true);
3814
3815 sp = null;
3816 }
3817 //else
3818 // m_log.WarnFormat("[SCENE]: Existing root scene presence for {0} {1} in {2}, but agent is in trasit", sp.Name, sp.UUID, RegionInfo.RegionName);
3819 }
3820
3821 // Optimistic: add or update the circuit data with the new agent circuit data and teleport flags.
3822 // We need the circuit data here for some of the subsequent checks. (groups, for example)
3823 // If the checks fail, we remove the circuit.
3824 acd.teleportFlags = teleportFlags;
3825 m_authenticateHandler.AddNewCircuit(acd.circuitcode, acd);
3826
3827 land = LandChannel.GetLandObject(acd.startpos.X, acd.startpos.Y);
3828
3829 // On login test land permisions
3830 if (vialogin)
3831 {
3832 if (land != null && !TestLandRestrictions(acd.AgentID, out reason, ref acd.startpos.X, ref acd.startpos.Y))
3833 {
3834 m_authenticateHandler.RemoveCircuit(acd.circuitcode);
3835 return false;
3836 }
3837 }
3838
3839 if (sp == null) // We don't have an [child] agent here already
3840 {
3841 if (requirePresenceLookup)
3842 {
3843 try
3844 {
3845 if (!VerifyUserPresence(acd, out reason))
3846 {
3847 m_authenticateHandler.RemoveCircuit(acd.circuitcode);
3848 return false;
3849 }
3850 }
3851 catch (Exception e)
3852 {
3853 m_log.ErrorFormat(
3854 "[SCENE]: Exception verifying presence {0}{1}", e.Message, e.StackTrace);
3855
3856 m_authenticateHandler.RemoveCircuit(acd.circuitcode);
3857 return false;
3858 }
3859 }
3860
3861 try
3862 {
3863 if (!AuthorizeUser(acd, (vialogin ? false : SeeIntoRegion), out reason))
3864 {
3865 m_authenticateHandler.RemoveCircuit(acd.circuitcode);
3866 return false;
3867 }
3868 }
3869 catch (Exception e)
3870 {
3871 m_log.ErrorFormat(
3872 "[SCENE]: Exception authorizing user {0}{1}", e.Message, e.StackTrace);
3873
3874 m_authenticateHandler.RemoveCircuit(acd.circuitcode);
3875 return false;
3876 }
3877
3878 m_log.InfoFormat(
3879 "[SCENE]: Region {0} authenticated and authorized incoming {1} agent {2} {3} {4} (circuit code {5})",
3880 Name, (acd.child ? "child" : "root"), acd.firstname, acd.lastname,
3881 acd.AgentID, acd.circuitcode);
3882
3883 if (CapsModule != null)
3884 {
3885 CapsModule.SetAgentCapsSeeds(acd);
3886 CapsModule.CreateCaps(acd.AgentID);
3887 }
3888 }
3889 else
3890 {
3891 // Let the SP know how we got here. This has a lot of interesting
3892 // uses down the line.
3893 sp.TeleportFlags = (TPFlags)teleportFlags;
3894
3895 if (sp.IsChildAgent)
3896 {
3897 m_log.DebugFormat(
3898 "[SCENE]: Adjusting known seeds for existing agent {0} in {1}",
3899 acd.AgentID, RegionInfo.RegionName);
3900
3901 sp.AdjustKnownSeeds();
3902
3903 if (CapsModule != null)
3904 {
3905 CapsModule.SetAgentCapsSeeds(acd);
3906 CapsModule.CreateCaps(acd.AgentID);
3907 }
3908 }
3909 }
3910
3911 // Try caching an incoming user name much earlier on to see if this helps with an issue
3912 // where HG users are occasionally seen by others as "Unknown User" because their UUIDName
3913 // request for the HG avatar appears to trigger before the user name is cached.
3914 CacheUserName(null, acd);
3915 } 3859 }
3916 3860
3917 if (vialogin) 3861 if (sp == null) // We don't have an [child] agent here already
3918 { 3862 {
3919// CleanDroppedAttachments(); 3863 if (requirePresenceLookup)
3920 3864 {
3921 // Make sure avatar position is in the region (why it wouldn't be is a mystery but do sanity checking) 3865 try
3922 if (acd.startpos.X < 0) acd.startpos.X = 1f; 3866 {
3923 if (acd.startpos.X >= RegionInfo.RegionSizeX) acd.startpos.X = RegionInfo.RegionSizeX - 1f; 3867 if (!VerifyUserPresence(acd, out reason))
3924 if (acd.startpos.Y < 0) acd.startpos.Y = 1f; 3868 {
3925 if (acd.startpos.Y >= RegionInfo.RegionSizeY) acd.startpos.Y = RegionInfo.RegionSizeY - 1f;
3926
3927// m_log.DebugFormat(
3928// "[SCENE]: Found telehub object {0} for new user connection {1} to {2}",
3929// RegionInfo.RegionSettings.TelehubObject, acd.Name, Name);
3930
3931 // Honor Estate teleport routing via Telehubs excluding ViaHome and GodLike TeleportFlags
3932 if (RegionInfo.RegionSettings.TelehubObject != UUID.Zero &&
3933 RegionInfo.EstateSettings.AllowDirectTeleport == false &&
3934 !viahome && !godlike)
3935 {
3936 SceneObjectGroup telehub = GetSceneObjectGroup(RegionInfo.RegionSettings.TelehubObject);
3937
3938 if (telehub != null)
3939 {
3940 // Can have multiple SpawnPoints
3941 List<SpawnPoint> spawnpoints = RegionInfo.RegionSettings.SpawnPoints();
3942 if (spawnpoints.Count > 1)
3943 {
3944 // We have multiple SpawnPoints, Route the agent to a random or sequential one
3945 if (SpawnPointRouting == "random")
3946 acd.startpos = spawnpoints[Util.RandomClass.Next(spawnpoints.Count) - 1].GetLocation(
3947 telehub.AbsolutePosition,
3948 telehub.GroupRotation
3949 );
3950 else
3951 acd.startpos = spawnpoints[SpawnPoint()].GetLocation(
3952 telehub.AbsolutePosition,
3953 telehub.GroupRotation
3954 );
3955 }
3956 else if (spawnpoints.Count == 1)
3957 {
3958 // We have a single SpawnPoint and will route the agent to it
3959 acd.startpos = spawnpoints[0].GetLocation(telehub.AbsolutePosition, telehub.GroupRotation);
3960 }
3961 else
3962 {
3963 m_log.DebugFormat(
3964 "[SCENE]: No spawnpoints defined for telehub {0} for {1} in {2}. Continuing.",
3965 RegionInfo.RegionSettings.TelehubObject, acd.Name, Name);
3966 }
3967 }
3968 else
3969 {
3970 m_log.DebugFormat(
3971 "[SCENE]: No telehub {0} found to direct {1} in {2}. Continuing.",
3972 RegionInfo.RegionSettings.TelehubObject, acd.Name, Name);
3973 }
3974
3975 // Final permissions check; this time we don't allow changing the position
3976 if (!IsPositionAllowed(acd.AgentID, acd.startpos, ref reason))
3977 {
3978 m_authenticateHandler.RemoveCircuit(acd.circuitcode); 3869 m_authenticateHandler.RemoveCircuit(acd.circuitcode);
3979 return false; 3870 return false;
3980 } 3871 }
3981 3872 }
3982 return true; 3873 catch (Exception e)
3983 } 3874 {
3984 3875 m_log.ErrorFormat(
3985 // Honor parcel landing type and position. 3876 "[SCENE]: Exception verifying presence {0}{1}", e.Message, e.StackTrace);
3986 if (land != null) 3877
3987 { 3878 m_authenticateHandler.RemoveCircuit(acd.circuitcode);
3988 if (land.LandData.LandingType == (byte)1 && land.LandData.UserLocation != Vector3.Zero) 3879 return false;
3989 { 3880 }
3990 acd.startpos = land.LandData.UserLocation; 3881 }
3991 3882
3992 // Final permissions check; this time we don't allow changing the position 3883 try
3993 if (!IsPositionAllowed(acd.AgentID, acd.startpos, ref reason)) 3884 {
3994 { 3885 if (!AuthorizeUser(acd, (vialogin ? false : SeeIntoRegion), out reason))
3995 m_authenticateHandler.RemoveCircuit(acd.circuitcode); 3886 {
3996 return false; 3887 m_authenticateHandler.RemoveCircuit(acd.circuitcode);
3997 } 3888 return false;
3998 } 3889 }
3999 } 3890 }
3891 catch (Exception e)
3892 {
3893 m_log.ErrorFormat(
3894 "[SCENE]: Exception authorizing user {0}{1}", e.Message, e.StackTrace);
3895
3896 m_authenticateHandler.RemoveCircuit(acd.circuitcode);
3897 return false;
3898 }
3899
3900 m_log.InfoFormat(
3901 "[SCENE]: Region {0} authenticated and authorized incoming {1} agent {2} {3} {4} (circuit code {5})",
3902 Name, (acd.child ? "child" : "root"), acd.firstname, acd.lastname,
3903 acd.AgentID, acd.circuitcode);
3904
3905 if (CapsModule != null)
3906 {
3907 CapsModule.SetAgentCapsSeeds(acd);
3908 CapsModule.CreateCaps(acd.AgentID);
3909 }
4000 } 3910 }
3911 else
3912 {
3913 // Let the SP know how we got here. This has a lot of interesting
3914 // uses down the line.
3915 sp.TeleportFlags = (TPFlags)teleportFlags;
3916
3917 if (sp.IsChildAgent)
3918 {
3919 m_log.DebugFormat(
3920 "[SCENE]: Adjusting known seeds for existing agent {0} in {1}",
3921 acd.AgentID, RegionInfo.RegionName);
3922
3923 sp.AdjustKnownSeeds();
3924
3925 if (CapsModule != null)
3926 {
3927 CapsModule.SetAgentCapsSeeds(acd);
3928 CapsModule.CreateCaps(acd.AgentID);
3929 }
3930 }
3931 }
3932
3933 // Try caching an incoming user name much earlier on to see if this helps with an issue
3934 // where HG users are occasionally seen by others as "Unknown User" because their UUIDName
3935 // request for the HG avatar appears to trigger before the user name is cached.
3936 CacheUserName(null, acd);
3937 }
3938
3939 if (vialogin)
3940 {
3941 // CleanDroppedAttachments();
3942
3943 // Make sure avatar position is in the region (why it wouldn't be is a mystery but do sanity checking)
3944 if (acd.startpos.X < 0) acd.startpos.X = 1f;
3945 if (acd.startpos.X >= RegionInfo.RegionSizeX) acd.startpos.X = RegionInfo.RegionSizeX - 1f;
3946 if (acd.startpos.Y < 0) acd.startpos.Y = 1f;
3947 if (acd.startpos.Y >= RegionInfo.RegionSizeY) acd.startpos.Y = RegionInfo.RegionSizeY - 1f;
3948
3949 // m_log.DebugFormat(
3950 // "[SCENE]: Found telehub object {0} for new user connection {1} to {2}",
3951 // RegionInfo.RegionSettings.TelehubObject, acd.Name, Name);
3952
3953 // Honor Estate teleport routing via Telehubs excluding ViaHome and GodLike TeleportFlags
3954 if (RegionInfo.RegionSettings.TelehubObject != UUID.Zero &&
3955 RegionInfo.EstateSettings.AllowDirectTeleport == false &&
3956 !viahome && !godlike)
3957 {
3958 SceneObjectGroup telehub = GetSceneObjectGroup(RegionInfo.RegionSettings.TelehubObject);
3959
3960 if (telehub != null)
3961 {
3962 // Can have multiple SpawnPoints
3963 List<SpawnPoint> spawnpoints = RegionInfo.RegionSettings.SpawnPoints();
3964 if (spawnpoints.Count > 1)
3965 {
3966 // We have multiple SpawnPoints, Route the agent to a random or sequential one
3967 if (SpawnPointRouting == "random")
3968 acd.startpos = spawnpoints[Util.RandomClass.Next(spawnpoints.Count) - 1].GetLocation(
3969 telehub.AbsolutePosition,
3970 telehub.GroupRotation
3971 );
3972 else
3973 acd.startpos = spawnpoints[SpawnPoint()].GetLocation(
3974 telehub.AbsolutePosition,
3975 telehub.GroupRotation
3976 );
3977 }
3978 else if (spawnpoints.Count == 1)
3979 {
3980 // We have a single SpawnPoint and will route the agent to it
3981 acd.startpos = spawnpoints[0].GetLocation(telehub.AbsolutePosition, telehub.GroupRotation);
3982 }
3983 else
3984 {
3985 m_log.DebugFormat(
3986 "[SCENE]: No spawnpoints defined for telehub {0} for {1} in {2}. Continuing.",
3987 RegionInfo.RegionSettings.TelehubObject, acd.Name, Name);
3988 }
3989 }
3990 else
3991 {
3992 m_log.DebugFormat(
3993 "[SCENE]: No telehub {0} found to direct {1} in {2}. Continuing.",
3994 RegionInfo.RegionSettings.TelehubObject, acd.Name, Name);
3995 }
3996
3997 // Final permissions check; this time we don't allow changing the position
3998 if (!IsPositionAllowed(acd.AgentID, acd.startpos, ref reason))
3999 {
4000 m_authenticateHandler.RemoveCircuit(acd.circuitcode);
4001 return false;
4002 }
4003
4004 return true;
4005 }
4006
4007 // Honor parcel landing type and position.
4008 if (land != null)
4009 {
4010 if (land.LandData.LandingType == (byte)1 && land.LandData.UserLocation != Vector3.Zero)
4011 {
4012 acd.startpos = land.LandData.UserLocation;
4013
4014 // Final permissions check; this time we don't allow changing the position
4015 if (!IsPositionAllowed(acd.AgentID, acd.startpos, ref reason))
4016 {
4017 m_authenticateHandler.RemoveCircuit(acd.circuitcode);
4018 return false;
4019 }
4020 }
4021 }
4022 }
4023
4024 return true;
4025 }
4026
4027 private bool IsPositionAllowed(UUID agentID, Vector3 pos, ref string reason)
4028 {
4029 ILandObject land = LandChannel.GetLandObject(pos);
4030 if (land == null)
4031 return true;
4001 4032
4033 if (land.IsBannedFromLand(agentID) || land.IsRestrictedFromLand(agentID))
4034 {
4035 reason = "You are banned from the region.";
4036 return false;
4037 }
4038
4039 return true;
4040 }
4041
4042 public bool TestLandRestrictions(UUID agentID, out string reason, ref float posX, ref float posY)
4043 {
4044 if (posX < 0)
4045 posX = 0;
4046 else if (posX >= (float)RegionInfo.RegionSizeX)
4047 posX = (float)RegionInfo.RegionSizeX - 0.001f;
4048 if (posY < 0)
4049 posY = 0;
4050 else if (posY >= (float)RegionInfo.RegionSizeY)
4051 posY = (float)RegionInfo.RegionSizeY - 0.001f;
4052
4053 reason = String.Empty;
4054 if (Permissions.IsGod(agentID))
4002 return true; 4055 return true;
4003 }
4004 4056
4005 private bool IsPositionAllowed(UUID agentID, Vector3 pos, ref string reason) 4057 ILandObject land = LandChannel.GetLandObject(posX, posY);
4006 { 4058 if (land == null)
4007 ILandObject land = LandChannel.GetLandObject(pos); 4059 return false;
4008 if (land == null) 4060
4009 return true; 4061 bool banned = land.IsBannedFromLand(agentID);
4062 bool restricted = land.IsRestrictedFromLand(agentID);
4010 4063
4011 if (land.IsBannedFromLand(agentID) || land.IsRestrictedFromLand(agentID)) 4064 if (banned || restricted)
4065 {
4066 ILandObject nearestParcel = GetNearestAllowedParcel(agentID, posX, posY);
4067 if (nearestParcel != null)
4012 { 4068 {
4013 reason = "You are banned from the region."; 4069 //Move agent to nearest allowed
4014 return false; 4070 Vector3 newPosition = GetParcelCenterAtGround(nearestParcel);
4071 posX = newPosition.X;
4072 posY = newPosition.Y;
4015 } 4073 }
4074 else
4075 {
4076 if (banned)
4077 {
4078 reason = "Cannot regioncross into banned parcel.";
4079 }
4080 else
4081 {
4082 reason = String.Format("Denied access to private region {0}: You are not on the access list for that region.",
4083 RegionInfo.RegionName);
4084 }
4085 return false;
4086 }
4087 }
4088 reason = "";
4089 return true;
4090 }
4091
4092 /// <summary>
4093 /// Verifies that the user has a presence on the Grid
4094 /// </summary>
4095 /// <param name="agent">Circuit Data of the Agent we're verifying</param>
4096 /// <param name="reason">Outputs the reason for the false response on this string</param>
4097 /// <returns>True if the user has a session on the grid. False if it does not. False will
4098 /// also return a reason.</returns>
4099 public virtual bool VerifyUserPresence(AgentCircuitData agent, out string reason)
4100 {
4101 reason = String.Empty;
4102
4103 IPresenceService presence = RequestModuleInterface<IPresenceService>();
4104 if (presence == null)
4105 {
4106 reason = String.Format("Failed to verify user presence in the grid for {0} {1} in region {2}. Presence service does not exist.", agent.firstname, agent.lastname, RegionInfo.RegionName);
4107 return false;
4108 }
4016 4109
4017 return true; 4110 OpenSim.Services.Interfaces.PresenceInfo pinfo = presence.GetAgent(agent.SessionID);
4018 }
4019
4020 public bool TestLandRestrictions(UUID agentID, out string reason, ref float posX, ref float posY)
4021 {
4022 if (posX < 0)
4023 posX = 0;
4024 else if (posX >= (float)RegionInfo.RegionSizeX)
4025 posX = (float)RegionInfo.RegionSizeX - 0.001f;
4026 if (posY < 0)
4027 posY = 0;
4028 else if (posY >= (float)RegionInfo.RegionSizeY)
4029 posY = (float)RegionInfo.RegionSizeY - 0.001f;
4030 4111
4031 reason = String.Empty; 4112 if (pinfo == null)
4032 if (Permissions.IsGod(agentID)) 4113 {
4033 return true; 4114 reason = String.Format("Failed to verify user presence in the grid for {0} {1}, access denied to region {2}.", agent.firstname, agent.lastname, RegionInfo.RegionName);
4115 return false;
4116 }
4117
4118 return true;
4119 }
4120
4121 /// <summary>
4122 /// Verify if the user can connect to this region. Checks the banlist and ensures that the region is set for public access
4123 /// </summary>
4124 /// <param name="agent">The circuit data for the agent</param>
4125 /// <param name="reason">outputs the reason to this string</param>
4126 /// <returns>True if the region accepts this agent. False if it does not. False will
4127 /// also return a reason.</returns>
4128 protected virtual bool AuthorizeUser(AgentCircuitData agent, bool bypassAccessControl, out string reason)
4129 {
4130 reason = String.Empty;
4131
4132 if (!m_strictAccessControl) return true;
4133 if (Permissions.IsGod(agent.AgentID)) return true;
4134
4135 if (AuthorizationService != null)
4136 {
4137 if (!AuthorizationService.IsAuthorizedForRegion(
4138 agent.AgentID.ToString(), agent.firstname, agent.lastname, RegionInfo.RegionID.ToString(), out reason))
4139 {
4140 m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because: {4}",
4141 agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName, reason);
4142
4143 return false;
4144 }
4145 }
4146
4147 // We only test the things below when we want to cut off
4148 // child agents from being present in the scene for which their root
4149 // agent isn't allowed. Otherwise, we allow child agents. The test for
4150 // the root is done elsewhere (QueryAccess)
4151 if (!bypassAccessControl)
4152 {
4153 if (RegionInfo.EstateSettings != null)
4154 {
4155 if (RegionInfo.EstateSettings.IsBanned(agent.AgentID))
4156 {
4157 m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user is on the banlist",
4158 agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName);
4159 reason = String.Format("Denied access to region {0}: You have been banned from that region.",
4160 RegionInfo.RegionName);
4161 return false;
4162 }
4163 }
4164 else
4165 {
4166 m_log.ErrorFormat("[CONNECTION BEGIN]: Estate Settings is null!");
4167 }
4034 4168
4035 ILandObject land = LandChannel.GetLandObject(posX, posY); 4169 List<UUID> agentGroups = new List<UUID>();
4036 if (land == null)
4037 return false;
4038 4170
4039 bool banned = land.IsBannedFromLand(agentID); 4171 if (m_groupsModule != null)
4040 bool restricted = land.IsRestrictedFromLand(agentID);
4041
4042 if (banned || restricted)
4043 { 4172 {
4044 ILandObject nearestParcel = GetNearestAllowedParcel(agentID, posX, posY); 4173 GroupMembershipData[] GroupMembership = m_groupsModule.GetMembershipData(agent.AgentID);
4045 if (nearestParcel != null)
4046 {
4047 //Move agent to nearest allowed
4048 Vector3 newPosition = GetParcelCenterAtGround(nearestParcel);
4049 posX = newPosition.X;
4050 posY = newPosition.Y;
4051 }
4052 else
4053 {
4054 if (banned)
4055 {
4056 reason = "Cannot regioncross into banned parcel.";
4057 }
4058 else
4059 {
4060 reason = String.Format("Denied access to private region {0}: You are not on the access list for that region.",
4061 RegionInfo.RegionName);
4062 }
4063 return false;
4064 }
4065 }
4066 reason = "";
4067 return true;
4068 }
4069
4070 /// <summary>
4071 /// Verifies that the user has a presence on the Grid
4072 /// </summary>
4073 /// <param name="agent">Circuit Data of the Agent we're verifying</param>
4074 /// <param name="reason">Outputs the reason for the false response on this string</param>
4075 /// <returns>True if the user has a session on the grid. False if it does not. False will
4076 /// also return a reason.</returns>
4077 public virtual bool VerifyUserPresence(AgentCircuitData agent, out string reason)
4078 {
4079 reason = String.Empty;
4080 4174
4081 IPresenceService presence = RequestModuleInterface<IPresenceService>(); 4175 if (GroupMembership != null)
4082 if (presence == null) 4176 {
4083 { 4177 for (int i = 0; i < GroupMembership.Length; i++)
4084 reason = String.Format("Failed to verify user presence in the grid for {0} {1} in region {2}. Presence service does not exist.", agent.firstname, agent.lastname, RegionInfo.RegionName); 4178 agentGroups.Add(GroupMembership[i].GroupID);
4085 return false; 4179 }
4180 else
4181 {
4182 m_log.ErrorFormat("[CONNECTION BEGIN]: GroupMembership is null!");
4183 }
4086 } 4184 }
4087 4185
4088 OpenSim.Services.Interfaces.PresenceInfo pinfo = presence.GetAgent(agent.SessionID); 4186 bool groupAccess = false;
4187 UUID[] estateGroups = RegionInfo.EstateSettings.EstateGroups;
4089 4188
4090 if (pinfo == null) 4189 if (estateGroups != null)
4091 { 4190 {
4092 reason = String.Format("Failed to verify user presence in the grid for {0} {1}, access denied to region {2}.", agent.firstname, agent.lastname, RegionInfo.RegionName); 4191 foreach (UUID group in estateGroups)
4093 return false; 4192 {
4193 if (agentGroups.Contains(group))
4194 {
4195 groupAccess = true;
4196 break;
4197 }
4198 }
4094 } 4199 }
4200 else
4201 {
4202 m_log.ErrorFormat("[CONNECTION BEGIN]: EstateGroups is null!");
4203 }
4204
4205 if (!RegionInfo.EstateSettings.PublicAccess &&
4206 !RegionInfo.EstateSettings.HasAccess(agent.AgentID) &&
4207 !groupAccess)
4208 {
4209 m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user does not have access to the estate",
4210 agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName);
4211 reason = String.Format("Denied access to private region {0}: You are not on the access list for that region.",
4212 RegionInfo.RegionName);
4213 return false;
4214 }
4215 }
4216
4217 // TODO: estate/region settings are not properly hooked up
4218 // to ILandObject.isRestrictedFromLand()
4219 // if (null != LandChannel)
4220 // {
4221 // // region seems to have local Id of 1
4222 // ILandObject land = LandChannel.GetLandObject(1);
4223 // if (null != land)
4224 // {
4225 // if (land.isBannedFromLand(agent.AgentID))
4226 // {
4227 // m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user has been banned from land",
4228 // agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName);
4229 // reason = String.Format("Denied access to private region {0}: You are banned from that region.",
4230 // RegionInfo.RegionName);
4231 // return false;
4232 // }
4233
4234 // if (land.isRestrictedFromLand(agent.AgentID))
4235 // {
4236 // m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user does not have access to the region",
4237 // agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName);
4238 // reason = String.Format("Denied access to private region {0}: You are not on the access list for that region.",
4239 // RegionInfo.RegionName);
4240 // return false;
4241 // }
4242 // }
4243 // }
4244
4245 return true;
4246 }
4247
4248 /// <summary>
4249 /// Update an AgentCircuitData object with new information
4250 /// </summary>
4251 /// <param name="data">Information to update the AgentCircuitData with</param>
4252 public void UpdateCircuitData(AgentCircuitData data)
4253 {
4254 m_authenticateHandler.UpdateAgentData(data);
4255 }
4256
4257 /// <summary>
4258 /// Change the Circuit Code for the user's Circuit Data
4259 /// </summary>
4260 /// <param name="oldcc">The old Circuit Code. Must match a previous circuit code</param>
4261 /// <param name="newcc">The new Circuit Code. Must not be an already existing circuit code</param>
4262 /// <returns>True if we successfully changed it. False if we did not</returns>
4263 public bool ChangeCircuitCode(uint oldcc, uint newcc)
4264 {
4265 return m_authenticateHandler.TryChangeCiruitCode(oldcc, newcc);
4266 }
4267
4268 // /// <summary>
4269 // /// The Grid has requested that we log-off a user. Log them off.
4270 // /// </summary>
4271 // /// <param name="AvatarID">Unique ID of the avatar to log-off</param>
4272 // /// <param name="RegionSecret">SecureSessionID of the user, or the RegionSecret text when logging on to the grid</param>
4273 // /// <param name="message">message to display to the user. Reason for being logged off</param>
4274 // public void HandleLogOffUserFromGrid(UUID AvatarID, UUID RegionSecret, string message)
4275 // {
4276 // ScenePresence loggingOffUser = GetScenePresence(AvatarID);
4277 // if (loggingOffUser != null)
4278 // {
4279 // UUID localRegionSecret = UUID.Zero;
4280 // bool parsedsecret = UUID.TryParse(RegionInfo.regionSecret, out localRegionSecret);
4281 //
4282 // // Region Secret is used here in case a new sessionid overwrites an old one on the user server.
4283 // // Will update the user server in a few revisions to use it.
4284 //
4285 // if (RegionSecret == loggingOffUser.ControllingClient.SecureSessionId || (parsedsecret && RegionSecret == localRegionSecret))
4286 // {
4287 // m_sceneGridService.SendCloseChildAgentConnections(loggingOffUser.UUID, loggingOffUser.KnownRegionHandles);
4288 // loggingOffUser.ControllingClient.Kick(message);
4289 // // Give them a second to receive the message!
4290 // Thread.Sleep(1000);
4291 // loggingOffUser.ControllingClient.Close();
4292 // }
4293 // else
4294 // {
4295 // m_log.Info("[USERLOGOFF]: System sending the LogOff user message failed to sucessfully authenticate");
4296 // }
4297 // }
4298 // else
4299 // {
4300 // m_log.InfoFormat("[USERLOGOFF]: Got a logoff request for {0} but the user isn't here. The user might already have been logged out", AvatarID.ToString());
4301 // }
4302 // }
4303
4304 // /// <summary>
4305 // /// Triggered when an agent crosses into this sim. Also happens on initial login.
4306 // /// </summary>
4307 // /// <param name="agentID"></param>
4308 // /// <param name="position"></param>
4309 // /// <param name="isFlying"></param>
4310 // public virtual void AgentCrossing(UUID agentID, Vector3 position, bool isFlying)
4311 // {
4312 // ScenePresence presence = GetScenePresence(agentID);
4313 // if (presence != null)
4314 // {
4315 // try
4316 // {
4317 // presence.MakeRootAgent(position, isFlying);
4318 // }
4319 // catch (Exception e)
4320 // {
4321 // m_log.ErrorFormat("[SCENE]: Unable to do agent crossing, exception {0}{1}", e.Message, e.StackTrace);
4322 // }
4323 // }
4324 // else
4325 // {
4326 // m_log.ErrorFormat(
4327 // "[SCENE]: Could not find presence for agent {0} crossing into scene {1}",
4328 // agentID, RegionInfo.RegionName);
4329 // }
4330 // }
4331
4332 /// <summary>
4333 /// We've got an update about an agent that sees into this region,
4334 /// send it to ScenePresence for processing It's the full data.
4335 /// </summary>
4336 /// <param name="cAgentData">Agent that contains all of the relevant things about an agent.
4337 /// Appearance, animations, position, etc.</param>
4338 /// <returns>true if we handled it.</returns>
4339 public virtual bool IncomingUpdateChildAgent(AgentData cAgentData)
4340 {
4341 m_log.DebugFormat(
4342 "[SCENE]: Incoming child agent update for {0} in {1}", cAgentData.AgentID, RegionInfo.RegionName);
4343
4344 // TODO: This check should probably be in QueryAccess().
4345 ILandObject nearestParcel = GetNearestAllowedParcel(cAgentData.AgentID, RegionInfo.RegionSizeX / 2, RegionInfo.RegionSizeY / 2);
4346 if (nearestParcel == null)
4347 {
4348 m_log.InfoFormat(
4349 "[SCENE]: Denying root agent entry to {0} in {1}: no allowed parcel",
4350 cAgentData.AgentID, RegionInfo.RegionName);
4095 4351
4096 return true; 4352 return false;
4097 } 4353 }
4098
4099 /// <summary>
4100 /// Verify if the user can connect to this region. Checks the banlist and ensures that the region is set for public access
4101 /// </summary>
4102 /// <param name="agent">The circuit data for the agent</param>
4103 /// <param name="reason">outputs the reason to this string</param>
4104 /// <returns>True if the region accepts this agent. False if it does not. False will
4105 /// also return a reason.</returns>
4106 protected virtual bool AuthorizeUser(AgentCircuitData agent, bool bypassAccessControl, out string reason)
4107 {
4108 reason = String.Empty;
4109
4110 if (!m_strictAccessControl) return true;
4111 if (Permissions.IsGod(agent.AgentID)) return true;
4112
4113 if (AuthorizationService != null)
4114 {
4115 if (!AuthorizationService.IsAuthorizedForRegion(
4116 agent.AgentID.ToString(), agent.firstname, agent.lastname, RegionInfo.RegionID.ToString(), out reason))
4117 {
4118 m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because: {4}",
4119 agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName, reason);
4120
4121 return false;
4122 }
4123 }
4124
4125 // We only test the things below when we want to cut off
4126 // child agents from being present in the scene for which their root
4127 // agent isn't allowed. Otherwise, we allow child agents. The test for
4128 // the root is done elsewhere (QueryAccess)
4129 if (!bypassAccessControl)
4130 {
4131 if (RegionInfo.EstateSettings != null)
4132 {
4133 if (RegionInfo.EstateSettings.IsBanned(agent.AgentID))
4134 {
4135 m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user is on the banlist",
4136 agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName);
4137 reason = String.Format("Denied access to region {0}: You have been banned from that region.",
4138 RegionInfo.RegionName);
4139 return false;
4140 }
4141 }
4142 else
4143 {
4144 m_log.ErrorFormat("[CONNECTION BEGIN]: Estate Settings is null!");
4145 }
4146
4147 List<UUID> agentGroups = new List<UUID>();
4148
4149 if (m_groupsModule != null)
4150 {
4151 GroupMembershipData[] GroupMembership = m_groupsModule.GetMembershipData(agent.AgentID);
4152
4153 if (GroupMembership != null)
4154 {
4155 for (int i = 0; i < GroupMembership.Length; i++)
4156 agentGroups.Add(GroupMembership[i].GroupID);
4157 }
4158 else
4159 {
4160 m_log.ErrorFormat("[CONNECTION BEGIN]: GroupMembership is null!");
4161 }
4162 }
4163
4164 bool groupAccess = false;
4165 UUID[] estateGroups = RegionInfo.EstateSettings.EstateGroups;
4166
4167 if (estateGroups != null)
4168 {
4169 foreach (UUID group in estateGroups)
4170 {
4171 if (agentGroups.Contains(group))
4172 {
4173 groupAccess = true;
4174 break;
4175 }
4176 }
4177 }
4178 else
4179 {
4180 m_log.ErrorFormat("[CONNECTION BEGIN]: EstateGroups is null!");
4181 }
4182
4183 if (!RegionInfo.EstateSettings.PublicAccess &&
4184 !RegionInfo.EstateSettings.HasAccess(agent.AgentID) &&
4185 !groupAccess)
4186 {
4187 m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user does not have access to the estate",
4188 agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName);
4189 reason = String.Format("Denied access to private region {0}: You are not on the access list for that region.",
4190 RegionInfo.RegionName);
4191 return false;
4192 }
4193 }
4194
4195 // TODO: estate/region settings are not properly hooked up
4196 // to ILandObject.isRestrictedFromLand()
4197 // if (null != LandChannel)
4198 // {
4199 // // region seems to have local Id of 1
4200 // ILandObject land = LandChannel.GetLandObject(1);
4201 // if (null != land)
4202 // {
4203 // if (land.isBannedFromLand(agent.AgentID))
4204 // {
4205 // m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user has been banned from land",
4206 // agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName);
4207 // reason = String.Format("Denied access to private region {0}: You are banned from that region.",
4208 // RegionInfo.RegionName);
4209 // return false;
4210 // }
4211
4212 // if (land.isRestrictedFromLand(agent.AgentID))
4213 // {
4214 // m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user does not have access to the region",
4215 // agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName);
4216 // reason = String.Format("Denied access to private region {0}: You are not on the access list for that region.",
4217 // RegionInfo.RegionName);
4218 // return false;
4219 // }
4220 // }
4221 // }
4222 4354
4223 return true; 4355 // We have to wait until the viewer contacts this region
4224 } 4356 // after receiving the EnableSimulator HTTP Event Queue message (for the v1 teleport protocol)
4225 4357 // or TeleportFinish (for the v2 teleport protocol). This triggers the viewer to send
4226 /// <summary> 4358 // a UseCircuitCode packet which in turn calls AddNewAgent which finally creates the ScenePresence.
4227 /// Update an AgentCircuitData object with new information 4359 ScenePresence sp = WaitGetScenePresence(cAgentData.AgentID);
4228 /// </summary>
4229 /// <param name="data">Information to update the AgentCircuitData with</param>
4230 public void UpdateCircuitData(AgentCircuitData data)
4231 {
4232 m_authenticateHandler.UpdateAgentData(data);
4233 }
4234
4235 /// <summary>
4236 /// Change the Circuit Code for the user's Circuit Data
4237 /// </summary>
4238 /// <param name="oldcc">The old Circuit Code. Must match a previous circuit code</param>
4239 /// <param name="newcc">The new Circuit Code. Must not be an already existing circuit code</param>
4240 /// <returns>True if we successfully changed it. False if we did not</returns>
4241 public bool ChangeCircuitCode(uint oldcc, uint newcc)
4242 {
4243 return m_authenticateHandler.TryChangeCiruitCode(oldcc, newcc);
4244 }
4245
4246// /// <summary>
4247// /// The Grid has requested that we log-off a user. Log them off.
4248// /// </summary>
4249// /// <param name="AvatarID">Unique ID of the avatar to log-off</param>
4250// /// <param name="RegionSecret">SecureSessionID of the user, or the RegionSecret text when logging on to the grid</param>
4251// /// <param name="message">message to display to the user. Reason for being logged off</param>
4252// public void HandleLogOffUserFromGrid(UUID AvatarID, UUID RegionSecret, string message)
4253// {
4254// ScenePresence loggingOffUser = GetScenePresence(AvatarID);
4255// if (loggingOffUser != null)
4256// {
4257// UUID localRegionSecret = UUID.Zero;
4258// bool parsedsecret = UUID.TryParse(RegionInfo.regionSecret, out localRegionSecret);
4259//
4260// // Region Secret is used here in case a new sessionid overwrites an old one on the user server.
4261// // Will update the user server in a few revisions to use it.
4262//
4263// if (RegionSecret == loggingOffUser.ControllingClient.SecureSessionId || (parsedsecret && RegionSecret == localRegionSecret))
4264// {
4265// m_sceneGridService.SendCloseChildAgentConnections(loggingOffUser.UUID, loggingOffUser.KnownRegionHandles);
4266// loggingOffUser.ControllingClient.Kick(message);
4267// // Give them a second to receive the message!
4268// Thread.Sleep(1000);
4269// loggingOffUser.ControllingClient.Close();
4270// }
4271// else
4272// {
4273// m_log.Info("[USERLOGOFF]: System sending the LogOff user message failed to sucessfully authenticate");
4274// }
4275// }
4276// else
4277// {
4278// m_log.InfoFormat("[USERLOGOFF]: Got a logoff request for {0} but the user isn't here. The user might already have been logged out", AvatarID.ToString());
4279// }
4280// }
4281
4282// /// <summary>
4283// /// Triggered when an agent crosses into this sim. Also happens on initial login.
4284// /// </summary>
4285// /// <param name="agentID"></param>
4286// /// <param name="position"></param>
4287// /// <param name="isFlying"></param>
4288// public virtual void AgentCrossing(UUID agentID, Vector3 position, bool isFlying)
4289// {
4290// ScenePresence presence = GetScenePresence(agentID);
4291// if (presence != null)
4292// {
4293// try
4294// {
4295// presence.MakeRootAgent(position, isFlying);
4296// }
4297// catch (Exception e)
4298// {
4299// m_log.ErrorFormat("[SCENE]: Unable to do agent crossing, exception {0}{1}", e.Message, e.StackTrace);
4300// }
4301// }
4302// else
4303// {
4304// m_log.ErrorFormat(
4305// "[SCENE]: Could not find presence for agent {0} crossing into scene {1}",
4306// agentID, RegionInfo.RegionName);
4307// }
4308// }
4309
4310 /// <summary>
4311 /// We've got an update about an agent that sees into this region,
4312 /// send it to ScenePresence for processing It's the full data.
4313 /// </summary>
4314 /// <param name="cAgentData">Agent that contains all of the relevant things about an agent.
4315 /// Appearance, animations, position, etc.</param>
4316 /// <returns>true if we handled it.</returns>
4317 public virtual bool IncomingUpdateChildAgent(AgentData cAgentData)
4318 {
4319 m_log.DebugFormat(
4320 "[SCENE]: Incoming child agent update for {0} in {1}", cAgentData.AgentID, RegionInfo.RegionName);
4321 4360
4322 // TODO: This check should probably be in QueryAccess(). 4361 if (sp != null)
4323 ILandObject nearestParcel = GetNearestAllowedParcel(cAgentData.AgentID, RegionInfo.RegionSizeX / 2, RegionInfo.RegionSizeY / 2); 4362 {
4324 if (nearestParcel == null) 4363 if (cAgentData.SessionID != sp.ControllingClient.SessionId)
4325 { 4364 {
4326 m_log.InfoFormat( 4365 m_log.WarnFormat(
4327 "[SCENE]: Denying root agent entry to {0} in {1}: no allowed parcel", 4366 "[SCENE]: Attempt to update agent {0} with invalid session id {1} (possibly from simulator in older version; tell them to update).",
4328 cAgentData.AgentID, RegionInfo.RegionName); 4367 sp.UUID, cAgentData.SessionID);
4329 4368
4330 return false; 4369 Console.WriteLine(String.Format("[SCENE]: Attempt to update agent {0} ({1}) with invalid session id {2}",
4370 sp.UUID, sp.ControllingClient.SessionId, cAgentData.SessionID));
4331 } 4371 }
4332 4372
4333 // We have to wait until the viewer contacts this region 4373 sp.UpdateChildAgent(cAgentData);
4334 // after receiving the EnableSimulator HTTP Event Queue message (for the v1 teleport protocol)
4335 // or TeleportFinish (for the v2 teleport protocol). This triggers the viewer to send
4336 // a UseCircuitCode packet which in turn calls AddNewAgent which finally creates the ScenePresence.
4337 ScenePresence sp = WaitGetScenePresence(cAgentData.AgentID);
4338 4374
4339 if (sp != null) 4375 int ntimes = 20;
4376 if (cAgentData.SenderWantsToWaitForRoot)
4340 { 4377 {
4341 if (cAgentData.SessionID != sp.ControllingClient.SessionId) 4378 while (sp.IsChildAgent && ntimes-- > 0)
4342 { 4379 Thread.Sleep(1000);
4343 m_log.WarnFormat(
4344 "[SCENE]: Attempt to update agent {0} with invalid session id {1} (possibly from simulator in older version; tell them to update).",
4345 sp.UUID, cAgentData.SessionID);
4346
4347 Console.WriteLine(String.Format("[SCENE]: Attempt to update agent {0} ({1}) with invalid session id {2}",
4348 sp.UUID, sp.ControllingClient.SessionId, cAgentData.SessionID));
4349 }
4350
4351 sp.UpdateChildAgent(cAgentData);
4352
4353 int ntimes = 20;
4354 if (cAgentData.SenderWantsToWaitForRoot)
4355 {
4356 while (sp.IsChildAgent && ntimes-- > 0)
4357 Thread.Sleep(1000);
4358
4359 if (sp.IsChildAgent)
4360 m_log.WarnFormat(
4361 "[SCENE]: Found presence {0} {1} unexpectedly still child in {2}",
4362 sp.Name, sp.UUID, Name);
4363 else
4364 m_log.InfoFormat(
4365 "[SCENE]: Found presence {0} {1} as root in {2} after {3} waits",
4366 sp.Name, sp.UUID, Name, 20 - ntimes);
4367
4368 if (sp.IsChildAgent)
4369 return false;
4370 }
4371 4380
4372 return true; 4381 if (sp.IsChildAgent)
4373 } 4382 m_log.WarnFormat(
4383 "[SCENE]: Found presence {0} {1} unexpectedly still child in {2}",
4384 sp.Name, sp.UUID, Name);
4385 else
4386 m_log.InfoFormat(
4387 "[SCENE]: Found presence {0} {1} as root in {2} after {3} waits",
4388 sp.Name, sp.UUID, Name, 20 - ntimes);
4374 4389
4375 return false; 4390 if (sp.IsChildAgent)
4376 } 4391 return false;
4377
4378 /// <summary>
4379 /// We've got an update about an agent that sees into this region,
4380 /// send it to ScenePresence for processing It's only positional data
4381 /// </summary>
4382 /// <param name="cAgentData">AgentPosition that contains agent positional data so we can know what to send</param>
4383 /// <returns>true if we handled it.</returns>
4384 public virtual bool IncomingUpdateChildAgent(AgentPosition cAgentData)
4385 {
4386// m_log.DebugFormat(
4387// "[SCENE PRESENCE]: IncomingChildAgentDataUpdate POSITION for {0} in {1}, position {2}",
4388// cAgentData.AgentID, Name, cAgentData.Position);
4389
4390 ScenePresence childAgentUpdate = GetScenePresence(cAgentData.AgentID);
4391 if (childAgentUpdate != null)
4392 {
4393// if (childAgentUpdate.ControllingClient.SessionId != cAgentData.SessionID)
4394// // Only warn for now
4395// m_log.WarnFormat("[SCENE]: Attempt at updating position of agent {0} with invalid session id {1}. Neighbor running older version?",
4396// childAgentUpdate.UUID, cAgentData.SessionID);
4397
4398 // I can't imagine *yet* why we would get an update if the agent is a root agent..
4399 // however to avoid a race condition crossing borders..
4400 if (childAgentUpdate.IsChildAgent)
4401 {
4402 uint rRegionX = (uint)(cAgentData.RegionHandle >> 40);
4403 uint rRegionY = (((uint)(cAgentData.RegionHandle)) >> 8);
4404 uint tRegionX = RegionInfo.RegionLocX;
4405 uint tRegionY = RegionInfo.RegionLocY;
4406 //Send Data to ScenePresence
4407 childAgentUpdate.UpdateChildAgent(cAgentData, tRegionX, tRegionY, rRegionX, rRegionY);
4408 // Not Implemented:
4409 //TODO: Do we need to pass the message on to one of our neighbors?
4410 }
4411
4412 return true;
4413 } 4392 }
4414 4393
4415 return false; 4394 return true;
4416 } 4395 }
4417 4396
4418 /// <summary> 4397 return false;
4419 /// Poll until the requested ScenePresence appears or we timeout. 4398 }
4420 /// </summary> 4399
4421 /// <returns>The scene presence is found, else null.</returns> 4400 /// <summary>
4422 /// <param name='agentID'></param> 4401 /// We've got an update about an agent that sees into this region,
4423 protected virtual ScenePresence WaitGetScenePresence(UUID agentID) 4402 /// send it to ScenePresence for processing It's only positional data
4424 { 4403 /// </summary>
4425 int ntimes = 20; 4404 /// <param name="cAgentData">AgentPosition that contains agent positional data so we can know what to send</param>
4426 ScenePresence sp = null; 4405 /// <returns>true if we handled it.</returns>
4427 while ((sp = GetScenePresence(agentID)) == null && (ntimes-- > 0)) 4406 public virtual bool IncomingUpdateChildAgent(AgentPosition cAgentData)
4428 Thread.Sleep(1000); 4407 {
4429 4408 // m_log.DebugFormat(
4430 if (sp == null) 4409 // "[SCENE PRESENCE]: IncomingChildAgentDataUpdate POSITION for {0} in {1}, position {2}",
4431 m_log.WarnFormat( 4410 // cAgentData.AgentID, Name, cAgentData.Position);
4432 "[SCENE PRESENCE]: Did not find presence with id {0} in {1} before timeout", 4411
4433 agentID, RegionInfo.RegionName); 4412 ScenePresence childAgentUpdate = GetScenePresence(cAgentData.AgentID);
4413 if (childAgentUpdate != null)
4414 {
4415 // if (childAgentUpdate.ControllingClient.SessionId != cAgentData.SessionID)
4416 // // Only warn for now
4417 // m_log.WarnFormat("[SCENE]: Attempt at updating position of agent {0} with invalid session id {1}. Neighbor running older version?",
4418 // childAgentUpdate.UUID, cAgentData.SessionID);
4419
4420 // I can't imagine *yet* why we would get an update if the agent is a root agent..
4421 // however to avoid a race condition crossing borders..
4422 if (childAgentUpdate.IsChildAgent)
4423 {
4424 uint rRegionX = (uint)(cAgentData.RegionHandle >> 40);
4425 uint rRegionY = (((uint)(cAgentData.RegionHandle)) >> 8);
4426 uint tRegionX = RegionInfo.RegionLocX;
4427 uint tRegionY = RegionInfo.RegionLocY;
4428 //Send Data to ScenePresence
4429 childAgentUpdate.UpdateChildAgent(cAgentData, tRegionX, tRegionY, rRegionX, rRegionY);
4430 // Not Implemented:
4431 //TODO: Do we need to pass the message on to one of our neighbors?
4432 }
4434 4433
4435 return sp; 4434 return true;
4436 } 4435 }
4436
4437 return false;
4438 }
4439
4440 /// <summary>
4441 /// Poll until the requested ScenePresence appears or we timeout.
4442 /// </summary>
4443 /// <returns>The scene presence is found, else null.</returns>
4444 /// <param name='agentID'></param>
4445 protected virtual ScenePresence WaitGetScenePresence(UUID agentID)
4446 {
4447 int ntimes = 20;
4448 ScenePresence sp = null;
4449 while ((sp = GetScenePresence(agentID)) == null && (ntimes-- > 0))
4450 Thread.Sleep(1000);
4451
4452 if (sp == null)
4453 m_log.WarnFormat(
4454 "[SCENE PRESENCE]: Did not find presence with id {0} in {1} before timeout",
4455 agentID, RegionInfo.RegionName);
4456
4457 return sp;
4458 }
4459
4460 /// <summary>
4461 /// Authenticated close (via network)
4462 /// </summary>
4463 /// <param name="agentID"></param>
4464 /// <param name="force"></param>
4465 /// <param name="auth_token"></param>
4466 /// <returns></returns>
4467 public bool CloseAgent(UUID agentID, bool force, string auth_token)
4468 {
4469 //m_log.DebugFormat("[SCENE]: Processing incoming close agent {0} in region {1} with auth_token {2}", agentID, RegionInfo.RegionName, auth_token);
4470
4471 // Check that the auth_token is valid
4472 AgentCircuitData acd = AuthenticateHandler.GetAgentCircuitData(agentID);
4473
4474 if (acd == null)
4475 {
4476 m_log.DebugFormat(
4477 "[SCENE]: Request to close agent {0} but no such agent in scene {1}. May have been closed previously.",
4478 agentID, Name);
4437 4479
4438 /// <summary> 4480 return false;
4439 /// Authenticated close (via network) 4481 }
4440 /// </summary> 4482
4441 /// <param name="agentID"></param> 4483 if (acd.SessionID.ToString() == auth_token)
4442 /// <param name="force"></param> 4484 {
4443 /// <param name="auth_token"></param> 4485 return CloseAgent(agentID, force);
4444 /// <returns></returns> 4486 }
4445 public bool CloseAgent(UUID agentID, bool force, string auth_token) 4487 else
4446 { 4488 {
4447 //m_log.DebugFormat("[SCENE]: Processing incoming close agent {0} in region {1} with auth_token {2}", agentID, RegionInfo.RegionName, auth_token); 4489 m_log.WarnFormat(
4490 "[SCENE]: Request to close agent {0} with invalid authorization token {1} in {2}",
4491 agentID, auth_token, Name);
4492 }
4493
4494 return false;
4495 }
4496
4497 /// <summary>
4498 /// Tell a single client to prepare to close.
4499 /// </summary>
4500 /// <remarks>
4501 /// This should only be called if we may close the client but there will be some delay in so doing. Meant for
4502 /// internal use - other callers should almost certainly called CloseClient().
4503 /// </remarks>
4504 /// <param name="sp"></param>
4505 /// <returns>true if pre-close state notification was successful. false if the agent
4506 /// was not in a state where it could transition to pre-close.</returns>
4507 public bool IncomingPreCloseClient(ScenePresence sp)
4508 {
4509 lock (m_removeClientLock)
4510 {
4511 // We need to avoid a race condition where in, for example, an A B C D region layout, an avatar may
4512 // teleport from A -> D, but then -> C before A has asked B to close its old child agent. We do not
4513 // want to obey this close since C may have renewed the child agent lease on B.
4514 if (sp.DoNotCloseAfterTeleport)
4515 {
4516 m_log.DebugFormat(
4517 "[SCENE]: Not pre-closing {0} agent {1} in {2} since another simulator has re-established the child connection",
4518 sp.IsChildAgent ? "child" : "root", sp.Name, Name);
4519
4520 // Need to reset the flag so that a subsequent close after another teleport can succeed.
4521 sp.DoNotCloseAfterTeleport = false;
4522
4523 return false;
4524 }
4525
4526 if (sp.LifecycleState != ScenePresenceState.Running)
4527 {
4528 m_log.DebugFormat(
4529 "[SCENE]: Called IncomingPreCloseAgent() for {0} in {1} but presence is already in state {2}",
4530 sp.Name, Name, sp.LifecycleState);
4531
4532 return false;
4533 }
4534
4535 sp.LifecycleState = ScenePresenceState.PreRemove;
4448 4536
4449 // Check that the auth_token is valid 4537 return true;
4450 AgentCircuitData acd = AuthenticateHandler.GetAgentCircuitData(agentID); 4538 }
4539 }
4540
4541 /// <summary>
4542 /// Tell a single agent to disconnect from the region.
4543 /// </summary>
4544 /// <param name="agentID"></param>
4545 /// <param name="force">
4546 /// Force the agent to close even if it might be in the middle of some other operation. You do not want to
4547 /// force unless you are absolutely sure that the agent is dead and a normal close is not working.
4548 /// </param>
4549 public override bool CloseAgent(UUID agentID, bool force)
4550 {
4551 ScenePresence sp;
4552
4553 lock (m_removeClientLock)
4554 {
4555 sp = GetScenePresence(agentID);
4451 4556
4452 if (acd == null) 4557 if (sp == null)
4453 { 4558 {
4454 m_log.DebugFormat( 4559 m_log.DebugFormat(
4455 "[SCENE]: Request to close agent {0} but no such agent in scene {1}. May have been closed previously.", 4560 "[SCENE]: Called CloseClient() with agent ID {0} but no such presence is in {1}",
4456 agentID, Name); 4561 agentID, Name);
4457 4562
4458 return false; 4563 return false;
4459 } 4564 }
4460 4565
4461 if (acd.SessionID.ToString() == auth_token) 4566 if (sp.LifecycleState != ScenePresenceState.Running && sp.LifecycleState != ScenePresenceState.PreRemove)
4567 {
4568 m_log.DebugFormat(
4569 "[SCENE]: Called CloseClient() for {0} in {1} but presence is already in state {2}",
4570 sp.Name, Name, sp.LifecycleState);
4571
4572 return false;
4573 }
4574
4575 // We need to avoid a race condition where in, for example, an A B C D region layout, an avatar may
4576 // teleport from A -> D, but then -> C before A has asked B to close its old child agent. We do not
4577 // want to obey this close since C may have renewed the child agent lease on B.
4578 if (sp.DoNotCloseAfterTeleport)
4579 {
4580 m_log.DebugFormat(
4581 "[SCENE]: Not closing {0} agent {1} in {2} since another simulator has re-established the child connection",
4582 sp.IsChildAgent ? "child" : "root", sp.Name, Name);
4583
4584 // Need to reset the flag so that a subsequent close after another teleport can succeed.
4585 sp.DoNotCloseAfterTeleport = false;
4586
4587 return false;
4588 }
4589
4590 sp.LifecycleState = ScenePresenceState.Removing;
4591 }
4592
4593 sp.ControllingClient.Close(force);
4594
4595 return true;
4596 }
4597
4598 /// <summary>
4599 /// Tries to teleport agent to another region.
4600 /// </summary>
4601 /// <remarks>
4602 /// The region name must exactly match that given.
4603 /// </remarks>
4604 /// <param name="remoteClient"></param>
4605 /// <param name="regionName"></param>
4606 /// <param name="position"></param>
4607 /// <param name="lookAt"></param>
4608 /// <param name="teleportFlags"></param>
4609 public void RequestTeleportLocation(IClientAPI remoteClient, string regionName, Vector3 position,
4610 Vector3 lookat, uint teleportFlags)
4611 {
4612 GridRegion region = GridService.GetRegionByName(RegionInfo.ScopeID, regionName);
4613
4614 if (region == null)
4615 {
4616 // can't find the region: Tell viewer and abort
4617 remoteClient.SendTeleportFailed("The region '" + regionName + "' could not be found.");
4618 return;
4619 }
4620
4621 RequestTeleportLocation(remoteClient, region.RegionHandle, position, lookat, teleportFlags);
4622 }
4623
4624 /// <summary>
4625 /// Tries to teleport agent to other region.
4626 /// </summary>
4627 /// <param name="remoteClient"></param>
4628 /// <param name="regionHandle"></param>
4629 /// <param name="position"></param>
4630 /// <param name="lookAt"></param>
4631 /// <param name="teleportFlags"></param>
4632 public void RequestTeleportLocation(IClientAPI remoteClient, ulong regionHandle, Vector3 position,
4633 Vector3 lookAt, uint teleportFlags)
4634 {
4635 ScenePresence sp = GetScenePresence(remoteClient.AgentId);
4636 if (sp != null)
4637 {
4638 if (EntityTransferModule != null)
4462 { 4639 {
4463 return CloseAgent(agentID, force); 4640 EntityTransferModule.Teleport(sp, regionHandle, position, lookAt, teleportFlags);
4464 } 4641 }
4465 else 4642 else
4466 { 4643 {
4467 m_log.WarnFormat( 4644 m_log.DebugFormat("[SCENE]: Unable to perform teleports: no AgentTransferModule is active");
4468 "[SCENE]: Request to close agent {0} with invalid authorization token {1} in {2}", 4645 sp.ControllingClient.SendTeleportFailed("Unable to perform teleports on this simulator.");
4469 agentID, auth_token, Name); 4646 }
4647 }
4648 }
4649
4650 public bool CrossAgentToNewRegion(ScenePresence agent, bool isFlying)
4651 {
4652 if (EntityTransferModule != null)
4653 {
4654 return EntityTransferModule.Cross(agent, isFlying);
4655 }
4656 else
4657 {
4658 m_log.DebugFormat("[SCENE]: Unable to cross agent to neighbouring region, because there is no AgentTransferModule");
4659 }
4660
4661 return false;
4662 }
4663
4664 public void SendOutChildAgentUpdates(AgentPosition cadu, ScenePresence presence)
4665 {
4666 m_sceneGridService.SendChildAgentDataUpdate(cadu, presence);
4667 }
4668
4669 #endregion
4670
4671 #region Other Methods
4672
4673 protected override IConfigSource GetConfig()
4674 {
4675 return m_config;
4676 }
4677
4678 #endregion
4679
4680 public void HandleObjectPermissionsUpdate(IClientAPI controller, UUID agentID, UUID sessionID, byte field, uint localId, uint mask, byte set)
4681 {
4682 // Check for spoofing.. since this is permissions we're talking about here!
4683 if ((controller.SessionId == sessionID) && (controller.AgentId == agentID))
4684 {
4685 // Tell the object to do permission update
4686 if (localId != 0)
4687 {
4688 SceneObjectGroup chObjectGroup = GetGroupByPrim(localId);
4689 if (chObjectGroup != null)
4690 {
4691 chObjectGroup.UpdatePermissions(agentID, field, localId, mask, set);
4692 }
4693 }
4694 }
4695 }
4696
4697 /// <summary>
4698 /// Causes all clients to get a full object update on all of the objects in the scene.
4699 /// </summary>
4700 public void ForceClientUpdate()
4701 {
4702 EntityBase[] entityList = GetEntities();
4703 foreach (EntityBase ent in entityList)
4704 {
4705 if (ent is SceneObjectGroup)
4706 {
4707 ((SceneObjectGroup)ent).ScheduleGroupForFullUpdate();
4708 }
4709 }
4710 }
4711
4712 /// <summary>
4713 /// This is currently only used for scale (to scale to MegaPrim size)
4714 /// There is a console command that calls this in OpenSimMain
4715 /// </summary>
4716 /// <param name="cmdparams"></param>
4717 public void HandleEditCommand(string[] cmdparams)
4718 {
4719 m_log.DebugFormat("Searching for Primitive: '{0}'", cmdparams[2]);
4720
4721 EntityBase[] entityList = GetEntities();
4722 foreach (EntityBase ent in entityList)
4723 {
4724 if (ent is SceneObjectGroup)
4725 {
4726 SceneObjectPart part = ((SceneObjectGroup)ent).GetPart(((SceneObjectGroup)ent).UUID);
4727 if (part != null)
4728 {
4729 if (part.Name == cmdparams[2])
4730 {
4731 part.Resize(
4732 new Vector3(Convert.ToSingle(cmdparams[3]), Convert.ToSingle(cmdparams[4]),
4733 Convert.ToSingle(cmdparams[5])));
4734
4735 m_log.DebugFormat("Edited scale of Primitive: {0}", part.Name);
4736 }
4737 }
4738 }
4739 }
4740 }
4741
4742 #region Script Handling Methods
4743
4744 /// <summary>
4745 /// Console command handler to send script command to script engine.
4746 /// </summary>
4747 /// <param name="args"></param>
4748 public void SendCommandToPlugins(string[] args)
4749 {
4750 m_eventManager.TriggerOnPluginConsole(args);
4751 }
4752
4753 public LandData GetLandData(float x, float y)
4754 {
4755 return LandChannel.GetLandObject(x, y).LandData;
4756 }
4757
4758 /// <summary>
4759 /// Get LandData by position.
4760 /// </summary>
4761 /// <param name="pos"></param>
4762 /// <returns></returns>
4763 public LandData GetLandData(Vector3 pos)
4764 {
4765 return GetLandData(pos.X, pos.Y);
4766 }
4767
4768 public LandData GetLandData(uint x, uint y)
4769 {
4770 m_log.DebugFormat("[SCENE]: returning land for {0},{1}", x, y);
4771 return LandChannel.GetLandObject((int)x, (int)y).LandData;
4772 }
4773
4774 #endregion
4775
4776 #region Script Engine
4777
4778 private bool ScriptDanger(SceneObjectPart part, Vector3 pos)
4779 {
4780 ILandObject parcel = LandChannel.GetLandObject(pos.X, pos.Y);
4781 if (part != null)
4782 {
4783 if (parcel != null)
4784 {
4785 if ((parcel.LandData.Flags & (uint)ParcelFlags.AllowOtherScripts) != 0)
4786 {
4787 return true;
4788 }
4789 else if ((part.OwnerID == parcel.LandData.OwnerID) || Permissions.IsGod(part.OwnerID))
4790 {
4791 return true;
4792 }
4793 else if (((parcel.LandData.Flags & (uint)ParcelFlags.AllowGroupScripts) != 0)
4794 && (parcel.LandData.GroupID != UUID.Zero) && (parcel.LandData.GroupID == part.GroupID))
4795 {
4796 return true;
4797 }
4798 else
4799 {
4800 return false;
4801 }
4470 } 4802 }
4803 else
4804 {
4471 4805
4806 if (pos.X > 0f && pos.X < RegionInfo.RegionSizeX && pos.Y > 0f && pos.Y < RegionInfo.RegionSizeY)
4807 {
4808 // The only time parcel != null when an object is inside a region is when
4809 // there is nothing behind the landchannel. IE, no land plugin loaded.
4810 return true;
4811 }
4812 else
4813 {
4814 // The object is outside of this region. Stop piping events to it.
4815 return false;
4816 }
4817 }
4818 }
4819 else
4820 {
4821 return false;
4822 }
4823 }
4824
4825 public bool ScriptDanger(uint localID, Vector3 pos)
4826 {
4827 SceneObjectPart part = GetSceneObjectPart(localID);
4828 if (part != null)
4829 {
4830 return ScriptDanger(part, pos);
4831 }
4832 else
4833 {
4834 return false;
4835 }
4836 }
4837
4838 public bool PipeEventsForScript(uint localID)
4839 {
4840 SceneObjectPart part = GetSceneObjectPart(localID);
4841
4842 if (part != null)
4843 {
4844 SceneObjectPart parent = part.ParentGroup.RootPart;
4845 return ScriptDanger(parent, parent.GetWorldPosition());
4846 }
4847 else
4848 {
4472 return false; 4849 return false;
4473 } 4850 }
4474 4851 }
4475 /// <summary> 4852
4476 /// Tell a single client to prepare to close. 4853 #endregion
4477 /// </summary> 4854
4478 /// <remarks> 4855 #region SceneGraph wrapper methods
4479 /// This should only be called if we may close the client but there will be some delay in so doing. Meant for 4856
4480 /// internal use - other callers should almost certainly called CloseClient(). 4857 /// <summary>
4481 /// </remarks> 4858 ///
4482 /// <param name="sp"></param> 4859 /// </summary>
4483 /// <returns>true if pre-close state notification was successful. false if the agent 4860 /// <param name="localID"></param>
4484 /// was not in a state where it could transition to pre-close.</returns> 4861 /// <returns></returns>
4485 public bool IncomingPreCloseClient(ScenePresence sp) 4862 public UUID ConvertLocalIDToFullID(uint localID)
4486 { 4863 {
4487 lock (m_removeClientLock) 4864 return m_sceneGraph.ConvertLocalIDToFullID(localID);
4488 { 4865 }
4489 // We need to avoid a race condition where in, for example, an A B C D region layout, an avatar may 4866
4490 // teleport from A -> D, but then -> C before A has asked B to close its old child agent. We do not 4867 public void SwapRootAgentCount(bool rootChildChildRootTF)
4491 // want to obey this close since C may have renewed the child agent lease on B. 4868 {
4492 if (sp.DoNotCloseAfterTeleport) 4869 m_sceneGraph.SwapRootChildAgent(rootChildChildRootTF);
4493 { 4870 }
4494 m_log.DebugFormat( 4871
4495 "[SCENE]: Not pre-closing {0} agent {1} in {2} since another simulator has re-established the child connection", 4872 public void AddPhysicalPrim(int num)
4496 sp.IsChildAgent ? "child" : "root", sp.Name, Name); 4873 {
4497 4874 m_sceneGraph.AddPhysicalPrim(num);
4498 // Need to reset the flag so that a subsequent close after another teleport can succeed. 4875 }
4499 sp.DoNotCloseAfterTeleport = false; 4876
4500 4877 public void RemovePhysicalPrim(int num)
4501 return false; 4878 {
4502 } 4879 m_sceneGraph.RemovePhysicalPrim(num);
4503 4880 }
4504 if (sp.LifecycleState != ScenePresenceState.Running) 4881
4505 { 4882 public int GetRootAgentCount()
4506 m_log.DebugFormat( 4883 {
4507 "[SCENE]: Called IncomingPreCloseAgent() for {0} in {1} but presence is already in state {2}", 4884 return m_sceneGraph.GetRootAgentCount();
4508 sp.Name, Name, sp.LifecycleState); 4885 }
4509 4886
4510 return false; 4887 public int GetChildAgentCount()
4511 } 4888 {
4512 4889 return m_sceneGraph.GetChildAgentCount();
4513 sp.LifecycleState = ScenePresenceState.PreRemove; 4890 }
4514 4891
4515 return true; 4892 /// <summary>
4516 } 4893 /// Request a scene presence by UUID. Fast, indexed lookup.
4517 } 4894 /// </summary>
4518 4895 /// <param name="agentID"></param>
4519 /// <summary> 4896 /// <returns>null if the presence was not found</returns>
4520 /// Tell a single agent to disconnect from the region. 4897 public ScenePresence GetScenePresence(UUID agentID)
4521 /// </summary> 4898 {
4522 /// <param name="agentID"></param> 4899 return m_sceneGraph.GetScenePresence(agentID);
4523 /// <param name="force"> 4900 }
4524 /// Force the agent to close even if it might be in the middle of some other operation. You do not want to 4901
4525 /// force unless you are absolutely sure that the agent is dead and a normal close is not working. 4902 /// <summary>
4526 /// </param> 4903 /// Request the scene presence by name.
4527 public override bool CloseAgent(UUID agentID, bool force) 4904 /// </summary>
4528 { 4905 /// <param name="firstName"></param>
4529 ScenePresence sp; 4906 /// <param name="lastName"></param>
4530 4907 /// <returns>null if the presence was not found</returns>
4531 lock (m_removeClientLock) 4908 public ScenePresence GetScenePresence(string firstName, string lastName)
4532 { 4909 {
4533 sp = GetScenePresence(agentID); 4910 return m_sceneGraph.GetScenePresence(firstName, lastName);
4534 4911 }
4535 if (sp == null) 4912
4536 { 4913 /// <summary>
4537 m_log.DebugFormat( 4914 /// Request the scene presence by localID.
4538 "[SCENE]: Called CloseClient() with agent ID {0} but no such presence is in {1}", 4915 /// </summary>
4539 agentID, Name); 4916 /// <param name="localID"></param>
4540 4917 /// <returns>null if the presence was not found</returns>
4541 return false; 4918 public ScenePresence GetScenePresence(uint localID)
4542 } 4919 {
4543 4920 return m_sceneGraph.GetScenePresence(localID);
4544 if (sp.LifecycleState != ScenePresenceState.Running && sp.LifecycleState != ScenePresenceState.PreRemove) 4921 }
4545 { 4922
4546 m_log.DebugFormat( 4923 /// <summary>
4547 "[SCENE]: Called CloseClient() for {0} in {1} but presence is already in state {2}", 4924 /// Gets all the scene presences in this scene.
4548 sp.Name, Name, sp.LifecycleState); 4925 /// </summary>
4549 4926 /// <remarks>
4550 return false; 4927 /// This method will return both root and child scene presences.
4551 } 4928 ///
4552 4929 /// Consider using ForEachScenePresence() or ForEachRootScenePresence() if possible since these will not
4553 // We need to avoid a race condition where in, for example, an A B C D region layout, an avatar may 4930 /// involving creating a new List object.
4554 // teleport from A -> D, but then -> C before A has asked B to close its old child agent. We do not 4931 /// </remarks>
4555 // want to obey this close since C may have renewed the child agent lease on B. 4932 /// <returns>
4556 if (sp.DoNotCloseAfterTeleport) 4933 /// A list of the scene presences. Adding or removing from the list will not affect the presences in the scene.
4557 { 4934 /// </returns>
4558 m_log.DebugFormat( 4935 public List<ScenePresence> GetScenePresences()
4559 "[SCENE]: Not closing {0} agent {1} in {2} since another simulator has re-established the child connection", 4936 {
4560 sp.IsChildAgent ? "child" : "root", sp.Name, Name); 4937 return new List<ScenePresence>(m_sceneGraph.GetScenePresences());
4561 4938 }
4562 // Need to reset the flag so that a subsequent close after another teleport can succeed. 4939
4563 sp.DoNotCloseAfterTeleport = false; 4940 /// <summary>
4564 4941 /// Performs action on all avatars in the scene (root scene presences)
4565 return false; 4942 /// Avatars may be an NPC or a 'real' client.
4566 } 4943 /// </summary>
4567 4944 /// <param name="action"></param>
4568 sp.LifecycleState = ScenePresenceState.Removing; 4945 public void ForEachRootScenePresence(Action<ScenePresence> action)
4569 } 4946 {
4570 4947 m_sceneGraph.ForEachAvatar(action);
4571 sp.ControllingClient.Close(force); 4948 }
4949
4950 /// <summary>
4951 /// Performs action on all scene presences (root and child)
4952 /// </summary>
4953 /// <param name="action"></param>
4954 public void ForEachScenePresence(Action<ScenePresence> action)
4955 {
4956 m_sceneGraph.ForEachScenePresence(action);
4957 }
4958
4959 /// <summary>
4960 /// Get all the scene object groups.
4961 /// </summary>
4962 /// <returns>
4963 /// The scene object groups. If the scene is empty then an empty list is returned.
4964 /// </returns>
4965 public List<SceneObjectGroup> GetSceneObjectGroups()
4966 {
4967 return m_sceneGraph.GetSceneObjectGroups();
4968 }
4969
4970 /// <summary>
4971 /// Get a group via its UUID
4972 /// </summary>
4973 /// <param name="fullID"></param>
4974 /// <returns>null if no group with that id exists</returns>
4975 public SceneObjectGroup GetSceneObjectGroup(UUID fullID)
4976 {
4977 return m_sceneGraph.GetSceneObjectGroup(fullID);
4978 }
4979
4980 /// <summary>
4981 /// Get a group via its local ID
4982 /// </summary>
4983 /// <remarks>This will only return a group if the local ID matches a root part</remarks>
4984 /// <param name="localID"></param>
4985 /// <returns>null if no group with that id exists</returns>
4986 public SceneObjectGroup GetSceneObjectGroup(uint localID)
4987 {
4988 return m_sceneGraph.GetSceneObjectGroup(localID);
4989 }
4990
4991 /// <summary>
4992 /// Get a group by name from the scene (will return the first
4993 /// found, if there are more than one prim with the same name)
4994 /// </summary>
4995 /// <param name="name"></param>
4996 /// <returns>null if no group with that name exists</returns>
4997 public SceneObjectGroup GetSceneObjectGroup(string name)
4998 {
4999 return m_sceneGraph.GetSceneObjectGroup(name);
5000 }
5001
5002 /// <summary>
5003 /// Attempt to get the SOG via its UUID
5004 /// </summary>
5005 /// <param name="fullID"></param>
5006 /// <param name="sog"></param>
5007 /// <returns></returns>
5008 public bool TryGetSceneObjectGroup(UUID fullID, out SceneObjectGroup sog)
5009 {
5010 sog = GetSceneObjectGroup(fullID);
5011 return sog != null;
5012 }
5013
5014 /// <summary>
5015 /// Get a prim by name from the scene (will return the first
5016 /// found, if there are more than one prim with the same name)
5017 /// </summary>
5018 /// <param name="name"></param>
5019 /// <returns></returns>
5020 public SceneObjectPart GetSceneObjectPart(string name)
5021 {
5022 return m_sceneGraph.GetSceneObjectPart(name);
5023 }
5024
5025 /// <summary>
5026 /// Get a prim via its local id
5027 /// </summary>
5028 /// <param name="localID"></param>
5029 /// <returns></returns>
5030 public SceneObjectPart GetSceneObjectPart(uint localID)
5031 {
5032 return m_sceneGraph.GetSceneObjectPart(localID);
5033 }
5034
5035 /// <summary>
5036 /// Get a prim via its UUID
5037 /// </summary>
5038 /// <param name="fullID"></param>
5039 /// <returns></returns>
5040 public SceneObjectPart GetSceneObjectPart(UUID fullID)
5041 {
5042 return m_sceneGraph.GetSceneObjectPart(fullID);
5043 }
5044
5045 /// <summary>
5046 /// Attempt to get a prim via its UUID
5047 /// </summary>
5048 /// <param name="fullID"></param>
5049 /// <param name="sop"></param>
5050 /// <returns></returns>
5051 public bool TryGetSceneObjectPart(UUID fullID, out SceneObjectPart sop)
5052 {
5053 sop = GetSceneObjectPart(fullID);
5054 return sop != null;
5055 }
5056
5057 /// <summary>
5058 /// Get a scene object group that contains the prim with the given local id
5059 /// </summary>
5060 /// <param name="localID"></param>
5061 /// <returns>null if no scene object group containing that prim is found</returns>
5062 public SceneObjectGroup GetGroupByPrim(uint localID)
5063 {
5064 return m_sceneGraph.GetGroupByPrim(localID);
5065 }
5066
5067 /// <summary>
5068 /// Get a scene object group that contains the prim with the given uuid
5069 /// </summary>
5070 /// <param name="fullID"></param>
5071 /// <returns>null if no scene object group containing that prim is found</returns>
5072 public SceneObjectGroup GetGroupByPrim(UUID fullID)
5073 {
5074 return m_sceneGraph.GetGroupByPrim(fullID);
5075 }
5076
5077 public override bool TryGetScenePresence(UUID agentID, out ScenePresence sp)
5078 {
5079 return m_sceneGraph.TryGetScenePresence(agentID, out sp);
5080 }
5081
5082 public bool TryGetAvatarByName(string avatarName, out ScenePresence avatar)
5083 {
5084 return m_sceneGraph.TryGetAvatarByName(avatarName, out avatar);
5085 }
5086
5087 /// <summary>
5088 /// Perform an action on all clients with an avatar in this scene (root only)
5089 /// </summary>
5090 /// <param name="action"></param>
5091 public void ForEachRootClient(Action<IClientAPI> action)
5092 {
5093 ForEachRootScenePresence(delegate(ScenePresence presence)
5094 {
5095 action(presence.ControllingClient);
5096 });
5097 }
5098
5099 /// <summary>
5100 /// Perform an action on all clients connected to the region (root and child)
5101 /// </summary>
5102 /// <param name="action"></param>
5103 public void ForEachClient(Action<IClientAPI> action)
5104 {
5105 m_clientManager.ForEachSync(action);
5106 }
5107
5108 public bool TryGetClient(UUID avatarID, out IClientAPI client)
5109 {
5110 return m_clientManager.TryGetValue(avatarID, out client);
5111 }
5112
5113 public bool TryGetClient(System.Net.IPEndPoint remoteEndPoint, out IClientAPI client)
5114 {
5115 return m_clientManager.TryGetValue(remoteEndPoint, out client);
5116 }
5117
5118 public void ForEachSOG(Action<SceneObjectGroup> action)
5119 {
5120 m_sceneGraph.ForEachSOG(action);
5121 }
5122
5123 /// <summary>
5124 /// Returns a list of the entities in the scene. This is a new list so operations perform on the list itself
5125 /// will not affect the original list of objects in the scene.
5126 /// </summary>
5127 /// <returns></returns>
5128 public EntityBase[] GetEntities()
5129 {
5130 return m_sceneGraph.GetEntities();
5131 }
5132
5133 #endregion
5134
5135
5136 // Commented pending deletion since this method no longer appears to do anything at all
5137 // public bool NeedSceneCacheClear(UUID agentID)
5138 // {
5139 // IInventoryTransferModule inv = RequestModuleInterface<IInventoryTransferModule>();
5140 // if (inv == null)
5141 // return true;
5142 //
5143 // return inv.NeedSceneCacheClear(agentID, this);
5144 // }
5145
5146 public void CleanTempObjects()
5147 {
5148 EntityBase[] entities = GetEntities();
5149 foreach (EntityBase obj in entities)
5150 {
5151 if (obj is SceneObjectGroup)
5152 {
5153 SceneObjectGroup grp = (SceneObjectGroup)obj;
5154
5155 if (!grp.IsDeleted)
5156 {
5157 if ((grp.RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
5158 {
5159 if (grp.RootPart.Expires <= DateTime.Now)
5160 DeleteSceneObject(grp, false);
5161 }
5162 }
5163 }
5164 }
5165
5166 }
5167
5168 public void DeleteFromStorage(UUID uuid)
5169 {
5170 SimulationDataService.RemoveObject(uuid, RegionInfo.RegionID);
5171 }
5172
5173 public int GetHealth()
5174 {
5175 // Returns:
5176 // 1 = sim is up and accepting http requests. The heartbeat has
5177 // stopped and the sim is probably locked up, but a remote
5178 // admin restart may succeed
5179 //
5180 // 2 = Sim is up and the heartbeat is running. The sim is likely
5181 // usable for people within and logins _may_ work
5182 //
5183 // 3 = We have seen a new user enter within the past 4 minutes
5184 // which can be seen as positive confirmation of sim health
5185 //
5186 int health = 1; // Start at 1, means we're up
5187
5188 if ((Util.EnvironmentTickCountSubtract(m_lastFrameTick)) < 1000)
5189 health += 1;
5190 else
5191 return health;
4572 5192
4573 return true; 5193 // A login in the last 4 mins? We can't be doing too badly
4574 } 5194 //
4575 5195 if ((Util.EnvironmentTickCountSubtract(m_LastLogin)) < 240000)
4576 /// <summary> 5196 health++;
4577 /// Tries to teleport agent to another region. 5197 else
4578 /// </summary> 5198 return health;
4579 /// <remarks>
4580 /// The region name must exactly match that given.
4581 /// </remarks>
4582 /// <param name="remoteClient"></param>
4583 /// <param name="regionName"></param>
4584 /// <param name="position"></param>
4585 /// <param name="lookAt"></param>
4586 /// <param name="teleportFlags"></param>
4587 public void RequestTeleportLocation(IClientAPI remoteClient, string regionName, Vector3 position,
4588 Vector3 lookat, uint teleportFlags)
4589 {
4590 GridRegion region = GridService.GetRegionByName(RegionInfo.ScopeID, regionName);
4591
4592 if (region == null)
4593 {
4594 // can't find the region: Tell viewer and abort
4595 remoteClient.SendTeleportFailed("The region '" + regionName + "' could not be found.");
4596 return;
4597 }
4598
4599 RequestTeleportLocation(remoteClient, region.RegionHandle, position, lookat, teleportFlags);
4600 }
4601
4602 /// <summary>
4603 /// Tries to teleport agent to other region.
4604 /// </summary>
4605 /// <param name="remoteClient"></param>
4606 /// <param name="regionHandle"></param>
4607 /// <param name="position"></param>
4608 /// <param name="lookAt"></param>
4609 /// <param name="teleportFlags"></param>
4610 public void RequestTeleportLocation(IClientAPI remoteClient, ulong regionHandle, Vector3 position,
4611 Vector3 lookAt, uint teleportFlags)
4612 {
4613 ScenePresence sp = GetScenePresence(remoteClient.AgentId);
4614 if (sp != null)
4615 {
4616 if (EntityTransferModule != null)
4617 {
4618 EntityTransferModule.Teleport(sp, regionHandle, position, lookAt, teleportFlags);
4619 }
4620 else
4621 {
4622 m_log.DebugFormat("[SCENE]: Unable to perform teleports: no AgentTransferModule is active");
4623 sp.ControllingClient.SendTeleportFailed("Unable to perform teleports on this simulator.");
4624 }
4625 }
4626 }
4627 5199
4628 public bool CrossAgentToNewRegion(ScenePresence agent, bool isFlying) 5200 // CheckHeartbeat();
4629 { 5201
4630 if (EntityTransferModule != null) 5202 return health;
4631 { 5203 }
4632 return EntityTransferModule.Cross(agent, isFlying); 5204
5205 // This callback allows the PhysicsScene to call back to its caller (the SceneGraph) and
5206 // update non-physical objects like the joint proxy objects that represent the position
5207 // of the joints in the scene.
5208
5209 // This routine is normally called from within a lock (OdeLock) from within the OdePhysicsScene
5210 // WARNING: be careful of deadlocks here if you manipulate the scene. Remember you are being called
5211 // from within the OdePhysicsScene.
5212
5213 protected internal void jointMoved(PhysicsJoint joint)
5214 {
5215 // m_parentScene.PhysicsScene.DumpJointInfo(); // non-thread-locked version; we should already be in a lock (OdeLock) when this callback is invoked
5216 SceneObjectPart jointProxyObject = GetSceneObjectPart(joint.ObjectNameInScene);
5217 if (jointProxyObject == null)
5218 {
5219 jointErrorMessage(joint, "WARNING, joint proxy not found, name " + joint.ObjectNameInScene);
5220 return;
5221 }
5222
5223 // now update the joint proxy object in the scene to have the position of the joint as returned by the physics engine
5224 SceneObjectPart trackedBody = GetSceneObjectPart(joint.TrackedBodyName); // FIXME: causes a sequential lookup
5225 if (trackedBody == null) return; // the actor may have been deleted but the joint still lingers around a few frames waiting for deletion. during this time, trackedBody is NULL to prevent further motion of the joint proxy.
5226 jointProxyObject.Velocity = trackedBody.Velocity;
5227 jointProxyObject.AngularVelocity = trackedBody.AngularVelocity;
5228 switch (joint.Type)
5229 {
5230 case PhysicsJointType.Ball:
5231 {
5232 Vector3 jointAnchor = PhysicsScene.GetJointAnchor(joint);
5233 Vector3 proxyPos = jointAnchor;
5234 jointProxyObject.ParentGroup.UpdateGroupPosition(proxyPos); // schedules the entire group for a terse update
5235 }
5236 break;
5237
5238 case PhysicsJointType.Hinge:
5239 {
5240 Vector3 jointAnchor = PhysicsScene.GetJointAnchor(joint);
5241
5242 // Normally, we would just ask the physics scene to return the axis for the joint.
5243 // Unfortunately, ODE sometimes returns <0,0,0> for the joint axis, which should
5244 // never occur. Therefore we cannot rely on ODE to always return a correct joint axis.
5245 // Therefore the following call does not always work:
5246 //PhysicsVector phyJointAxis = _PhyScene.GetJointAxis(joint);
5247
5248 // instead we compute the joint orientation by saving the original joint orientation
5249 // relative to one of the jointed bodies, and applying this transformation
5250 // to the current position of the jointed bodies (the tracked body) to compute the
5251 // current joint orientation.
5252
5253 if (joint.TrackedBodyName == null)
5254 {
5255 jointErrorMessage(joint, "joint.TrackedBodyName is null, joint " + joint.ObjectNameInScene);
5256 }
5257
5258 Vector3 proxyPos = jointAnchor;
5259 Quaternion q = trackedBody.RotationOffset * joint.LocalRotation;
5260
5261 jointProxyObject.ParentGroup.UpdateGroupPosition(proxyPos); // schedules the entire group for a terse update
5262 jointProxyObject.ParentGroup.UpdateGroupRotationR(q); // schedules the entire group for a terse update
5263 }
5264 break;
5265 }
5266 }
5267
5268 // This callback allows the PhysicsScene to call back to its caller (the SceneGraph) and
5269 // update non-physical objects like the joint proxy objects that represent the position
5270 // of the joints in the scene.
5271
5272 // This routine is normally called from within a lock (OdeLock) from within the OdePhysicsScene
5273 // WARNING: be careful of deadlocks here if you manipulate the scene. Remember you are being called
5274 // from within the OdePhysicsScene.
5275 protected internal void jointDeactivated(PhysicsJoint joint)
5276 {
5277 //m_log.Debug("[NINJA] SceneGraph.jointDeactivated, joint:" + joint.ObjectNameInScene);
5278 SceneObjectPart jointProxyObject = GetSceneObjectPart(joint.ObjectNameInScene);
5279 if (jointProxyObject == null)
5280 {
5281 jointErrorMessage(joint, "WARNING, trying to deactivate (stop interpolation of) joint proxy, but not found, name " + joint.ObjectNameInScene);
5282 return;
5283 }
5284
5285 // turn the proxy non-physical, which also stops its client-side interpolation
5286 bool wasUsingPhysics = ((jointProxyObject.Flags & PrimFlags.Physics) != 0);
5287 if (wasUsingPhysics)
5288 {
5289 jointProxyObject.UpdatePrimFlags(false, false, true, false); // FIXME: possible deadlock here; check to make sure all the scene alterations set into motion here won't deadlock
5290 }
5291 }
5292
5293 // This callback allows the PhysicsScene to call back to its caller (the SceneGraph) and
5294 // alert the user of errors by using the debug channel in the same way that scripts alert
5295 // the user of compile errors.
5296
5297 // This routine is normally called from within a lock (OdeLock) from within the OdePhysicsScene
5298 // WARNING: be careful of deadlocks here if you manipulate the scene. Remember you are being called
5299 // from within the OdePhysicsScene.
5300 public void jointErrorMessage(PhysicsJoint joint, string message)
5301 {
5302 if (joint != null)
5303 {
5304 if (joint.ErrorMessageCount > PhysicsJoint.maxErrorMessages)
5305 return;
5306
5307 SceneObjectPart jointProxyObject = GetSceneObjectPart(joint.ObjectNameInScene);
5308 if (jointProxyObject != null)
5309 {
5310 SimChat(Utils.StringToBytes("[NINJA]: " + message),
5311 ChatTypeEnum.DebugChannel,
5312 2147483647,
5313 jointProxyObject.AbsolutePosition,
5314 jointProxyObject.Name,
5315 jointProxyObject.UUID,
5316 false);
5317
5318 joint.ErrorMessageCount++;
5319
5320 if (joint.ErrorMessageCount > PhysicsJoint.maxErrorMessages)
5321 {
5322 SimChat(Utils.StringToBytes("[NINJA]: Too many messages for this joint, suppressing further messages."),
5323 ChatTypeEnum.DebugChannel,
5324 2147483647,
5325 jointProxyObject.AbsolutePosition,
5326 jointProxyObject.Name,
5327 jointProxyObject.UUID,
5328 false);
5329 }
4633 } 5330 }
4634 else 5331 else
4635 { 5332 {
4636 m_log.DebugFormat("[SCENE]: Unable to cross agent to neighbouring region, because there is no AgentTransferModule"); 5333 // couldn't find the joint proxy object; the error message is silently suppressed
4637 } 5334 }
5335 }
5336 }
4638 5337
4639 return false; 5338 public Scene ConsoleScene()
4640 } 5339 {
4641 5340 if (MainConsole.Instance == null)
4642 public void SendOutChildAgentUpdates(AgentPosition cadu, ScenePresence presence) 5341 return null;
4643 { 5342 if (MainConsole.Instance.ConsoleScene is Scene)
4644 m_sceneGridService.SendChildAgentDataUpdate(cadu, presence); 5343 return (Scene)MainConsole.Instance.ConsoleScene;
4645 } 5344 return null;
4646 5345 }
4647 #endregion 5346
4648 5347 // Get terrain height at the specified <x,y> location.
4649 #region Other Methods 5348 // Presumes the underlying implementation is a heightmap which is a 1m grid.
4650 5349 // Finds heightmap grid points before and after the point and
4651 protected override IConfigSource GetConfig() 5350 // does a linear approximation of the height at this intermediate point.
4652 { 5351 public float GetGroundHeight(float x, float y)
4653 return m_config; 5352 {
4654 } 5353 if (x < 0)
4655 5354 x = 0;
4656 #endregion 5355 if (x >= Heightmap.Width)
4657 5356 x = Heightmap.Width - 1;
4658 public void HandleObjectPermissionsUpdate(IClientAPI controller, UUID agentID, UUID sessionID, byte field, uint localId, uint mask, byte set) 5357 if (y < 0)
4659 { 5358 y = 0;
4660 // Check for spoofing.. since this is permissions we're talking about here! 5359 if (y >= Heightmap.Height)
4661 if ((controller.SessionId == sessionID) && (controller.AgentId == agentID)) 5360 y = Heightmap.Height - 1;
4662 { 5361
4663 // Tell the object to do permission update 5362 Vector3 p0 = new Vector3(x, y, (float)Heightmap[(int)x, (int)y]);
4664 if (localId != 0) 5363 Vector3 p1 = p0;
4665 { 5364 Vector3 p2 = p0;
4666 SceneObjectGroup chObjectGroup = GetGroupByPrim(localId); 5365
4667 if (chObjectGroup != null) 5366 p1.X += 1.0f;
4668 { 5367 if (p1.X < Heightmap.Width)
4669 chObjectGroup.UpdatePermissions(agentID, field, localId, mask, set); 5368 p1.Z = (float)Heightmap[(int)p1.X, (int)p1.Y];
4670 } 5369
4671 } 5370 p2.Y += 1.0f;
4672 } 5371 if (p2.Y < Heightmap.Height)
4673 } 5372 p2.Z = (float)Heightmap[(int)p2.X, (int)p2.Y];
4674 5373
4675 /// <summary> 5374 Vector3 v0 = new Vector3(p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z);
4676 /// Causes all clients to get a full object update on all of the objects in the scene. 5375 Vector3 v1 = new Vector3(p2.X - p0.X, p2.Y - p0.Y, p2.Z - p0.Z);
4677 /// </summary> 5376
4678 public void ForceClientUpdate() 5377 v0.Normalize();
4679 { 5378 v1.Normalize();
4680 EntityBase[] entityList = GetEntities(); 5379
4681 foreach (EntityBase ent in entityList) 5380 Vector3 vsn = new Vector3();
4682 { 5381 vsn.X = (v0.Y * v1.Z) - (v0.Z * v1.Y);
4683 if (ent is SceneObjectGroup) 5382 vsn.Y = (v0.Z * v1.X) - (v0.X * v1.Z);
4684 { 5383 vsn.Z = (v0.X * v1.Y) - (v0.Y * v1.X);
4685 ((SceneObjectGroup)ent).ScheduleGroupForFullUpdate(); 5384 vsn.Normalize();
4686 } 5385
4687 } 5386 float xdiff = x - (float)((int)x);
4688 } 5387 float ydiff = y - (float)((int)y);
4689 5388
4690 /// <summary> 5389 return (((vsn.X * xdiff) + (vsn.Y * ydiff)) / (-1 * vsn.Z)) + p0.Z;
4691 /// This is currently only used for scale (to scale to MegaPrim size) 5390 }
4692 /// There is a console command that calls this in OpenSimMain 5391
4693 /// </summary> 5392 // private void CheckHeartbeat()
4694 /// <param name="cmdparams"></param> 5393 // {
4695 public void HandleEditCommand(string[] cmdparams) 5394 // if (m_firstHeartbeat)
4696 { 5395 // return;
4697 m_log.DebugFormat("Searching for Primitive: '{0}'", cmdparams[2]); 5396 //
4698 5397 // if (Util.EnvironmentTickCountSubtract(m_lastFrameTick) > 2000)
4699 EntityBase[] entityList = GetEntities(); 5398 // StartTimer();
4700 foreach (EntityBase ent in entityList) 5399 // }
4701 { 5400
4702 if (ent is SceneObjectGroup) 5401 public override ISceneObject DeserializeObject(string representation)
4703 { 5402 {
4704 SceneObjectPart part = ((SceneObjectGroup)ent).GetPart(((SceneObjectGroup)ent).UUID); 5403 return SceneObjectSerializer.FromXml2Format(representation);
4705 if (part != null) 5404 }
4706 { 5405
4707 if (part.Name == cmdparams[2]) 5406 public override bool AllowScriptCrossings
4708 { 5407 {
4709 part.Resize( 5408 get { return m_allowScriptCrossings; }
4710 new Vector3(Convert.ToSingle(cmdparams[3]), Convert.ToSingle(cmdparams[4]), 5409 }
4711 Convert.ToSingle(cmdparams[5]))); 5410
4712 5411 public Vector3 GetNearestAllowedPosition(ScenePresence avatar)
4713 m_log.DebugFormat("Edited scale of Primitive: {0}", part.Name); 5412 {
4714 } 5413 return GetNearestAllowedPosition(avatar, null);
4715 } 5414 }
4716 } 5415
4717 } 5416 public Vector3 GetNearestAllowedPosition(ScenePresence avatar, ILandObject excludeParcel)
4718 } 5417 {
4719 5418 ILandObject nearestParcel = GetNearestAllowedParcel(avatar.UUID, avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y, excludeParcel);
4720 #region Script Handling Methods 5419
4721 5420 if (nearestParcel != null)
4722 /// <summary> 5421 {
4723 /// Console command handler to send script command to script engine. 5422 Vector3 dir = Vector3.Normalize(Vector3.Multiply(avatar.Velocity, -1));
4724 /// </summary> 5423 //Try to get a location that feels like where they came from
4725 /// <param name="args"></param> 5424 Vector3? nearestPoint = GetNearestPointInParcelAlongDirectionFromPoint(avatar.AbsolutePosition, dir, nearestParcel);
4726 public void SendCommandToPlugins(string[] args) 5425 if (nearestPoint != null)
4727 { 5426 {
4728 m_eventManager.TriggerOnPluginConsole(args); 5427 m_log.Debug("Found a sane previous position based on velocity, sending them to: " + nearestPoint.ToString());
4729 } 5428 return nearestPoint.Value;
4730 5429 }
4731 public LandData GetLandData(float x, float y) 5430
4732 { 5431 //Sometimes velocity might be zero (local teleport), so try finding point along path from avatar to center of nearest parcel
4733 return LandChannel.GetLandObject(x, y).LandData; 5432 Vector3 directionToParcelCenter = Vector3.Subtract(GetParcelCenterAtGround(nearestParcel), avatar.AbsolutePosition);
4734 } 5433 dir = Vector3.Normalize(directionToParcelCenter);
4735 5434 nearestPoint = GetNearestPointInParcelAlongDirectionFromPoint(avatar.AbsolutePosition, dir, nearestParcel);
4736 /// <summary> 5435 if (nearestPoint != null)
4737 /// Get LandData by position. 5436 {
4738 /// </summary> 5437 m_log.Debug("They had a zero velocity, sending them to: " + nearestPoint.ToString());
4739 /// <param name="pos"></param> 5438 return nearestPoint.Value;
4740 /// <returns></returns> 5439 }
4741 public LandData GetLandData(Vector3 pos) 5440
4742 { 5441 ILandObject dest = LandChannel.GetLandObject(avatar.lastKnownAllowedPosition.X, avatar.lastKnownAllowedPosition.Y);
4743 return GetLandData(pos.X, pos.Y); 5442 if (dest != excludeParcel)
4744 } 5443 {
4745 5444 // Ultimate backup if we have no idea where they are and
4746 public LandData GetLandData(uint x, uint y) 5445 // the last allowed position was in another parcel
4747 { 5446 m_log.Debug("Have no idea where they are, sending them to: " + avatar.lastKnownAllowedPosition.ToString());
4748 m_log.DebugFormat("[SCENE]: returning land for {0},{1}", x, y); 5447 return avatar.lastKnownAllowedPosition;
4749 return LandChannel.GetLandObject((int)x, (int)y).LandData; 5448 }
4750 } 5449
4751 5450 // else fall through to region edge
4752 #endregion 5451 }
4753 5452
4754 #region Script Engine 5453 //Go to the edge, this happens in teleporting to a region with no available parcels
4755 5454 Vector3 nearestRegionEdgePoint = GetNearestRegionEdgePosition(avatar);
4756 private bool ScriptDanger(SceneObjectPart part,Vector3 pos) 5455
4757 { 5456 //m_log.Debug("They are really in a place they don't belong, sending them to: " + nearestRegionEdgePoint.ToString());
4758 ILandObject parcel = LandChannel.GetLandObject(pos.X, pos.Y); 5457
4759 if (part != null) 5458 return nearestRegionEdgePoint;
4760 { 5459 }
4761 if (parcel != null) 5460
4762 { 5461 private Vector3 GetParcelCenterAtGround(ILandObject parcel)
4763 if ((parcel.LandData.Flags & (uint)ParcelFlags.AllowOtherScripts) != 0) 5462 {
4764 { 5463 Vector2 center = GetParcelCenter(parcel);
4765 return true; 5464 return GetPositionAtGround(center.X, center.Y);
4766 } 5465 }
4767 else if ((part.OwnerID == parcel.LandData.OwnerID) || Permissions.IsGod(part.OwnerID)) 5466
4768 { 5467 private Vector3? GetNearestPointInParcelAlongDirectionFromPoint(Vector3 pos, Vector3 direction, ILandObject parcel)
4769 return true; 5468 {
4770 } 5469 Vector3 unitDirection = Vector3.Normalize(direction);
4771 else if (((parcel.LandData.Flags & (uint)ParcelFlags.AllowGroupScripts) != 0) 5470 //Making distance to search go through some sane limit of distance
4772 && (parcel.LandData.GroupID != UUID.Zero) && (parcel.LandData.GroupID == part.GroupID)) 5471 for (float distance = 0; distance < Math.Max(RegionInfo.RegionSizeX, RegionInfo.RegionSizeY) * 2; distance += .5f)
4773 { 5472 {
4774 return true; 5473 Vector3 testPos = Vector3.Add(pos, Vector3.Multiply(unitDirection, distance));
4775 } 5474 if (parcel.ContainsPoint((int)testPos.X, (int)testPos.Y))
4776 else 5475 {
4777 { 5476 return testPos;
4778 return false; 5477 }
4779 } 5478 }
4780 } 5479 return null;
4781 else 5480 }
4782 { 5481
4783 5482 public ILandObject GetNearestAllowedParcel(UUID avatarId, float x, float y)
4784 if (pos.X > 0f && pos.X < RegionInfo.RegionSizeX && pos.Y > 0f && pos.Y < RegionInfo.RegionSizeY) 5483 {
4785 { 5484 return GetNearestAllowedParcel(avatarId, x, y, null);
4786 // The only time parcel != null when an object is inside a region is when 5485 }
4787 // there is nothing behind the landchannel. IE, no land plugin loaded. 5486
4788 return true; 5487 public ILandObject GetNearestAllowedParcel(UUID avatarId, float x, float y, ILandObject excludeParcel)
4789 } 5488 {
4790 else 5489 List<ILandObject> all = AllParcels();
4791 { 5490 float minParcelDistance = float.MaxValue;
4792 // The object is outside of this region. Stop piping events to it. 5491 ILandObject nearestParcel = null;
4793 return false; 5492
4794 } 5493 foreach (var parcel in all)
4795 } 5494 {
5495 if (!parcel.IsEitherBannedOrRestricted(avatarId) && parcel != excludeParcel)
5496 {
5497 float parcelDistance = GetParcelDistancefromPoint(parcel, x, y);
5498 if (parcelDistance < minParcelDistance)
5499 {
5500 minParcelDistance = parcelDistance;
5501 nearestParcel = parcel;
5502 }
5503 }
5504 }
5505
5506 return nearestParcel;
5507 }
5508
5509 private List<ILandObject> AllParcels()
5510 {
5511 return LandChannel.AllParcels();
5512 }
5513
5514 private float GetParcelDistancefromPoint(ILandObject parcel, float x, float y)
5515 {
5516 return Vector2.Distance(new Vector2(x, y), GetParcelCenter(parcel));
5517 }
5518
5519 //calculate the average center point of a parcel
5520 private Vector2 GetParcelCenter(ILandObject parcel)
5521 {
5522 int count = 0;
5523 int avgx = 0;
5524 int avgy = 0;
5525 for (int x = 0; x < RegionInfo.RegionSizeX; x++)
5526 {
5527 for (int y = 0; y < RegionInfo.RegionSizeY; y++)
5528 {
5529 //Just keep a running average as we check if all the points are inside or not
5530 if (parcel.ContainsPoint(x, y))
5531 {
5532 if (count == 0)
5533 {
5534 avgx = x;
5535 avgy = y;
5536 }
5537 else
5538 {
5539 avgx = (avgx * count + x) / (count + 1);
5540 avgy = (avgy * count + y) / (count + 1);
5541 }
5542 count += 1;
5543 }
5544 }
5545 }
5546 return new Vector2(avgx, avgy);
5547 }
5548
5549 private Vector3 GetNearestRegionEdgePosition(ScenePresence avatar)
5550 {
5551 float xdistance = avatar.AbsolutePosition.X < RegionInfo.RegionSizeX / 2
5552 ? avatar.AbsolutePosition.X : RegionInfo.RegionSizeX - avatar.AbsolutePosition.X;
5553 float ydistance = avatar.AbsolutePosition.Y < RegionInfo.RegionSizeY / 2
5554 ? avatar.AbsolutePosition.Y : RegionInfo.RegionSizeY - avatar.AbsolutePosition.Y;
5555
5556 //find out what vertical edge to go to
5557 if (xdistance < ydistance)
5558 {
5559 if (avatar.AbsolutePosition.X < RegionInfo.RegionSizeX / 2)
5560 {
5561 return GetPositionAtAvatarHeightOrGroundHeight(avatar, 0.0f, avatar.AbsolutePosition.Y);
4796 } 5562 }
4797 else 5563 else
4798 { 5564 {
4799 return false; 5565 return GetPositionAtAvatarHeightOrGroundHeight(avatar, RegionInfo.RegionSizeY, avatar.AbsolutePosition.Y);
4800 } 5566 }
4801 } 5567 }
4802 5568 //find out what horizontal edge to go to
4803 public bool ScriptDanger(uint localID, Vector3 pos) 5569 else
4804 { 5570 {
4805 SceneObjectPart part = GetSceneObjectPart(localID); 5571 if (avatar.AbsolutePosition.Y < RegionInfo.RegionSizeY / 2)
4806 if (part != null)
4807 { 5572 {
4808 return ScriptDanger(part, pos); 5573 return GetPositionAtAvatarHeightOrGroundHeight(avatar, avatar.AbsolutePosition.X, 0.0f);
4809 } 5574 }
4810 else 5575 else
4811 { 5576 {
4812 return false; 5577 return GetPositionAtAvatarHeightOrGroundHeight(avatar, avatar.AbsolutePosition.X, RegionInfo.RegionSizeY);
4813 } 5578 }
4814 } 5579 }
5580 }
5581
5582 private Vector3 GetPositionAtAvatarHeightOrGroundHeight(ScenePresence avatar, float x, float y)
5583 {
5584 Vector3 ground = GetPositionAtGround(x, y);
5585 if (avatar.AbsolutePosition.Z > ground.Z)
5586 {
5587 ground.Z = avatar.AbsolutePosition.Z;
5588 }
5589 return ground;
5590 }
5591
5592 private Vector3 GetPositionAtGround(float x, float y)
5593 {
5594 return new Vector3(x, y, GetGroundHeight(x, y));
5595 }
5596
5597 public List<UUID> GetEstateRegions(int estateID)
5598 {
5599 IEstateDataService estateDataService = EstateDataService;
5600 if (estateDataService == null)
5601 return new List<UUID>(0);
5602
5603 return estateDataService.GetRegions(estateID);
5604 }
5605
5606 public void ReloadEstateData()
5607 {
5608 IEstateDataService estateDataService = EstateDataService;
5609 if (estateDataService != null)
5610 {
5611 RegionInfo.EstateSettings = estateDataService.LoadEstateSettings(RegionInfo.RegionID, false);
5612 TriggerEstateSunUpdate();
5613 }
5614 }
5615
5616 public void TriggerEstateSunUpdate()
5617 {
5618 EventManager.TriggerEstateToolsSunUpdate(RegionInfo.RegionHandle);
5619 }
5620
5621 private void HandleReloadEstate(string module, string[] cmd)
5622 {
5623 if (MainConsole.Instance.ConsoleScene == null ||
5624 (MainConsole.Instance.ConsoleScene is Scene &&
5625 (Scene)MainConsole.Instance.ConsoleScene == this))
5626 {
5627 ReloadEstateData();
5628 }
5629 }
5630
5631 /// <summary>
5632 /// Get the volume of space that will encompass all the given objects.
5633 /// </summary>
5634 /// <param name="objects"></param>
5635 /// <param name="minX"></param>
5636 /// <param name="maxX"></param>
5637 /// <param name="minY"></param>
5638 /// <param name="maxY"></param>
5639 /// <param name="minZ"></param>
5640 /// <param name="maxZ"></param>
5641 /// <returns></returns>
5642 public static Vector3[] GetCombinedBoundingBox(
5643 List<SceneObjectGroup> objects,
5644 out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ)
5645 {
5646 minX = float.MaxValue;
5647 maxX = float.MinValue;
5648 minY = float.MaxValue;
5649 maxY = float.MinValue;
5650 minZ = float.MaxValue;
5651 maxZ = float.MinValue;
5652
5653 List<Vector3> offsets = new List<Vector3>();
5654
5655 foreach (SceneObjectGroup g in objects)
5656 {
5657 float ominX, ominY, ominZ, omaxX, omaxY, omaxZ;
5658
5659 Vector3 vec = g.AbsolutePosition;
5660
5661 g.GetAxisAlignedBoundingBoxRaw(out ominX, out omaxX, out ominY, out omaxY, out ominZ, out omaxZ);
5662
5663 // m_log.DebugFormat(
5664 // "[SCENE]: For {0} found AxisAlignedBoundingBoxRaw {1}, {2}",
5665 // g.Name, new Vector3(ominX, ominY, ominZ), new Vector3(omaxX, omaxY, omaxZ));
5666
5667 ominX += vec.X;
5668 omaxX += vec.X;
5669 ominY += vec.Y;
5670 omaxY += vec.Y;
5671 ominZ += vec.Z;
5672 omaxZ += vec.Z;
5673
5674 if (minX > ominX)
5675 minX = ominX;
5676 if (minY > ominY)
5677 minY = ominY;
5678 if (minZ > ominZ)
5679 minZ = ominZ;
5680 if (maxX < omaxX)
5681 maxX = omaxX;
5682 if (maxY < omaxY)
5683 maxY = omaxY;
5684 if (maxZ < omaxZ)
5685 maxZ = omaxZ;
5686 }
5687
5688 foreach (SceneObjectGroup g in objects)
5689 {
5690 Vector3 vec = g.AbsolutePosition;
5691 vec.X -= minX;
5692 vec.Y -= minY;
5693 vec.Z -= minZ;
5694
5695 offsets.Add(vec);
5696 }
5697
5698 return offsets.ToArray();
5699 }
5700
5701 /// <summary>
5702 /// Regenerate the maptile for this scene.
5703 /// </summary>
5704 /// <param name="sender"></param>
5705 /// <param name="e"></param>
5706 private void RegenerateMaptile()
5707 {
5708 IWorldMapModule mapModule = RequestModuleInterface<IWorldMapModule>();
5709 if (mapModule != null)
5710 mapModule.GenerateMaptile();
5711 }
5712
5713 private void RegenerateMaptileAndReregister(object sender, ElapsedEventArgs e)
5714 {
5715 RegenerateMaptile();
5716
5717 // We need to propagate the new image UUID to the grid service
5718 // so that all simulators can retrieve it
5719 string error = GridService.RegisterRegion(RegionInfo.ScopeID, new GridRegion(RegionInfo));
5720 if (error != string.Empty)
5721 throw new Exception(error);
5722 }
5723
5724 /// <summary>
5725 /// This method is called across the simulation connector to
5726 /// determine if a given agent is allowed in this region
5727 /// AS A ROOT AGENT
5728 /// </summary>
5729 /// <remarks>
5730 /// Returning false here will prevent them
5731 /// from logging into the region, teleporting into the region
5732 /// or corssing the broder walking, but will NOT prevent
5733 /// child agent creation, thereby emulating the SL behavior.
5734 /// </remarks>
5735 /// <param name='agentID'>The visitor's User ID</param>
5736 /// <param name="agentHomeURI">The visitor's Home URI (may be null)</param>
5737 /// <param name='position'></param>
5738 /// <param name='reason'></param>
5739 /// <returns></returns>
5740 public bool QueryAccess(UUID agentID, string agentHomeURI, bool viaTeleport, Vector3 position, out string reason)
5741 {
5742 reason = string.Empty;
5743
5744 if (Permissions.IsGod(agentID))
5745 {
5746 reason = String.Empty;
5747 return true;
5748 }
4815 5749
4816 public bool PipeEventsForScript(uint localID) 5750 if (!AllowAvatarCrossing && !viaTeleport)
4817 { 5751 return false;
4818 SceneObjectPart part = GetSceneObjectPart(localID); 5752
5753 // FIXME: Root agent count is currently known to be inaccurate. This forces a recount before we check.
5754 // However, the long term fix is to make sure root agent count is always accurate.
5755 m_sceneGraph.RecalculateStats();
4819 5756
4820 if (part != null) 5757 int num = m_sceneGraph.GetRootAgentCount();
5758
5759 if (num >= RegionInfo.RegionSettings.AgentLimit)
5760 {
5761 if (!Permissions.IsAdministrator(agentID))
4821 { 5762 {
4822 SceneObjectPart parent = part.ParentGroup.RootPart; 5763 reason = "The region is full";
4823 return ScriptDanger(parent, parent.GetWorldPosition()); 5764
5765 m_log.DebugFormat(
5766 "[SCENE]: Denying presence with id {0} entry into {1} since region is at agent limit of {2}",
5767 agentID, RegionInfo.RegionName, RegionInfo.RegionSettings.AgentLimit);
5768
5769 return false;
4824 } 5770 }
4825 else 5771 }
4826 {
4827 return false;
4828 }
4829 }
4830
4831 #endregion
4832
4833 #region SceneGraph wrapper methods
4834
4835 /// <summary>
4836 ///
4837 /// </summary>
4838 /// <param name="localID"></param>
4839 /// <returns></returns>
4840 public UUID ConvertLocalIDToFullID(uint localID)
4841 {
4842 return m_sceneGraph.ConvertLocalIDToFullID(localID);
4843 }
4844
4845 public void SwapRootAgentCount(bool rootChildChildRootTF)
4846 {
4847 m_sceneGraph.SwapRootChildAgent(rootChildChildRootTF);
4848 }
4849
4850 public void AddPhysicalPrim(int num)
4851 {
4852 m_sceneGraph.AddPhysicalPrim(num);
4853 }
4854
4855 public void RemovePhysicalPrim(int num)
4856 {
4857 m_sceneGraph.RemovePhysicalPrim(num);
4858 }
4859
4860 public int GetRootAgentCount()
4861 {
4862 return m_sceneGraph.GetRootAgentCount();
4863 }
4864
4865 public int GetChildAgentCount()
4866 {
4867 return m_sceneGraph.GetChildAgentCount();
4868 }
4869
4870 /// <summary>
4871 /// Request a scene presence by UUID. Fast, indexed lookup.
4872 /// </summary>
4873 /// <param name="agentID"></param>
4874 /// <returns>null if the presence was not found</returns>
4875 public ScenePresence GetScenePresence(UUID agentID)
4876 {
4877 return m_sceneGraph.GetScenePresence(agentID);
4878 }
4879
4880 /// <summary>
4881 /// Request the scene presence by name.
4882 /// </summary>
4883 /// <param name="firstName"></param>
4884 /// <param name="lastName"></param>
4885 /// <returns>null if the presence was not found</returns>
4886 public ScenePresence GetScenePresence(string firstName, string lastName)
4887 {
4888 return m_sceneGraph.GetScenePresence(firstName, lastName);
4889 }
4890
4891 /// <summary>
4892 /// Request the scene presence by localID.
4893 /// </summary>
4894 /// <param name="localID"></param>
4895 /// <returns>null if the presence was not found</returns>
4896 public ScenePresence GetScenePresence(uint localID)
4897 {
4898 return m_sceneGraph.GetScenePresence(localID);
4899 }
4900
4901 /// <summary>
4902 /// Gets all the scene presences in this scene.
4903 /// </summary>
4904 /// <remarks>
4905 /// This method will return both root and child scene presences.
4906 ///
4907 /// Consider using ForEachScenePresence() or ForEachRootScenePresence() if possible since these will not
4908 /// involving creating a new List object.
4909 /// </remarks>
4910 /// <returns>
4911 /// A list of the scene presences. Adding or removing from the list will not affect the presences in the scene.
4912 /// </returns>
4913 public List<ScenePresence> GetScenePresences()
4914 {
4915 return new List<ScenePresence>(m_sceneGraph.GetScenePresences());
4916 }
4917
4918 /// <summary>
4919 /// Performs action on all avatars in the scene (root scene presences)
4920 /// Avatars may be an NPC or a 'real' client.
4921 /// </summary>
4922 /// <param name="action"></param>
4923 public void ForEachRootScenePresence(Action<ScenePresence> action)
4924 {
4925 m_sceneGraph.ForEachAvatar(action);
4926 }
4927
4928 /// <summary>
4929 /// Performs action on all scene presences (root and child)
4930 /// </summary>
4931 /// <param name="action"></param>
4932 public void ForEachScenePresence(Action<ScenePresence> action)
4933 {
4934 m_sceneGraph.ForEachScenePresence(action);
4935 }
4936
4937 /// <summary>
4938 /// Get all the scene object groups.
4939 /// </summary>
4940 /// <returns>
4941 /// The scene object groups. If the scene is empty then an empty list is returned.
4942 /// </returns>
4943 public List<SceneObjectGroup> GetSceneObjectGroups()
4944 {
4945 return m_sceneGraph.GetSceneObjectGroups();
4946 }
4947
4948 /// <summary>
4949 /// Get a group via its UUID
4950 /// </summary>
4951 /// <param name="fullID"></param>
4952 /// <returns>null if no group with that id exists</returns>
4953 public SceneObjectGroup GetSceneObjectGroup(UUID fullID)
4954 {
4955 return m_sceneGraph.GetSceneObjectGroup(fullID);
4956 }
4957
4958 /// <summary>
4959 /// Get a group via its local ID
4960 /// </summary>
4961 /// <remarks>This will only return a group if the local ID matches a root part</remarks>
4962 /// <param name="localID"></param>
4963 /// <returns>null if no group with that id exists</returns>
4964 public SceneObjectGroup GetSceneObjectGroup(uint localID)
4965 {
4966 return m_sceneGraph.GetSceneObjectGroup(localID);
4967 }
4968
4969 /// <summary>
4970 /// Get a group by name from the scene (will return the first
4971 /// found, if there are more than one prim with the same name)
4972 /// </summary>
4973 /// <param name="name"></param>
4974 /// <returns>null if no group with that name exists</returns>
4975 public SceneObjectGroup GetSceneObjectGroup(string name)
4976 {
4977 return m_sceneGraph.GetSceneObjectGroup(name);
4978 }
4979
4980 /// <summary>
4981 /// Attempt to get the SOG via its UUID
4982 /// </summary>
4983 /// <param name="fullID"></param>
4984 /// <param name="sog"></param>
4985 /// <returns></returns>
4986 public bool TryGetSceneObjectGroup(UUID fullID, out SceneObjectGroup sog)
4987 {
4988 sog = GetSceneObjectGroup(fullID);
4989 return sog != null;
4990 }
4991
4992 /// <summary>
4993 /// Get a prim by name from the scene (will return the first
4994 /// found, if there are more than one prim with the same name)
4995 /// </summary>
4996 /// <param name="name"></param>
4997 /// <returns></returns>
4998 public SceneObjectPart GetSceneObjectPart(string name)
4999 {
5000 return m_sceneGraph.GetSceneObjectPart(name);
5001 }
5002
5003 /// <summary>
5004 /// Get a prim via its local id
5005 /// </summary>
5006 /// <param name="localID"></param>
5007 /// <returns></returns>
5008 public SceneObjectPart GetSceneObjectPart(uint localID)
5009 {
5010 return m_sceneGraph.GetSceneObjectPart(localID);
5011 }
5012
5013 /// <summary>
5014 /// Get a prim via its UUID
5015 /// </summary>
5016 /// <param name="fullID"></param>
5017 /// <returns></returns>
5018 public SceneObjectPart GetSceneObjectPart(UUID fullID)
5019 {
5020 return m_sceneGraph.GetSceneObjectPart(fullID);
5021 }
5022
5023 /// <summary>
5024 /// Attempt to get a prim via its UUID
5025 /// </summary>
5026 /// <param name="fullID"></param>
5027 /// <param name="sop"></param>
5028 /// <returns></returns>
5029 public bool TryGetSceneObjectPart(UUID fullID, out SceneObjectPart sop)
5030 {
5031 sop = GetSceneObjectPart(fullID);
5032 return sop != null;
5033 }
5034
5035 /// <summary>
5036 /// Get a scene object group that contains the prim with the given local id
5037 /// </summary>
5038 /// <param name="localID"></param>
5039 /// <returns>null if no scene object group containing that prim is found</returns>
5040 public SceneObjectGroup GetGroupByPrim(uint localID)
5041 {
5042 return m_sceneGraph.GetGroupByPrim(localID);
5043 }
5044
5045 /// <summary>
5046 /// Get a scene object group that contains the prim with the given uuid
5047 /// </summary>
5048 /// <param name="fullID"></param>
5049 /// <returns>null if no scene object group containing that prim is found</returns>
5050 public SceneObjectGroup GetGroupByPrim(UUID fullID)
5051 {
5052 return m_sceneGraph.GetGroupByPrim(fullID);
5053 }
5054
5055 public override bool TryGetScenePresence(UUID agentID, out ScenePresence sp)
5056 {
5057 return m_sceneGraph.TryGetScenePresence(agentID, out sp);
5058 }
5059
5060 public bool TryGetAvatarByName(string avatarName, out ScenePresence avatar)
5061 {
5062 return m_sceneGraph.TryGetAvatarByName(avatarName, out avatar);
5063 }
5064
5065 /// <summary>
5066 /// Perform an action on all clients with an avatar in this scene (root only)
5067 /// </summary>
5068 /// <param name="action"></param>
5069 public void ForEachRootClient(Action<IClientAPI> action)
5070 {
5071 ForEachRootScenePresence(delegate(ScenePresence presence)
5072 {
5073 action(presence.ControllingClient);
5074 });
5075 }
5076
5077 /// <summary>
5078 /// Perform an action on all clients connected to the region (root and child)
5079 /// </summary>
5080 /// <param name="action"></param>
5081 public void ForEachClient(Action<IClientAPI> action)
5082 {
5083 m_clientManager.ForEachSync(action);
5084 }
5085
5086 public bool TryGetClient(UUID avatarID, out IClientAPI client)
5087 {
5088 return m_clientManager.TryGetValue(avatarID, out client);
5089 }
5090
5091 public bool TryGetClient(System.Net.IPEndPoint remoteEndPoint, out IClientAPI client)
5092 {
5093 return m_clientManager.TryGetValue(remoteEndPoint, out client);
5094 }
5095
5096 public void ForEachSOG(Action<SceneObjectGroup> action)
5097 {
5098 m_sceneGraph.ForEachSOG(action);
5099 }
5100
5101 /// <summary>
5102 /// Returns a list of the entities in the scene. This is a new list so operations perform on the list itself
5103 /// will not affect the original list of objects in the scene.
5104 /// </summary>
5105 /// <returns></returns>
5106 public EntityBase[] GetEntities()
5107 {
5108 return m_sceneGraph.GetEntities();
5109 }
5110
5111 #endregion
5112
5113
5114// Commented pending deletion since this method no longer appears to do anything at all
5115// public bool NeedSceneCacheClear(UUID agentID)
5116// {
5117// IInventoryTransferModule inv = RequestModuleInterface<IInventoryTransferModule>();
5118// if (inv == null)
5119// return true;
5120//
5121// return inv.NeedSceneCacheClear(agentID, this);
5122// }
5123
5124 public void CleanTempObjects()
5125 {
5126 EntityBase[] entities = GetEntities();
5127 foreach (EntityBase obj in entities)
5128 {
5129 if (obj is SceneObjectGroup)
5130 {
5131 SceneObjectGroup grp = (SceneObjectGroup)obj;
5132
5133 if (!grp.IsDeleted)
5134 {
5135 if ((grp.RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
5136 {
5137 if (grp.RootPart.Expires <= DateTime.Now)
5138 DeleteSceneObject(grp, false);
5139 }
5140 }
5141 }
5142 }
5143
5144 }
5145
5146 public void DeleteFromStorage(UUID uuid)
5147 {
5148 SimulationDataService.RemoveObject(uuid, RegionInfo.RegionID);
5149 }
5150
5151 public int GetHealth()
5152 {
5153 // Returns:
5154 // 1 = sim is up and accepting http requests. The heartbeat has
5155 // stopped and the sim is probably locked up, but a remote
5156 // admin restart may succeed
5157 //
5158 // 2 = Sim is up and the heartbeat is running. The sim is likely
5159 // usable for people within and logins _may_ work
5160 //
5161 // 3 = We have seen a new user enter within the past 4 minutes
5162 // which can be seen as positive confirmation of sim health
5163 //
5164 int health=1; // Start at 1, means we're up
5165 5772
5166 if ((Util.EnvironmentTickCountSubtract(m_lastFrameTick)) < 1000) 5773 ScenePresence presence = GetScenePresence(agentID);
5167 health += 1; 5774 IClientAPI client = null;
5168 else 5775 AgentCircuitData aCircuit = null;
5169 return health;
5170 5776
5171 // A login in the last 4 mins? We can't be doing too badly 5777 if (presence != null)
5172 // 5778 {
5173 if ((Util.EnvironmentTickCountSubtract(m_LastLogin)) < 240000) 5779 client = presence.ControllingClient;
5174 health++; 5780 if (client != null)
5175 else 5781 aCircuit = client.RequestClientInfo();
5176 return health; 5782 }
5177 5783
5178// CheckHeartbeat(); 5784 // We may be called before there is a presence or a client.
5785 // Fake AgentCircuitData to keep IAuthorizationModule smiling
5786 if (client == null)
5787 {
5788 aCircuit = new AgentCircuitData();
5789 aCircuit.AgentID = agentID;
5790 aCircuit.firstname = String.Empty;
5791 aCircuit.lastname = String.Empty;
5792 }
5179 5793
5180 return health; 5794 try
5181 } 5795 {
5796 if (!AuthorizeUser(aCircuit, false, out reason))
5797 {
5798 //m_log.DebugFormat("[SCENE]: Denying access for {0}", agentID);
5799 return false;
5800 }
5801 }
5802 catch (Exception e)
5803 {
5804 m_log.DebugFormat("[SCENE]: Exception authorizing agent: {0} " + e.StackTrace, e.Message);
5805 reason = "Error authorizing agent: " + e.Message;
5806 return false;
5807 }
5808
5809 if (viaTeleport)
5810 {
5811 if (!RegionInfo.EstateSettings.AllowDirectTeleport)
5812 {
5813 SceneObjectGroup telehub;
5814 if (RegionInfo.RegionSettings.TelehubObject != UUID.Zero && (telehub = GetSceneObjectGroup(RegionInfo.RegionSettings.TelehubObject)) != null)
5815 {
5816 List<SpawnPoint> spawnPoints = RegionInfo.RegionSettings.SpawnPoints();
5817 bool banned = true;
5818 foreach (SpawnPoint sp in spawnPoints)
5819 {
5820 Vector3 spawnPoint = sp.GetLocation(telehub.AbsolutePosition, telehub.GroupRotation);
5821 ILandObject land = LandChannel.GetLandObject(spawnPoint.X, spawnPoint.Y);
5822 if (land == null)
5823 continue;
5824 if (land.IsEitherBannedOrRestricted(agentID))
5825 continue;
5826 banned = false;
5827 break;
5828 }
5829
5830 if (banned)
5831 {
5832 if (Permissions.IsAdministrator(agentID) == false || Permissions.IsGridGod(agentID) == false)
5833 {
5834 reason = "No suitable landing point found";
5835 return false;
5836 }
5837 reason = "Administrative access only";
5838 return true;
5839 }
5840 }
5841 }
5182 5842
5183 // This callback allows the PhysicsScene to call back to its caller (the SceneGraph) and 5843 float posX = 128.0f;
5184 // update non-physical objects like the joint proxy objects that represent the position 5844 float posY = 128.0f;
5185 // of the joints in the scene.
5186 5845
5187 // This routine is normally called from within a lock (OdeLock) from within the OdePhysicsScene 5846 if (!TestLandRestrictions(agentID, out reason, ref posX, ref posY))
5188 // WARNING: be careful of deadlocks here if you manipulate the scene. Remember you are being called 5847 {
5189 // from within the OdePhysicsScene. 5848 // m_log.DebugFormat("[SCENE]: Denying {0} because they are banned on all parcels", agentID);
5849 reason = "You are banned from the region on all parcels";
5850 return false;
5851 }
5852 }
5853 else // Walking
5854 {
5855 ILandObject land = LandChannel.GetLandObject(position.X, position.Y);
5856 if (land == null)
5857 {
5858 reason = "No parcel found";
5859 return false;
5860 }
5190 5861
5191 protected internal void jointMoved(PhysicsJoint joint) 5862 bool banned = land.IsBannedFromLand(agentID);
5192 { 5863 bool restricted = land.IsRestrictedFromLand(agentID);
5193 // m_parentScene.PhysicsScene.DumpJointInfo(); // non-thread-locked version; we should already be in a lock (OdeLock) when this callback is invoked
5194 SceneObjectPart jointProxyObject = GetSceneObjectPart(joint.ObjectNameInScene);
5195 if (jointProxyObject == null)
5196 {
5197 jointErrorMessage(joint, "WARNING, joint proxy not found, name " + joint.ObjectNameInScene);
5198 return;
5199 }
5200
5201 // now update the joint proxy object in the scene to have the position of the joint as returned by the physics engine
5202 SceneObjectPart trackedBody = GetSceneObjectPart(joint.TrackedBodyName); // FIXME: causes a sequential lookup
5203 if (trackedBody == null) return; // the actor may have been deleted but the joint still lingers around a few frames waiting for deletion. during this time, trackedBody is NULL to prevent further motion of the joint proxy.
5204 jointProxyObject.Velocity = trackedBody.Velocity;
5205 jointProxyObject.AngularVelocity = trackedBody.AngularVelocity;
5206 switch (joint.Type)
5207 {
5208 case PhysicsJointType.Ball:
5209 {
5210 Vector3 jointAnchor = PhysicsScene.GetJointAnchor(joint);
5211 Vector3 proxyPos = jointAnchor;
5212 jointProxyObject.ParentGroup.UpdateGroupPosition(proxyPos); // schedules the entire group for a terse update
5213 }
5214 break;
5215
5216 case PhysicsJointType.Hinge:
5217 {
5218 Vector3 jointAnchor = PhysicsScene.GetJointAnchor(joint);
5219
5220 // Normally, we would just ask the physics scene to return the axis for the joint.
5221 // Unfortunately, ODE sometimes returns <0,0,0> for the joint axis, which should
5222 // never occur. Therefore we cannot rely on ODE to always return a correct joint axis.
5223 // Therefore the following call does not always work:
5224 //PhysicsVector phyJointAxis = _PhyScene.GetJointAxis(joint);
5225
5226 // instead we compute the joint orientation by saving the original joint orientation
5227 // relative to one of the jointed bodies, and applying this transformation
5228 // to the current position of the jointed bodies (the tracked body) to compute the
5229 // current joint orientation.
5230
5231 if (joint.TrackedBodyName == null)
5232 {
5233 jointErrorMessage(joint, "joint.TrackedBodyName is null, joint " + joint.ObjectNameInScene);
5234 }
5235
5236 Vector3 proxyPos = jointAnchor;
5237 Quaternion q = trackedBody.RotationOffset * joint.LocalRotation;
5238
5239 jointProxyObject.ParentGroup.UpdateGroupPosition(proxyPos); // schedules the entire group for a terse update
5240 jointProxyObject.ParentGroup.UpdateGroupRotationR(q); // schedules the entire group for a terse update
5241 }
5242 break;
5243 }
5244 }
5245
5246 // This callback allows the PhysicsScene to call back to its caller (the SceneGraph) and
5247 // update non-physical objects like the joint proxy objects that represent the position
5248 // of the joints in the scene.
5249
5250 // This routine is normally called from within a lock (OdeLock) from within the OdePhysicsScene
5251 // WARNING: be careful of deadlocks here if you manipulate the scene. Remember you are being called
5252 // from within the OdePhysicsScene.
5253 protected internal void jointDeactivated(PhysicsJoint joint)
5254 {
5255 //m_log.Debug("[NINJA] SceneGraph.jointDeactivated, joint:" + joint.ObjectNameInScene);
5256 SceneObjectPart jointProxyObject = GetSceneObjectPart(joint.ObjectNameInScene);
5257 if (jointProxyObject == null)
5258 {
5259 jointErrorMessage(joint, "WARNING, trying to deactivate (stop interpolation of) joint proxy, but not found, name " + joint.ObjectNameInScene);
5260 return;
5261 }
5262
5263 // turn the proxy non-physical, which also stops its client-side interpolation
5264 bool wasUsingPhysics = ((jointProxyObject.Flags & PrimFlags.Physics) != 0);
5265 if (wasUsingPhysics)
5266 {
5267 jointProxyObject.UpdatePrimFlags(false, false, true, false); // FIXME: possible deadlock here; check to make sure all the scene alterations set into motion here won't deadlock
5268 }
5269 }
5270
5271 // This callback allows the PhysicsScene to call back to its caller (the SceneGraph) and
5272 // alert the user of errors by using the debug channel in the same way that scripts alert
5273 // the user of compile errors.
5274
5275 // This routine is normally called from within a lock (OdeLock) from within the OdePhysicsScene
5276 // WARNING: be careful of deadlocks here if you manipulate the scene. Remember you are being called
5277 // from within the OdePhysicsScene.
5278 public void jointErrorMessage(PhysicsJoint joint, string message)
5279 {
5280 if (joint != null)
5281 {
5282 if (joint.ErrorMessageCount > PhysicsJoint.maxErrorMessages)
5283 return;
5284
5285 SceneObjectPart jointProxyObject = GetSceneObjectPart(joint.ObjectNameInScene);
5286 if (jointProxyObject != null)
5287 {
5288 SimChat(Utils.StringToBytes("[NINJA]: " + message),
5289 ChatTypeEnum.DebugChannel,
5290 2147483647,
5291 jointProxyObject.AbsolutePosition,
5292 jointProxyObject.Name,
5293 jointProxyObject.UUID,
5294 false);
5295
5296 joint.ErrorMessageCount++;
5297
5298 if (joint.ErrorMessageCount > PhysicsJoint.maxErrorMessages)
5299 {
5300 SimChat(Utils.StringToBytes("[NINJA]: Too many messages for this joint, suppressing further messages."),
5301 ChatTypeEnum.DebugChannel,
5302 2147483647,
5303 jointProxyObject.AbsolutePosition,
5304 jointProxyObject.Name,
5305 jointProxyObject.UUID,
5306 false);
5307 }
5308 }
5309 else
5310 {
5311 // couldn't find the joint proxy object; the error message is silently suppressed
5312 }
5313 }
5314 }
5315
5316 public Scene ConsoleScene()
5317 {
5318 if (MainConsole.Instance == null)
5319 return null;
5320 if (MainConsole.Instance.ConsoleScene is Scene)
5321 return (Scene)MainConsole.Instance.ConsoleScene;
5322 return null;
5323 }
5324
5325 // Get terrain height at the specified <x,y> location.
5326 // Presumes the underlying implementation is a heightmap which is a 1m grid.
5327 // Finds heightmap grid points before and after the point and
5328 // does a linear approximation of the height at this intermediate point.
5329 public float GetGroundHeight(float x, float y)
5330 {
5331 if (x < 0)
5332 x = 0;
5333 if (x >= Heightmap.Width)
5334 x = Heightmap.Width - 1;
5335 if (y < 0)
5336 y = 0;
5337 if (y >= Heightmap.Height)
5338 y = Heightmap.Height - 1;
5339
5340 Vector3 p0 = new Vector3(x, y, (float)Heightmap[(int)x, (int)y]);
5341 Vector3 p1 = p0;
5342 Vector3 p2 = p0;
5343
5344 p1.X += 1.0f;
5345 if (p1.X < Heightmap.Width)
5346 p1.Z = (float)Heightmap[(int)p1.X, (int)p1.Y];
5347
5348 p2.Y += 1.0f;
5349 if (p2.Y < Heightmap.Height)
5350 p2.Z = (float)Heightmap[(int)p2.X, (int)p2.Y];
5351
5352 Vector3 v0 = new Vector3(p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z);
5353 Vector3 v1 = new Vector3(p2.X - p0.X, p2.Y - p0.Y, p2.Z - p0.Z);
5354
5355 v0.Normalize();
5356 v1.Normalize();
5357
5358 Vector3 vsn = new Vector3();
5359 vsn.X = (v0.Y * v1.Z) - (v0.Z * v1.Y);
5360 vsn.Y = (v0.Z * v1.X) - (v0.X * v1.Z);
5361 vsn.Z = (v0.X * v1.Y) - (v0.Y * v1.X);
5362 vsn.Normalize();
5363
5364 float xdiff = x - (float)((int)x);
5365 float ydiff = y - (float)((int)y);
5366
5367 return (((vsn.X * xdiff) + (vsn.Y * ydiff)) / (-1 * vsn.Z)) + p0.Z;
5368 }
5369
5370// private void CheckHeartbeat()
5371// {
5372// if (m_firstHeartbeat)
5373// return;
5374//
5375// if (Util.EnvironmentTickCountSubtract(m_lastFrameTick) > 2000)
5376// StartTimer();
5377// }
5378
5379 public override ISceneObject DeserializeObject(string representation)
5380 {
5381 return SceneObjectSerializer.FromXml2Format(representation);
5382 }
5383
5384 public override bool AllowScriptCrossings
5385 {
5386 get { return m_allowScriptCrossings; }
5387 }
5388
5389 public Vector3 GetNearestAllowedPosition(ScenePresence avatar)
5390 {
5391 return GetNearestAllowedPosition(avatar, null);
5392 }
5393
5394 public Vector3 GetNearestAllowedPosition(ScenePresence avatar, ILandObject excludeParcel)
5395 {
5396 ILandObject nearestParcel = GetNearestAllowedParcel(avatar.UUID, avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y, excludeParcel);
5397 5864
5398 if (nearestParcel != null) 5865 if (banned || restricted)
5399 { 5866 {
5400 Vector3 dir = Vector3.Normalize(Vector3.Multiply(avatar.Velocity, -1)); 5867 if (banned)
5401 //Try to get a location that feels like where they came from 5868 reason = "You are banned from the parcel";
5402 Vector3? nearestPoint = GetNearestPointInParcelAlongDirectionFromPoint(avatar.AbsolutePosition, dir, nearestParcel); 5869 else
5403 if (nearestPoint != null) 5870 reason = "The parcel is restricted";
5404 { 5871 return false;
5405 m_log.Debug("Found a sane previous position based on velocity, sending them to: " + nearestPoint.ToString()); 5872 }
5406 return nearestPoint.Value; 5873 }
5407 } 5874
5408 5875 reason = String.Empty;
5409 //Sometimes velocity might be zero (local teleport), so try finding point along path from avatar to center of nearest parcel 5876 return true;
5410 Vector3 directionToParcelCenter = Vector3.Subtract(GetParcelCenterAtGround(nearestParcel), avatar.AbsolutePosition); 5877 }
5411 dir = Vector3.Normalize(directionToParcelCenter); 5878
5412 nearestPoint = GetNearestPointInParcelAlongDirectionFromPoint(avatar.AbsolutePosition, dir, nearestParcel); 5879 /// <summary>
5413 if (nearestPoint != null) 5880 /// This method deals with movement when an avatar is automatically moving (but this is distinct from the
5414 { 5881 /// autopilot that moves an avatar to a sit target!.
5415 m_log.Debug("They had a zero velocity, sending them to: " + nearestPoint.ToString()); 5882 /// </summary>
5416 return nearestPoint.Value; 5883 /// <remarks>
5417 } 5884 /// This is not intended as a permament location for this method.
5418 5885 /// </remarks>
5419 ILandObject dest = LandChannel.GetLandObject(avatar.lastKnownAllowedPosition.X, avatar.lastKnownAllowedPosition.Y); 5886 /// <param name="presence"></param>
5420 if (dest != excludeParcel) 5887 private void HandleOnSignificantClientMovement(ScenePresence presence)
5421 { 5888 {
5422 // Ultimate backup if we have no idea where they are and 5889 if (presence.MovingToTarget)
5423 // the last allowed position was in another parcel 5890 {
5424 m_log.Debug("Have no idea where they are, sending them to: " + avatar.lastKnownAllowedPosition.ToString()); 5891 double distanceToTarget = Util.GetDistanceTo(presence.AbsolutePosition, presence.MoveToPositionTarget);
5425 return avatar.lastKnownAllowedPosition; 5892 // m_log.DebugFormat(
5426 } 5893 // "[SCENE]: Abs pos of {0} is {1}, target {2}, distance {3}",
5427 5894 // presence.Name, presence.AbsolutePosition, presence.MoveToPositionTarget, distanceToTarget);
5428 // else fall through to region edge 5895
5429 } 5896 // Check the error term of the current position in relation to the target position
5430 5897 if (distanceToTarget <= ScenePresence.SIGNIFICANT_MOVEMENT)
5431 //Go to the edge, this happens in teleporting to a region with no available parcels 5898 {
5432 Vector3 nearestRegionEdgePoint = GetNearestRegionEdgePosition(avatar); 5899 // We are close enough to the target
5433 5900 // m_log.DebugFormat("[SCENEE]: Stopping autopilot of {0}", presence.Name);
5434 //m_log.Debug("They are really in a place they don't belong, sending them to: " + nearestRegionEdgePoint.ToString()); 5901
5435 5902 presence.Velocity = Vector3.Zero;
5436 return nearestRegionEdgePoint; 5903 presence.AbsolutePosition = presence.MoveToPositionTarget;
5437 } 5904 presence.ResetMoveToTarget();
5438 5905
5439 private Vector3 GetParcelCenterAtGround(ILandObject parcel) 5906 if (presence.Flying)
5440 { 5907 {
5441 Vector2 center = GetParcelCenter(parcel); 5908 // A horrible hack to stop the avatar dead in its tracks rather than having them overshoot
5442 return GetPositionAtGround(center.X, center.Y); 5909 // the target if flying.
5443 } 5910 // We really need to be more subtle (slow the avatar as it approaches the target) or at
5444 5911 // least be able to set collision status once, rather than 5 times to give it enough
5445 private Vector3? GetNearestPointInParcelAlongDirectionFromPoint(Vector3 pos, Vector3 direction, ILandObject parcel) 5912 // weighting so that that PhysicsActor thinks it really is colliding.
5446 { 5913 for (int i = 0; i < 5; i++)
5447 Vector3 unitDirection = Vector3.Normalize(direction); 5914 presence.IsColliding = true;
5448 //Making distance to search go through some sane limit of distance 5915
5449 for (float distance = 0; distance < Math.Max(RegionInfo.RegionSizeX, RegionInfo.RegionSizeY) * 2; distance += .5f) 5916 if (presence.LandAtTarget)
5450 { 5917 presence.Flying = false;
5451 Vector3 testPos = Vector3.Add(pos, Vector3.Multiply(unitDirection, distance)); 5918
5452 if (parcel.ContainsPoint((int)testPos.X, (int)testPos.Y)) 5919 // Vector3 targetPos = presence.MoveToPositionTarget;
5453 { 5920 // float terrainHeight = (float)presence.Scene.Heightmap[(int)targetPos.X, (int)targetPos.Y];
5454 return testPos; 5921 // if (targetPos.Z - terrainHeight < 0.2)
5455 } 5922 // {
5923 // presence.Flying = false;
5924 // }
5925 }
5926
5927 // m_log.DebugFormat(
5928 // "[SCENE]: AgentControlFlags {0}, MovementFlag {1} for {2}",
5929 // presence.AgentControlFlags, presence.MovementFlag, presence.Name);
5456 } 5930 }
5457 return null;
5458 }
5459
5460 public ILandObject GetNearestAllowedParcel(UUID avatarId, float x, float y)
5461 {
5462 return GetNearestAllowedParcel(avatarId, x, y, null);
5463 }
5464
5465 public ILandObject GetNearestAllowedParcel(UUID avatarId, float x, float y, ILandObject excludeParcel)
5466 {
5467 List<ILandObject> all = AllParcels();
5468 float minParcelDistance = float.MaxValue;
5469 ILandObject nearestParcel = null;
5470
5471 foreach (var parcel in all)
5472 {
5473 if (!parcel.IsEitherBannedOrRestricted(avatarId) && parcel != excludeParcel)
5474 {
5475 float parcelDistance = GetParcelDistancefromPoint(parcel, x, y);
5476 if (parcelDistance < minParcelDistance)
5477 {
5478 minParcelDistance = parcelDistance;
5479 nearestParcel = parcel;
5480 }
5481 }
5482 }
5483
5484 return nearestParcel;
5485 }
5486
5487 private List<ILandObject> AllParcels()
5488 {
5489 return LandChannel.AllParcels();
5490 }
5491
5492 private float GetParcelDistancefromPoint(ILandObject parcel, float x, float y)
5493 {
5494 return Vector2.Distance(new Vector2(x, y), GetParcelCenter(parcel));
5495 }
5496
5497 //calculate the average center point of a parcel
5498 private Vector2 GetParcelCenter(ILandObject parcel)
5499 {
5500 int count = 0;
5501 int avgx = 0;
5502 int avgy = 0;
5503 for (int x = 0; x < RegionInfo.RegionSizeX; x++)
5504 {
5505 for (int y = 0; y < RegionInfo.RegionSizeY; y++)
5506 {
5507 //Just keep a running average as we check if all the points are inside or not
5508 if (parcel.ContainsPoint(x, y))
5509 {
5510 if (count == 0)
5511 {
5512 avgx = x;
5513 avgy = y;
5514 }
5515 else
5516 {
5517 avgx = (avgx * count + x) / (count + 1);
5518 avgy = (avgy * count + y) / (count + 1);
5519 }
5520 count += 1;
5521 }
5522 }
5523 }
5524 return new Vector2(avgx, avgy);
5525 }
5526
5527 private Vector3 GetNearestRegionEdgePosition(ScenePresence avatar)
5528 {
5529 float xdistance = avatar.AbsolutePosition.X < RegionInfo.RegionSizeX / 2
5530 ? avatar.AbsolutePosition.X : RegionInfo.RegionSizeX - avatar.AbsolutePosition.X;
5531 float ydistance = avatar.AbsolutePosition.Y < RegionInfo.RegionSizeY / 2
5532 ? avatar.AbsolutePosition.Y : RegionInfo.RegionSizeY - avatar.AbsolutePosition.Y;
5533
5534 //find out what vertical edge to go to
5535 if (xdistance < ydistance)
5536 {
5537 if (avatar.AbsolutePosition.X < RegionInfo.RegionSizeX / 2)
5538 {
5539 return GetPositionAtAvatarHeightOrGroundHeight(avatar, 0.0f, avatar.AbsolutePosition.Y);
5540 }
5541 else
5542 {
5543 return GetPositionAtAvatarHeightOrGroundHeight(avatar, RegionInfo.RegionSizeY, avatar.AbsolutePosition.Y);
5544 }
5545 }
5546 //find out what horizontal edge to go to
5547 else 5931 else
5548 { 5932 {
5549 if (avatar.AbsolutePosition.Y < RegionInfo.RegionSizeY / 2) 5933 // m_log.DebugFormat(
5550 { 5934 // "[SCENE]: Updating npc {0} at {1} for next movement to {2}",
5551 return GetPositionAtAvatarHeightOrGroundHeight(avatar, avatar.AbsolutePosition.X, 0.0f); 5935 // presence.Name, presence.AbsolutePosition, presence.MoveToPositionTarget);
5552 }
5553 else
5554 {
5555 return GetPositionAtAvatarHeightOrGroundHeight(avatar, avatar.AbsolutePosition.X, RegionInfo.RegionSizeY);
5556 }
5557 }
5558 }
5559
5560 private Vector3 GetPositionAtAvatarHeightOrGroundHeight(ScenePresence avatar, float x, float y)
5561 {
5562 Vector3 ground = GetPositionAtGround(x, y);
5563 if (avatar.AbsolutePosition.Z > ground.Z)
5564 {
5565 ground.Z = avatar.AbsolutePosition.Z;
5566 }
5567 return ground;
5568 }
5569
5570 private Vector3 GetPositionAtGround(float x, float y)
5571 {
5572 return new Vector3(x, y, GetGroundHeight(x, y));
5573 }
5574
5575 public List<UUID> GetEstateRegions(int estateID)
5576 {
5577 IEstateDataService estateDataService = EstateDataService;
5578 if (estateDataService == null)
5579 return new List<UUID>(0);
5580
5581 return estateDataService.GetRegions(estateID);
5582 }
5583
5584 public void ReloadEstateData()
5585 {
5586 IEstateDataService estateDataService = EstateDataService;
5587 if (estateDataService != null)
5588 {
5589 RegionInfo.EstateSettings = estateDataService.LoadEstateSettings(RegionInfo.RegionID, false);
5590 TriggerEstateSunUpdate();
5591 }
5592 }
5593
5594 public void TriggerEstateSunUpdate()
5595 {
5596 EventManager.TriggerEstateToolsSunUpdate(RegionInfo.RegionHandle);
5597 }
5598
5599 private void HandleReloadEstate(string module, string[] cmd)
5600 {
5601 if (MainConsole.Instance.ConsoleScene == null ||
5602 (MainConsole.Instance.ConsoleScene is Scene &&
5603 (Scene)MainConsole.Instance.ConsoleScene == this))
5604 {
5605 ReloadEstateData();
5606 }
5607 }
5608
5609 /// <summary>
5610 /// Get the volume of space that will encompass all the given objects.
5611 /// </summary>
5612 /// <param name="objects"></param>
5613 /// <param name="minX"></param>
5614 /// <param name="maxX"></param>
5615 /// <param name="minY"></param>
5616 /// <param name="maxY"></param>
5617 /// <param name="minZ"></param>
5618 /// <param name="maxZ"></param>
5619 /// <returns></returns>
5620 public static Vector3[] GetCombinedBoundingBox(
5621 List<SceneObjectGroup> objects,
5622 out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ)
5623 {
5624 minX = float.MaxValue;
5625 maxX = float.MinValue;
5626 minY = float.MaxValue;
5627 maxY = float.MinValue;
5628 minZ = float.MaxValue;
5629 maxZ = float.MinValue;
5630
5631 List<Vector3> offsets = new List<Vector3>();
5632
5633 foreach (SceneObjectGroup g in objects)
5634 {
5635 float ominX, ominY, ominZ, omaxX, omaxY, omaxZ;
5636
5637 Vector3 vec = g.AbsolutePosition;
5638
5639 g.GetAxisAlignedBoundingBoxRaw(out ominX, out omaxX, out ominY, out omaxY, out ominZ, out omaxZ);
5640
5641// m_log.DebugFormat(
5642// "[SCENE]: For {0} found AxisAlignedBoundingBoxRaw {1}, {2}",
5643// g.Name, new Vector3(ominX, ominY, ominZ), new Vector3(omaxX, omaxY, omaxZ));
5644
5645 ominX += vec.X;
5646 omaxX += vec.X;
5647 ominY += vec.Y;
5648 omaxY += vec.Y;
5649 ominZ += vec.Z;
5650 omaxZ += vec.Z;
5651
5652 if (minX > ominX)
5653 minX = ominX;
5654 if (minY > ominY)
5655 minY = ominY;
5656 if (minZ > ominZ)
5657 minZ = ominZ;
5658 if (maxX < omaxX)
5659 maxX = omaxX;
5660 if (maxY < omaxY)
5661 maxY = omaxY;
5662 if (maxZ < omaxZ)
5663 maxZ = omaxZ;
5664 }
5665
5666 foreach (SceneObjectGroup g in objects)
5667 {
5668 Vector3 vec = g.AbsolutePosition;
5669 vec.X -= minX;
5670 vec.Y -= minY;
5671 vec.Z -= minZ;
5672
5673 offsets.Add(vec);
5674 }
5675
5676 return offsets.ToArray();
5677 }
5678
5679 /// <summary>
5680 /// Regenerate the maptile for this scene.
5681 /// </summary>
5682 /// <param name="sender"></param>
5683 /// <param name="e"></param>
5684 private void RegenerateMaptile()
5685 {
5686 IWorldMapModule mapModule = RequestModuleInterface<IWorldMapModule>();
5687 if (mapModule != null)
5688 mapModule.GenerateMaptile();
5689 }
5690
5691 private void RegenerateMaptileAndReregister(object sender, ElapsedEventArgs e)
5692 {
5693 RegenerateMaptile();
5694 5936
5695 // We need to propagate the new image UUID to the grid service 5937 Vector3 agent_control_v3 = new Vector3();
5696 // so that all simulators can retrieve it 5938 presence.HandleMoveToTargetUpdate(1, ref agent_control_v3);
5697 string error = GridService.RegisterRegion(RegionInfo.ScopeID, new GridRegion(RegionInfo)); 5939 presence.AddNewMovement(agent_control_v3);
5698 if (error != string.Empty) 5940 }
5699 throw new Exception(error); 5941 }
5700 } 5942 }
5701 5943
5702 /// <summary> 5944 // manage and select spawn points in sequence
5703 /// This method is called across the simulation connector to 5945 public int SpawnPoint()
5704 /// determine if a given agent is allowed in this region 5946 {
5705 /// AS A ROOT AGENT 5947 int spawnpoints = RegionInfo.RegionSettings.SpawnPoints().Count;
5706 /// </summary>
5707 /// <remarks>
5708 /// Returning false here will prevent them
5709 /// from logging into the region, teleporting into the region
5710 /// or corssing the broder walking, but will NOT prevent
5711 /// child agent creation, thereby emulating the SL behavior.
5712 /// </remarks>
5713 /// <param name='agentID'>The visitor's User ID</param>
5714 /// <param name="agentHomeURI">The visitor's Home URI (may be null)</param>
5715 /// <param name='position'></param>
5716 /// <param name='reason'></param>
5717 /// <returns></returns>
5718 public bool QueryAccess(UUID agentID, string agentHomeURI, bool viaTeleport, Vector3 position, out string reason)
5719 {
5720 reason = string.Empty;
5721 5948
5722 if (Permissions.IsGod(agentID)) 5949 if (spawnpoints == 0)
5723 { 5950 return 0;
5724 reason = String.Empty;
5725 return true;
5726 }
5727 5951
5728 if (!AllowAvatarCrossing && !viaTeleport) 5952 m_SpawnPoint++;
5729 return false; 5953 if (m_SpawnPoint > spawnpoints)
5954 m_SpawnPoint = 1;
5955 return m_SpawnPoint - 1;
5956 }
5730 5957
5731 // FIXME: Root agent count is currently known to be inaccurate. This forces a recount before we check. 5958 /// <summary>
5732 // However, the long term fix is to make sure root agent count is always accurate. 5959 /// Wrappers to get physics modules retrieve assets.
5733 m_sceneGraph.RecalculateStats(); 5960 /// </summary>
5961 /// <remarks>
5962 /// Has to be done this way
5963 /// because we can't assign the asset service to physics directly - at the
5964 /// time physics are instantiated it's not registered but it will be by
5965 /// the time the first prim exists.
5966 /// </remarks>
5967 /// <param name="assetID"></param>
5968 /// <param name="callback"></param>
5969 public void PhysicsRequestAsset(UUID assetID, AssetReceivedDelegate callback)
5970 {
5971 AssetService.Get(assetID.ToString(), callback, PhysicsAssetReceived);
5972 }
5734 5973
5735 int num = m_sceneGraph.GetRootAgentCount(); 5974 private void PhysicsAssetReceived(string id, Object sender, AssetBase asset)
5975 {
5976 AssetReceivedDelegate callback = (AssetReceivedDelegate)sender;
5736 5977
5737 if (num >= RegionInfo.RegionSettings.AgentLimit) 5978 callback(asset);
5738 { 5979 }
5739 if (!Permissions.IsAdministrator(agentID))
5740 {
5741 reason = "The region is full";
5742 5980
5743 m_log.DebugFormat( 5981 public string GetExtraSetting(string name)
5744 "[SCENE]: Denying presence with id {0} entry into {1} since region is at agent limit of {2}", 5982 {
5745 agentID, RegionInfo.RegionName, RegionInfo.RegionSettings.AgentLimit); 5983 if (m_extraSettings == null)
5984 return String.Empty;
5746 5985
5747 return false; 5986 string val;
5748 }
5749 }
5750 5987
5751 ScenePresence presence = GetScenePresence(agentID); 5988 if (!m_extraSettings.TryGetValue(name, out val))
5752 IClientAPI client = null; 5989 return String.Empty;
5753 AgentCircuitData aCircuit = null;
5754 5990
5755 if (presence != null) 5991 return val;
5756 { 5992 }
5757 client = presence.ControllingClient;
5758 if (client != null)
5759 aCircuit = client.RequestClientInfo();
5760 }
5761 5993
5762 // We may be called before there is a presence or a client. 5994 public void StoreExtraSetting(string name, string val)
5763 // Fake AgentCircuitData to keep IAuthorizationModule smiling 5995 {
5764 if (client == null) 5996 if (m_extraSettings == null)
5765 { 5997 return;
5766 aCircuit = new AgentCircuitData();
5767 aCircuit.AgentID = agentID;
5768 aCircuit.firstname = String.Empty;
5769 aCircuit.lastname = String.Empty;
5770 }
5771 5998
5772 try 5999 string oldVal;
5773 {
5774 if (!AuthorizeUser(aCircuit, false, out reason))
5775 {
5776 //m_log.DebugFormat("[SCENE]: Denying access for {0}", agentID);
5777 return false;
5778 }
5779 }
5780 catch (Exception e)
5781 {
5782 m_log.DebugFormat("[SCENE]: Exception authorizing agent: {0} "+ e.StackTrace, e.Message);
5783 reason = "Error authorizing agent: " + e.Message;
5784 return false;
5785 }
5786
5787 if (viaTeleport)
5788 {
5789 if (!RegionInfo.EstateSettings.AllowDirectTeleport)
5790 {
5791 SceneObjectGroup telehub;
5792 if (RegionInfo.RegionSettings.TelehubObject != UUID.Zero && (telehub = GetSceneObjectGroup(RegionInfo.RegionSettings.TelehubObject)) != null)
5793 {
5794 List<SpawnPoint> spawnPoints = RegionInfo.RegionSettings.SpawnPoints();
5795 bool banned = true;
5796 foreach (SpawnPoint sp in spawnPoints)
5797 {
5798 Vector3 spawnPoint = sp.GetLocation(telehub.AbsolutePosition, telehub.GroupRotation);
5799 ILandObject land = LandChannel.GetLandObject(spawnPoint.X, spawnPoint.Y);
5800 if (land == null)
5801 continue;
5802 if (land.IsEitherBannedOrRestricted(agentID))
5803 continue;
5804 banned = false;
5805 break;
5806 }
5807
5808 if (banned)
5809 {
5810 if(Permissions.IsAdministrator(agentID) == false || Permissions.IsGridGod(agentID) == false)
5811 {
5812 reason = "No suitable landing point found";
5813 return false;
5814 }
5815 reason = "Administrative access only";
5816 return true;
5817 }
5818 }
5819 }
5820
5821 float posX = 128.0f;
5822 float posY = 128.0f;
5823
5824 if (!TestLandRestrictions(agentID, out reason, ref posX, ref posY))
5825 {
5826 // m_log.DebugFormat("[SCENE]: Denying {0} because they are banned on all parcels", agentID);
5827 reason = "You are banned from the region on all parcels";
5828 return false;
5829 }
5830 }
5831 else // Walking
5832 {
5833 ILandObject land = LandChannel.GetLandObject(position.X, position.Y);
5834 if (land == null)
5835 {
5836 reason = "No parcel found";
5837 return false;
5838 }
5839
5840 bool banned = land.IsBannedFromLand(agentID);
5841 bool restricted = land.IsRestrictedFromLand(agentID);
5842
5843 if (banned || restricted)
5844 {
5845 if (banned)
5846 reason = "You are banned from the parcel";
5847 else
5848 reason = "The parcel is restricted";
5849 return false;
5850 }
5851 }
5852 6000
5853 reason = String.Empty; 6001 if (m_extraSettings.TryGetValue(name, out oldVal))
5854 return true; 6002 {
5855 } 6003 if (oldVal == val)
5856 6004 return;
5857 /// <summary> 6005 }
5858 /// This method deals with movement when an avatar is automatically moving (but this is distinct from the 6006
5859 /// autopilot that moves an avatar to a sit target!. 6007 m_extraSettings[name] = val;
5860 /// </summary> 6008
5861 /// <remarks> 6009 m_SimulationDataService.SaveExtra(RegionInfo.RegionID, name, val);
5862 /// This is not intended as a permament location for this method. 6010
5863 /// </remarks> 6011 m_eventManager.TriggerExtraSettingChanged(this, name, val);
5864 /// <param name="presence"></param> 6012 }
5865 private void HandleOnSignificantClientMovement(ScenePresence presence) 6013
5866 { 6014 public void RemoveExtraSetting(string name)
5867 if (presence.MovingToTarget) 6015 {
5868 { 6016 if (m_extraSettings == null)
5869 double distanceToTarget = Util.GetDistanceTo(presence.AbsolutePosition, presence.MoveToPositionTarget); 6017 return;
5870// m_log.DebugFormat( 6018
5871// "[SCENE]: Abs pos of {0} is {1}, target {2}, distance {3}", 6019 if (!m_extraSettings.ContainsKey(name))
5872// presence.Name, presence.AbsolutePosition, presence.MoveToPositionTarget, distanceToTarget); 6020 return;
5873
5874 // Check the error term of the current position in relation to the target position
5875 if (distanceToTarget <= ScenePresence.SIGNIFICANT_MOVEMENT)
5876 {
5877 // We are close enough to the target
5878// m_log.DebugFormat("[SCENEE]: Stopping autopilot of {0}", presence.Name);
5879
5880 presence.Velocity = Vector3.Zero;
5881 presence.AbsolutePosition = presence.MoveToPositionTarget;
5882 presence.ResetMoveToTarget();
5883
5884 if (presence.Flying)
5885 {
5886 // A horrible hack to stop the avatar dead in its tracks rather than having them overshoot
5887 // the target if flying.
5888 // We really need to be more subtle (slow the avatar as it approaches the target) or at
5889 // least be able to set collision status once, rather than 5 times to give it enough
5890 // weighting so that that PhysicsActor thinks it really is colliding.
5891 for (int i = 0; i < 5; i++)
5892 presence.IsColliding = true;
5893
5894 if (presence.LandAtTarget)
5895 presence.Flying = false;
5896
5897// Vector3 targetPos = presence.MoveToPositionTarget;
5898// float terrainHeight = (float)presence.Scene.Heightmap[(int)targetPos.X, (int)targetPos.Y];
5899// if (targetPos.Z - terrainHeight < 0.2)
5900// {
5901// presence.Flying = false;
5902// }
5903 }
5904
5905// m_log.DebugFormat(
5906// "[SCENE]: AgentControlFlags {0}, MovementFlag {1} for {2}",
5907// presence.AgentControlFlags, presence.MovementFlag, presence.Name);
5908 }
5909 else
5910 {
5911// m_log.DebugFormat(
5912// "[SCENE]: Updating npc {0} at {1} for next movement to {2}",
5913// presence.Name, presence.AbsolutePosition, presence.MoveToPositionTarget);
5914
5915 Vector3 agent_control_v3 = new Vector3();
5916 presence.HandleMoveToTargetUpdate(1, ref agent_control_v3);
5917 presence.AddNewMovement(agent_control_v3);
5918 }
5919 }
5920 }
5921
5922 // manage and select spawn points in sequence
5923 public int SpawnPoint()
5924 {
5925 int spawnpoints = RegionInfo.RegionSettings.SpawnPoints().Count;
5926
5927 if (spawnpoints == 0)
5928 return 0;
5929
5930 m_SpawnPoint++;
5931 if (m_SpawnPoint > spawnpoints)
5932 m_SpawnPoint = 1;
5933 return m_SpawnPoint - 1;
5934 }
5935
5936 /// <summary>
5937 /// Wrappers to get physics modules retrieve assets.
5938 /// </summary>
5939 /// <remarks>
5940 /// Has to be done this way
5941 /// because we can't assign the asset service to physics directly - at the
5942 /// time physics are instantiated it's not registered but it will be by
5943 /// the time the first prim exists.
5944 /// </remarks>
5945 /// <param name="assetID"></param>
5946 /// <param name="callback"></param>
5947 public void PhysicsRequestAsset(UUID assetID, AssetReceivedDelegate callback)
5948 {
5949 AssetService.Get(assetID.ToString(), callback, PhysicsAssetReceived);
5950 }
5951
5952 private void PhysicsAssetReceived(string id, Object sender, AssetBase asset)
5953 {
5954 AssetReceivedDelegate callback = (AssetReceivedDelegate)sender;
5955
5956 callback(asset);
5957 }
5958
5959 public string GetExtraSetting(string name)
5960 {
5961 if (m_extraSettings == null)
5962 return String.Empty;
5963
5964 string val;
5965
5966 if (!m_extraSettings.TryGetValue(name, out val))
5967 return String.Empty;
5968
5969 return val;
5970 }
5971
5972 public void StoreExtraSetting(string name, string val)
5973 {
5974 if (m_extraSettings == null)
5975 return;
5976
5977 string oldVal;
5978
5979 if (m_extraSettings.TryGetValue(name, out oldVal))
5980 {
5981 if (oldVal == val)
5982 return;
5983 }
5984
5985 m_extraSettings[name] = val;
5986
5987 m_SimulationDataService.SaveExtra(RegionInfo.RegionID, name, val);
5988
5989 m_eventManager.TriggerExtraSettingChanged(this, name, val);
5990 }
5991
5992 public void RemoveExtraSetting(string name)
5993 {
5994 if (m_extraSettings == null)
5995 return;
5996 6021
5997 if (!m_extraSettings.ContainsKey(name)) 6022 m_extraSettings.Remove(name);
5998 return;
5999
6000 m_extraSettings.Remove(name);
6001 6023
6002 m_SimulationDataService.RemoveExtra(RegionInfo.RegionID, name); 6024 m_SimulationDataService.RemoveExtra(RegionInfo.RegionID, name);
6003 6025
6004 m_eventManager.TriggerExtraSettingChanged(this, name, String.Empty); 6026 m_eventManager.TriggerExtraSettingChanged(this, name, String.Empty);
6005 } 6027 }
6006 } 6028 }
6007} 6029}
diff --git a/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs b/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs
index b6da636..07d5f04 100755
--- a/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs
+++ b/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs
@@ -63,7 +63,7 @@ namespace OpenSim.Region.Framework.Scenes
63 63
64 // Determines the size of the array that is used to collect StatBlocks 64 // Determines the size of the array that is used to collect StatBlocks
65 // for sending to the SimStats and SimExtraStatsCollector 65 // for sending to the SimStats and SimExtraStatsCollector
66 private const int m_statisticArraySize = 26; 66 private const int m_statisticArraySize = 27;
67 67
68 /// <summary> 68 /// <summary>
69 /// These are the IDs of stats sent in the StatsPacket to the viewer. 69 /// These are the IDs of stats sent in the StatsPacket to the viewer.
@@ -109,10 +109,11 @@ namespace OpenSim.Region.Framework.Scenes
109 SimSpareMs = 32, 109 SimSpareMs = 32,
110 SimSleepMs = 33, 110 SimSleepMs = 33,
111 SimIoPumpTime = 34, 111 SimIoPumpTime = 34,
112 UsersLoggingIn = 35, 112 FrameDilation = 35,
113 TotalGeoPrim = 36, 113 UsersLoggingIn = 36,
114 TotalMesh = 37, 114 TotalGeoPrim = 37,
115 ThreadCount = 38 115 TotalMesh = 38,
116 ThreadCount = 39
116 } 117 }
117 118
118 /// <summary> 119 /// <summary>
@@ -348,7 +349,7 @@ namespace OpenSim.Region.Framework.Scenes
348 double simulationSumFrameTime; 349 double simulationSumFrameTime;
349 double physicsSumFrameTime; 350 double physicsSumFrameTime;
350 double networkSumFrameTime; 351 double networkSumFrameTime;
351 float timeDilation; 352 float frameDilation;
352 int currentFrame; 353 int currentFrame;
353 354
354 if (!m_scene.Active) 355 if (!m_scene.Active)
@@ -466,16 +467,14 @@ namespace OpenSim.Region.Framework.Scenes
466 else 467 else
467 currentFrame = m_nextLocation - 1; 468 currentFrame = m_nextLocation - 1;
468 469
469 // Calculate the time dilation; which is currently based on the ratio between the sum of the 470 // Calculate the frame dilation; which is currently based on the ratio between the sum of the
470 // physics and simulation rate, and the set minimum time to run the scene's update; minFrameTime 471 // physics and simulation rate, and the set minimum time to run a scene's frame
471 // is given in seconds so multiply by 1000 to convert it to milliseconds 472 frameDilation = (float)(m_simulationFrameTimeMilliseconds[currentFrame] +
472 timeDilation = (float)(m_simulationFrameTimeMilliseconds[currentFrame] + 473 m_physicsFrameTimeMilliseconds[currentFrame]) / m_scene.MinFrameTicks;
473 m_physicsFrameTimeMilliseconds[currentFrame]) / (m_scene.MinFrameTime * 1000);
474 474
475 // ORIGINAL code commented out until we have time to add our own 475 // ORIGINAL code commented out until we have time to add our own
476 sb[0].StatID = (uint) Stats.TimeDilation; 476 sb[0].StatID = (uint) Stats.TimeDilation;
477 //sb[0].StatValue = (Single.IsNaN(m_timeDilation)) ? 0.1f : m_timeDilation ; //((((m_timeDilation + (0.10f * statsUpdateFactor)) /10) / statsUpdateFactor)); 477 sb[0].StatValue = (Single.IsNaN(m_timeDilation)) ? 0.1f : m_timeDilation ; //((((m_timeDilation + (0.10f * statsUpdateFactor)) /10) / statsUpdateFactor));
478 sb[0].StatValue = timeDilation;
479 478
480 sb[1].StatID = (uint) Stats.SimFPS; 479 sb[1].StatID = (uint) Stats.SimFPS;
481 sb[1].StatValue = reportedFPS / m_statsUpdateFactor; 480 sb[1].StatValue = reportedFPS / m_statsUpdateFactor;
@@ -547,23 +546,26 @@ namespace OpenSim.Region.Framework.Scenes
547 sb[21].StatID = (uint)Stats.SimSpareMs; 546 sb[21].StatID = (uint)Stats.SimSpareMs;
548 sb[21].StatValue = m_spareMS / framesUpdated; 547 sb[21].StatValue = m_spareMS / framesUpdated;
549 548
550 // Added to track the number of users currently attempting to 549 // Current ratio between the sum of physics and sim rate, and the
551 // login to the region 550 // minimum time to run a scene's frame
552 sb[22].StatID = (uint)Stats.UsersLoggingIn; 551 sb[22].StatID = (uint)Stats.FrameDilation;
553 sb[22].StatValue = m_usersLoggingIn; 552 sb[22].StatValue = frameDilation;
553
554 // Current number of users currently attemptint to login to region
555 sb[23].StatID = (uint)Stats.UsersLoggingIn;
556 sb[23].StatValue = m_usersLoggingIn;
554 557
555 // Total number of geometric primitives in the scene 558 // Total number of geometric primitives in the scene
556 sb[23].StatID = (uint)Stats.TotalGeoPrim; 559 sb[24].StatID = (uint)Stats.TotalGeoPrim;
557 sb[23].StatValue = m_numGeoPrim; 560 sb[24].StatValue = m_numGeoPrim;
558 561
559 // Total number of mesh objects in the scene 562 // Total number of mesh objects in the scene
560 sb[24].StatID = (uint)Stats.TotalMesh; 563 sb[25].StatID = (uint)Stats.TotalMesh;
561 sb[24].StatValue = m_numMesh; 564 sb[25].StatValue = m_numMesh;
562 565
563 // Added to track the current number of threads that XEngine is 566 // Current number of threads that XEngine is using
564 // using 567 sb[26].StatID = (uint)Stats.ThreadCount;
565 sb[25].StatID = (uint)Stats.ThreadCount; 568 sb[26].StatValue = m_inUseThreads;
566 sb[25].StatValue = m_inUseThreads;
567 569
568 for (int i = 0; i < m_statisticArraySize; i++) 570 for (int i = 0; i < m_statisticArraySize; i++)
569 { 571 {