opensim – Blame information for rev 1

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