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