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