clockwerk-opensim – Blame information for rev 1

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