aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Environment/Scenes/Scene.cs
diff options
context:
space:
mode:
authorDr Scofield2009-02-06 16:55:34 +0000
committerDr Scofield2009-02-06 16:55:34 +0000
commit9b66108081a8c8cf79faaa6c541554091c40850e (patch)
tree095a232ae5a9de3a9244bcd34da08294f61eeea5 /OpenSim/Region/Environment/Scenes/Scene.cs
parent* removed superfluous constants class (diff)
downloadopensim-SC_OLD-9b66108081a8c8cf79faaa6c541554091c40850e.zip
opensim-SC_OLD-9b66108081a8c8cf79faaa6c541554091c40850e.tar.gz
opensim-SC_OLD-9b66108081a8c8cf79faaa6c541554091c40850e.tar.bz2
opensim-SC_OLD-9b66108081a8c8cf79faaa6c541554091c40850e.tar.xz
This changeset is the step 1 of 2 in refactoring
OpenSim.Region.Environment into a "framework" part and a modules only part. This first changeset refactors OpenSim.Region.Environment.Scenes, OpenSim.Region.Environment.Interfaces, and OpenSim.Region.Interfaces into OpenSim.Region.Framework.{Interfaces,Scenes} leaving only region modules in OpenSim.Region.Environment. The next step will be to move region modules up from OpenSim.Region.Environment.Modules to OpenSim.Region.CoreModules and then sort out which modules are really core modules and which should move out to forge. I've been very careful to NOT BREAK anything. i hope i've succeeded. as this is the work of a whole week i hope i managed to keep track with the applied patches of the last week --- could any of you that did check in stuff have a look at whether it survived? thx!
Diffstat (limited to 'OpenSim/Region/Environment/Scenes/Scene.cs')
-rw-r--r--OpenSim/Region/Environment/Scenes/Scene.cs4237
1 files changed, 0 insertions, 4237 deletions
diff --git a/OpenSim/Region/Environment/Scenes/Scene.cs b/OpenSim/Region/Environment/Scenes/Scene.cs
deleted file mode 100644
index f798a0e..0000000
--- a/OpenSim/Region/Environment/Scenes/Scene.cs
+++ /dev/null
@@ -1,4237 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Drawing;
31using System.Drawing.Imaging;
32using System.IO;
33using System.Xml;
34using System.Threading;
35using System.Timers;
36using OpenMetaverse;
37using OpenMetaverse.Imaging;
38using OpenMetaverse.Packets;
39using OpenSim.Framework;
40using OpenSim.Framework.Communications;
41using OpenSim.Framework.Communications.Cache;
42using OpenSim.Framework.Servers;
43using OpenSim.Region.Environment.Interfaces;
44using OpenSim.Region.Interfaces;
45using OpenSim.Region.Environment.Modules.World.Terrain;
46using OpenSim.Region.Environment.Scenes.Scripting;
47using OpenSim.Region.Physics.Manager;
48using Nini.Config;
49using Caps = OpenSim.Framework.Communications.Capabilities.Caps;
50using Image = System.Drawing.Image;
51using TPFlags = OpenSim.Framework.Constants.TeleportFlags;
52using Timer = System.Timers.Timer;
53using OSD = OpenMetaverse.StructuredData.OSD;
54
55namespace OpenSim.Region.Environment.Scenes
56{
57 public delegate bool FilterAvatarList(ScenePresence avatar);
58
59 public partial class Scene : SceneBase
60 {
61 public delegate void SynchronizeSceneHandler(Scene scene);
62 public SynchronizeSceneHandler SynchronizeScene = null;
63 public int splitID = 0;
64
65 private const long DEFAULT_MIN_TIME_FOR_PERSISTENCE = 60L;
66 private const long DEFAULT_MAX_TIME_FOR_PERSISTENCE = 600L;
67
68 #region Fields
69
70 protected Timer m_restartWaitTimer = new Timer();
71
72 public SimStatsReporter StatsReporter;
73
74 protected List<RegionInfo> m_regionRestartNotifyList = new List<RegionInfo>();
75 protected List<RegionInfo> m_neighbours = new List<RegionInfo>();
76
77 /// <value>
78 /// The scene graph for this scene
79 /// </value>
80 /// TODO: Possibly stop other classes being able to manipulate this directly.
81 public SceneGraph m_sceneGraph;
82
83 /// <summary>
84 /// Are we applying physics to any of the prims in this scene?
85 /// </summary>
86 public bool m_physicalPrim;
87 public float m_maxNonphys = 65536;
88 public float m_maxPhys = 10;
89 public bool m_clampPrimSize = false;
90 public bool m_trustBinaries = false;
91 public bool m_allowScriptCrossings = false;
92
93 public bool m_seeIntoRegionFromNeighbor;
94 public int MaxUndoCount = 5;
95 private int m_RestartTimerCounter;
96 private readonly Timer m_restartTimer = new Timer(15000); // Wait before firing
97 private int m_incrementsof15seconds = 0;
98 private volatile bool m_backingup = false;
99
100 private Dictionary<UUID, ReturnInfo> m_returns = new Dictionary<UUID, ReturnInfo>();
101
102 protected string m_simulatorVersion = "OpenSimulator Server";
103
104 protected ModuleLoader m_moduleLoader;
105 protected StorageManager m_storageManager;
106 protected AgentCircuitManager m_authenticateHandler;
107 public CommunicationsManager CommsManager;
108
109 protected SceneCommunicationService m_sceneGridService;
110
111 public SceneCommunicationService SceneGridService
112 {
113 get { return m_sceneGridService; }
114 }
115
116 public IXfer XferManager;
117
118 protected IXMLRPC m_xmlrpcModule;
119 protected IWorldComm m_worldCommModule;
120 protected IAvatarFactory m_AvatarFactory;
121 protected IConfigSource m_config;
122 protected IRegionSerialiserModule m_serialiser;
123 protected IInterregionCommsOut m_interregionCommsOut;
124 protected IInterregionCommsIn m_interregionCommsIn;
125 protected IDialogModule m_dialogModule;
126 protected internal ICapabilitiesModule CapsModule;
127
128 // Central Update Loop
129
130 protected int m_fps = 10;
131 protected int m_frame = 0;
132 protected float m_timespan = 0.089f;
133 protected DateTime m_lastupdate = DateTime.Now;
134
135 protected float m_timedilation = 1.0f;
136
137 private int m_update_physics = 1;
138 private int m_update_entitymovement = 1;
139 private int m_update_entities = 1; // Run through all objects checking for updates
140 private int m_update_entitiesquick = 200; // Run through objects that have scheduled updates checking for updates
141 private int m_update_presences = 1; // Update scene presence movements
142 private int m_update_events = 1;
143 private int m_update_backup = 200;
144 private int m_update_terrain = 50;
145 private int m_update_land = 1;
146
147 private int frameMS = 0;
148 private int physicsMS2 = 0;
149 private int physicsMS = 0;
150 private int otherMS = 0;
151
152 private bool m_physics_enabled = true;
153 private bool m_scripts_enabled = true;
154 private string m_defaultScriptEngine;
155 private int m_LastLogin = 0;
156 private Thread HeartbeatThread;
157 private volatile bool shuttingdown = false;
158
159 private object m_deleting_scene_object = new object();
160
161 // the minimum time that must elapse before a changed object will be considered for persisted
162 public long m_dontPersistBefore = DEFAULT_MIN_TIME_FOR_PERSISTENCE * 10000000L;
163 // the maximum time that must elapse before a changed object will be considered for persisted
164 public long m_persistAfter = DEFAULT_MAX_TIME_FOR_PERSISTENCE * 10000000L;
165
166 #endregion
167
168 #region Properties
169
170 public AgentCircuitManager AuthenticateHandler
171 {
172 get { return m_authenticateHandler; }
173 }
174
175 public SceneGraph SceneContents
176 {
177 get { return m_sceneGraph; }
178 }
179
180 // an instance to the physics plugin's Scene object.
181 public PhysicsScene PhysicsScene
182 {
183 get { return m_sceneGraph.PhysicsScene; }
184 set
185 {
186 // If we're not doing the initial set
187 // Then we've got to remove the previous
188 // event handler
189 if (PhysicsScene != null && PhysicsScene.SupportsNINJAJoints)
190 {
191 PhysicsScene.OnJointMoved -= jointMoved;
192 PhysicsScene.OnJointDeactivated -= jointDeactivated;
193 PhysicsScene.OnJointErrorMessage -= jointErrorMessage;
194 }
195
196 m_sceneGraph.PhysicsScene = value;
197
198 if (PhysicsScene != null && m_sceneGraph.PhysicsScene.SupportsNINJAJoints)
199 {
200 // register event handlers to respond to joint movement/deactivation
201 PhysicsScene.OnJointMoved += jointMoved;
202 PhysicsScene.OnJointDeactivated += jointDeactivated;
203 PhysicsScene.OnJointErrorMessage += jointErrorMessage;
204 }
205
206 }
207 }
208
209 // This gets locked so things stay thread safe.
210 public object SyncRoot
211 {
212 get { return m_sceneGraph.m_syncRoot; }
213 }
214
215 public float TimeDilation
216 {
217 get { return m_timedilation; }
218 }
219
220 /// <summary>
221 /// This is for llGetRegionFPS
222 /// </summary>
223 public float SimulatorFPS
224 {
225 get { return StatsReporter.getLastReportedSimFPS(); }
226 }
227
228 public string DefaultScriptEngine
229 {
230 get { return m_defaultScriptEngine; }
231 }
232
233 // Local reference to the objects in the scene (which are held in the scenegraph)
234 // public Dictionary<UUID, SceneObjectGroup> Objects
235 // {
236 // get { return m_sceneGraph.SceneObjects; }
237 // }
238
239 // Reference to all of the agents in the scene (root and child)
240 protected Dictionary<UUID, ScenePresence> m_scenePresences
241 {
242 get { return m_sceneGraph.ScenePresences; }
243 set { m_sceneGraph.ScenePresences = value; }
244 }
245
246 // protected Dictionary<UUID, SceneObjectGroup> m_sceneObjects
247 // {
248 // get { return m_sceneGraph.SceneObjects; }
249 // set { m_sceneGraph.SceneObjects = value; }
250 // }
251
252 public EntityManager Entities
253 {
254 get { return m_sceneGraph.Entities; }
255 }
256
257 public Dictionary<UUID, ScenePresence> m_restorePresences
258 {
259 get { return m_sceneGraph.RestorePresences; }
260 set { m_sceneGraph.RestorePresences = value; }
261 }
262
263 public int objectCapacity = 45000;
264
265 #endregion
266
267 #region Constructors
268
269 public Scene(RegionInfo regInfo, AgentCircuitManager authen,
270 CommunicationsManager commsMan, SceneCommunicationService sceneGridService,
271 AssetCache assetCach, StorageManager storeManager,
272 ModuleLoader moduleLoader, bool dumpAssetsToFile, bool physicalPrim,
273 bool SeeIntoRegionFromNeighbor, IConfigSource config, string simulatorVersion)
274 {
275 m_config = config;
276
277 Random random = new Random();
278 m_lastAllocatedLocalId = (uint)(random.NextDouble() * (double)(uint.MaxValue/2))+(uint)(uint.MaxValue/4);
279 m_moduleLoader = moduleLoader;
280 m_authenticateHandler = authen;
281 CommsManager = commsMan;
282 m_sceneGridService = sceneGridService;
283 m_storageManager = storeManager;
284 AssetCache = assetCach;
285 m_regInfo = regInfo;
286 m_regionHandle = m_regInfo.RegionHandle;
287 m_regionName = m_regInfo.RegionName;
288 m_datastore = m_regInfo.DataStore;
289
290 m_physicalPrim = physicalPrim;
291 m_seeIntoRegionFromNeighbor = SeeIntoRegionFromNeighbor;
292
293 m_eventManager = new EventManager();
294 m_permissions = new ScenePermissions(this);
295
296 m_asyncSceneObjectDeleter = new AsyncSceneObjectGroupDeleter(this);
297 m_asyncSceneObjectDeleter.Enabled = true;
298
299 // Load region settings
300 m_regInfo.RegionSettings = m_storageManager.DataStore.LoadRegionSettings(m_regInfo.RegionID);
301 if (m_storageManager.EstateDataStore != null)
302 m_regInfo.EstateSettings = m_storageManager.EstateDataStore.LoadEstateSettings(m_regInfo.RegionID);
303
304 //Bind Storage Manager functions to some land manager functions for this scene
305 EventManager.OnLandObjectAdded +=
306 new EventManager.LandObjectAdded(m_storageManager.DataStore.StoreLandObject);
307 EventManager.OnLandObjectRemoved +=
308 new EventManager.LandObjectRemoved(m_storageManager.DataStore.RemoveLandObject);
309
310 m_sceneGraph = new SceneGraph(this, m_regInfo);
311
312 // If the scene graph has an Unrecoverable error, restart this sim.
313 // Currently the only thing that causes it to happen is two kinds of specific
314 // Physics based crashes.
315 //
316 // Out of memory
317 // Operating system has killed the plugin
318 m_sceneGraph.UnRecoverableError += RestartNow;
319
320 RegisterDefaultSceneEvents();
321
322 DumpAssetsToFile = dumpAssetsToFile;
323
324 m_scripts_enabled = !RegionInfo.RegionSettings.DisableScripts;
325
326 m_physics_enabled = !RegionInfo.RegionSettings.DisablePhysics;
327
328 StatsReporter = new SimStatsReporter(this);
329 StatsReporter.OnSendStatsResult += SendSimStatsPackets;
330 StatsReporter.OnStatsIncorrect += m_sceneGraph.RecalculateStats;
331
332 StatsReporter.SetObjectCapacity(objectCapacity);
333
334 m_simulatorVersion = simulatorVersion
335 + " (OS " + Util.GetOperatingSystemInformation() + ")"
336 + " ChilTasks:" + m_seeIntoRegionFromNeighbor.ToString()
337 + " PhysPrim:" + m_physicalPrim.ToString();
338
339 try
340 {
341 // Region config overrides global config
342 //
343 IConfig startupConfig = m_config.Configs["Startup"];
344 m_maxNonphys = startupConfig.GetFloat("NonPhysicalPrimMax", 65536.0f);
345 if (RegionInfo.NonphysPrimMax > 0)
346 m_maxNonphys = RegionInfo.NonphysPrimMax;
347
348 m_maxPhys = startupConfig.GetFloat("PhysicalPrimMax", 10.0f);
349
350 if (RegionInfo.PhysPrimMax > 0)
351 m_maxPhys = RegionInfo.PhysPrimMax;
352
353 // Here, if clamping is requested in either global or
354 // local config, it will be used
355 //
356 m_clampPrimSize = startupConfig.GetBoolean("ClampPrimSize", false);
357 if (RegionInfo.ClampPrimSize)
358 m_clampPrimSize = true;
359
360 m_trustBinaries = startupConfig.GetBoolean("TrustBinaries", false);
361 m_allowScriptCrossings = startupConfig.GetBoolean("AllowScriptCrossing", false);
362 m_dontPersistBefore =
363 startupConfig.GetLong("MinimumTimeBeforePersistenceConsidered", DEFAULT_MIN_TIME_FOR_PERSISTENCE);
364 m_dontPersistBefore *= 10000000;
365 m_persistAfter =
366 startupConfig.GetLong("MaximumTimeBeforePersistenceConsidered", DEFAULT_MAX_TIME_FOR_PERSISTENCE);
367 m_persistAfter *= 10000000;
368
369 m_defaultScriptEngine = startupConfig.GetString("DefaultScriptEngine", "DotNetEngine");
370 }
371 catch
372 {
373 m_log.Warn("[SCENE]: Failed to load StartupConfig");
374 }
375 }
376
377 /// <summary>
378 /// Mock constructor for scene group persistency unit tests.
379 /// SceneObjectGroup RegionId property is delegated to Scene.
380 /// </summary>
381 /// <param name="regInfo"></param>
382 public Scene(RegionInfo regInfo)
383 {
384 m_regInfo = regInfo;
385 m_eventManager = new EventManager();
386 }
387
388 #endregion
389
390 #region Startup / Close Methods
391
392 public bool ShuttingDown
393 {
394 get { return shuttingdown; }
395 }
396
397 protected virtual void RegisterDefaultSceneEvents()
398 {
399 IDialogModule dm = RequestModuleInterface<IDialogModule>();
400
401 if (dm != null)
402 m_eventManager.OnPermissionError += dm.SendAlertToUser;
403 }
404
405 public override string GetSimulatorVersion()
406 {
407 return m_simulatorVersion;
408 }
409
410 /// <summary>
411 /// Another region is up. Gets called from Grid Comms:
412 /// (OGS1 -> LocalBackEnd -> RegionListened -> SceneCommunicationService)
413 /// We have to tell all our ScenePresences about it, and add it to the
414 /// neighbor list.
415 ///
416 /// We only add it to the neighbor list if it's within 1 region from here.
417 /// Agents may have draw distance values that cross two regions though, so
418 /// we add it to the notify list regardless of distance. We'll check
419 /// the agent's draw distance before notifying them though.
420 /// </summary>
421 /// <param name="otherRegion">RegionInfo handle for the new region.</param>
422 /// <returns>True after all operations complete, throws exceptions otherwise.</returns>
423 public override bool OtherRegionUp(RegionInfo otherRegion)
424 {
425 if (RegionInfo.RegionHandle != otherRegion.RegionHandle)
426 {
427 for (int i = 0; i < m_neighbours.Count; i++)
428 {
429 // The purpose of this loop is to re-update the known neighbors
430 // when another region comes up on top of another one.
431 // The latest region in that location ends up in the
432 // 'known neighbors list'
433 // Additionally, the commFailTF property gets reset to false.
434 if (m_neighbours[i].RegionHandle == otherRegion.RegionHandle)
435 {
436 lock (m_neighbours)
437 {
438 m_neighbours[i] = otherRegion;
439 }
440 }
441 }
442
443 // If the value isn't in the neighbours, add it.
444 // If the RegionInfo isn't exact but is for the same XY World location,
445 // then the above loop will fix that.
446
447 if (!(CheckNeighborRegion(otherRegion)))
448 {
449 lock (m_neighbours)
450 {
451 m_neighbours.Add(otherRegion);
452 //m_log.Info("[UP]: " + otherRegion.RegionHandle.ToString());
453 }
454 }
455
456 // If these are cast to INT because long + negative values + abs returns invalid data
457 int resultX = Math.Abs((int)otherRegion.RegionLocX - (int)RegionInfo.RegionLocX);
458 int resultY = Math.Abs((int)otherRegion.RegionLocY - (int)RegionInfo.RegionLocY);
459 if (resultX <= 1 && resultY <= 1)
460 {
461 try
462 {
463 ForEachScenePresence(delegate(ScenePresence agent)
464 {
465 // If agent is a root agent.
466 if (!agent.IsChildAgent)
467 {
468 //agent.ControllingClient.new
469 //this.CommsManager.InterRegion.InformRegionOfChildAgent(otherRegion.RegionHandle, agent.ControllingClient.RequestClientInfo());
470 InformClientOfNeighbor(agent, otherRegion);
471 }
472 }
473 );
474 }
475 catch (NullReferenceException)
476 {
477 // This means that we're not booted up completely yet.
478 // This shouldn't happen too often anymore.
479 m_log.Error("[SCENE]: Couldn't inform client of regionup because we got a null reference exception");
480 }
481 }
482 else
483 {
484 m_log.Info("[INTERGRID]: Got notice about far away Region: " + otherRegion.RegionName.ToString() +
485 " at (" + otherRegion.RegionLocX.ToString() + ", " +
486 otherRegion.RegionLocY.ToString() + ")");
487 }
488 }
489 return true;
490 }
491
492 public void AddNeighborRegion(RegionInfo region)
493 {
494 lock (m_neighbours)
495 {
496 if (!CheckNeighborRegion(region))
497 {
498 m_neighbours.Add(region);
499 }
500 }
501 }
502
503 public bool CheckNeighborRegion(RegionInfo region)
504 {
505 bool found = false;
506 lock (m_neighbours)
507 {
508 foreach (RegionInfo reg in m_neighbours)
509 {
510 if (reg.RegionHandle == region.RegionHandle)
511 {
512 found = true;
513 break;
514 }
515 }
516 }
517 return found;
518 }
519
520 /// <summary>
521 /// Given float seconds, this will restart the region.
522 /// </summary>
523 /// <param name="seconds">float indicating duration before restart.</param>
524 public virtual void Restart(float seconds)
525 {
526 // notifications are done in 15 second increments
527 // so .. if the number of seconds is less then 15 seconds, it's not really a restart request
528 // It's a 'Cancel restart' request.
529
530 // RestartNow() does immediate restarting.
531 if (seconds < 15)
532 {
533 m_restartTimer.Stop();
534 m_dialogModule.SendGeneralAlert("Restart Aborted");
535 }
536 else
537 {
538 // Now we figure out what to set the timer to that does the notifications and calls, RestartNow()
539 m_restartTimer.Interval = 15000;
540 m_incrementsof15seconds = (int)seconds / 15;
541 m_RestartTimerCounter = 0;
542 m_restartTimer.AutoReset = true;
543 m_restartTimer.Elapsed += new ElapsedEventHandler(RestartTimer_Elapsed);
544 m_log.Info("[REGION]: Restarting Region in " + (seconds / 60) + " minutes");
545 m_restartTimer.Start();
546 m_dialogModule.SendNotificationToUsersInRegion(
547 UUID.Random(), String.Empty, RegionInfo.RegionName + ": Restarting in 2 Minutes");
548 }
549 }
550
551 // The Restart timer has occured.
552 // We have to figure out if this is a notification or if the number of seconds specified in Restart
553 // have elapsed.
554 // If they have elapsed, call RestartNow()
555 public void RestartTimer_Elapsed(object sender, ElapsedEventArgs e)
556 {
557 m_RestartTimerCounter++;
558 if (m_RestartTimerCounter <= m_incrementsof15seconds)
559 {
560 if (m_RestartTimerCounter == 4 || m_RestartTimerCounter == 6 || m_RestartTimerCounter == 7)
561 m_dialogModule.SendNotificationToUsersInRegion(
562 UUID.Random(),
563 String.Empty,
564 RegionInfo.RegionName + ": Restarting in " + ((8 - m_RestartTimerCounter) * 15) + " seconds");
565 }
566 else
567 {
568 m_restartTimer.Stop();
569 m_restartTimer.AutoReset = false;
570 RestartNow();
571 }
572 }
573
574 // This causes the region to restart immediatley.
575 public void RestartNow()
576 {
577 if (PhysicsScene != null)
578 {
579 PhysicsScene.Dispose();
580 }
581
582 m_log.Error("[REGION]: Closing");
583 Close();
584 m_log.Error("[REGION]: Firing Region Restart Message");
585 base.Restart(0);
586 }
587
588 // This is a helper function that notifies root agents in this region that a new sim near them has come up
589 // This is in the form of a timer because when an instance of OpenSim.exe is started,
590 // Even though the sims initialize, they don't listen until 'all of the sims are initialized'
591 // If we tell an agent about a sim that's not listening yet, the agent will not be able to connect to it.
592 // subsequently the agent will never see the region come back online.
593 public void RestartNotifyWaitElapsed(object sender, ElapsedEventArgs e)
594 {
595 m_restartWaitTimer.Stop();
596 lock (m_regionRestartNotifyList)
597 {
598 foreach (RegionInfo region in m_regionRestartNotifyList)
599 {
600 try
601 {
602 ForEachScenePresence(delegate(ScenePresence agent)
603 {
604 // If agent is a root agent.
605 if (!agent.IsChildAgent)
606 {
607 //agent.ControllingClient.new
608 //this.CommsManager.InterRegion.InformRegionOfChildAgent(otherRegion.RegionHandle, agent.ControllingClient.RequestClientInfo());
609 InformClientOfNeighbor(agent, region);
610 }
611 }
612 );
613 }
614 catch (NullReferenceException)
615 {
616 // This means that we're not booted up completely yet.
617 // This shouldn't happen too often anymore.
618 }
619 }
620
621 // Reset list to nothing.
622 m_regionRestartNotifyList.Clear();
623 }
624 }
625
626 public void SetSceneCoreDebug(bool ScriptEngine, bool CollisionEvents, bool PhysicsEngine)
627 {
628 if (m_scripts_enabled != !ScriptEngine)
629 {
630 // Tedd! Here's the method to disable the scripting engine!
631 if (ScriptEngine)
632 {
633 m_log.Info("Stopping all Scripts in Scene");
634 foreach (EntityBase ent in Entities)
635 {
636 if (ent is SceneObjectGroup)
637 {
638 ((SceneObjectGroup) ent).RemoveScriptInstances();
639 }
640 }
641 }
642 else
643 {
644 m_log.Info("Starting all Scripts in Scene");
645 lock (Entities)
646 {
647 foreach (EntityBase ent in Entities)
648 {
649 if (ent is SceneObjectGroup)
650 {
651 ((SceneObjectGroup)ent).CreateScriptInstances(0, false, DefaultScriptEngine, 0);
652 }
653 }
654 }
655 }
656 m_scripts_enabled = !ScriptEngine;
657 m_log.Info("[TOTEDD]: Here is the method to trigger disabling of the scripting engine");
658 }
659
660 if (m_physics_enabled != !PhysicsEngine)
661 {
662 m_physics_enabled = !PhysicsEngine;
663 }
664 }
665
666 public int GetInaccurateNeighborCount()
667 {
668 lock (m_neighbours)
669 {
670 return m_neighbours.Count;
671 }
672 }
673
674 // This is the method that shuts down the scene.
675 public override void Close()
676 {
677 m_log.InfoFormat("[SCENE]: Closing down the single simulator: {0}", RegionInfo.RegionName);
678
679 // Kick all ROOT agents with the message, 'The simulator is going down'
680 ForEachScenePresence(delegate(ScenePresence avatar)
681 {
682 if (avatar.KnownChildRegionHandles.Contains(RegionInfo.RegionHandle))
683 avatar.KnownChildRegionHandles.Remove(RegionInfo.RegionHandle);
684
685 if (!avatar.IsChildAgent)
686 avatar.ControllingClient.Kick("The simulator is going down.");
687
688 avatar.ControllingClient.SendShutdownConnectionNotice();
689 });
690
691 // Wait here, or the kick messages won't actually get to the agents before the scene terminates.
692 Thread.Sleep(500);
693
694 // Stop all client threads.
695 ForEachScenePresence(delegate(ScenePresence avatar) { avatar.ControllingClient.Close(true); });
696
697 // Stop updating the scene objects and agents.
698 //m_heartbeatTimer.Close();
699 shuttingdown = true;
700
701 m_log.Debug("[SCENE]: Persisting changed objects");
702 List<EntityBase> entities = GetEntities();
703 foreach (EntityBase entity in entities)
704 {
705 if (!entity.IsDeleted && entity is SceneObjectGroup && ((SceneObjectGroup)entity).HasGroupChanged)
706 {
707 ((SceneObjectGroup)entity).ProcessBackup(m_storageManager.DataStore, false);
708 }
709 }
710
711 m_sceneGraph.Close();
712
713 // De-register with region communications (events cleanup)
714 UnRegisterRegionWithComms();
715
716 // call the base class Close method.
717 base.Close();
718 }
719
720 /// <summary>
721 /// Start the timer which triggers regular scene updates
722 /// </summary>
723 public void StartTimer()
724 {
725 //m_log.Debug("[SCENE]: Starting timer");
726 //m_heartbeatTimer.Enabled = true;
727 //m_heartbeatTimer.Interval = (int)(m_timespan * 1000);
728 //m_heartbeatTimer.Elapsed += new ElapsedEventHandler(Heartbeat);
729 HeartbeatThread = new Thread(new ParameterizedThreadStart(Heartbeat));
730 HeartbeatThread.SetApartmentState(ApartmentState.MTA);
731 HeartbeatThread.Name = "Heartbeat";
732 HeartbeatThread.Priority = ThreadPriority.AboveNormal;
733 ThreadTracker.Add(HeartbeatThread);
734 HeartbeatThread.Start();
735 }
736
737 /// <summary>
738 /// Sets up references to modules required by the scene
739 /// </summary>
740 public void SetModuleInterfaces()
741 {
742 m_xmlrpcModule = RequestModuleInterface<IXMLRPC>();
743 m_worldCommModule = RequestModuleInterface<IWorldComm>();
744 XferManager = RequestModuleInterface<IXfer>();
745 m_AvatarFactory = RequestModuleInterface<IAvatarFactory>();
746 m_serialiser = RequestModuleInterface<IRegionSerialiserModule>();
747 m_interregionCommsOut = RequestModuleInterface<IInterregionCommsOut>();
748 m_interregionCommsIn = RequestModuleInterface<IInterregionCommsIn>();
749 m_dialogModule = RequestModuleInterface<IDialogModule>();
750 CapsModule = RequestModuleInterface<ICapabilitiesModule>();
751 }
752
753 #endregion
754
755 #region Update Methods
756
757 /// <summary>
758 /// Performs per-frame updates regularly
759 /// </summary>
760 /// <param name="sender"></param>
761 /// <param name="e"></param>
762 private void Heartbeat(object sender)
763 {
764 Update();
765 }
766
767 /// <summary>
768 /// Performs per-frame updates on the scene, this should be the central scene loop
769 /// </summary>
770 public override void Update()
771 {
772 int maintc = 0;
773 while (!shuttingdown)
774 {
775 maintc = System.Environment.TickCount;
776
777 TimeSpan SinceLastFrame = DateTime.Now - m_lastupdate;
778 // Aquire a lock so only one update call happens at once
779 //updateLock.WaitOne();
780 float physicsFPS = 0;
781 //m_log.Info("sadfadf" + m_neighbours.Count.ToString());
782 int agentsInScene = m_sceneGraph.GetRootAgentCount() + m_sceneGraph.GetChildAgentCount();
783
784 if (agentsInScene > 21)
785 {
786 if (m_update_entities == 1)
787 {
788 m_update_entities = 5;
789 StatsReporter.SetUpdateMS(6000);
790 }
791 }
792 else
793 {
794 if (m_update_entities == 5)
795 {
796 m_update_entities = 1;
797 StatsReporter.SetUpdateMS(3000);
798 }
799 }
800
801 frameMS = System.Environment.TickCount;
802 try
803 {
804 // Increment the frame counter
805 m_frame++;
806
807 // Loop it
808 if (m_frame == Int32.MaxValue)
809 m_frame = 0;
810
811 physicsMS2 = System.Environment.TickCount;
812 if ((m_frame % m_update_physics == 0) && m_physics_enabled)
813 m_sceneGraph.UpdatePreparePhysics();
814 physicsMS2 = System.Environment.TickCount - physicsMS2;
815
816 if (m_frame % m_update_entitymovement == 0)
817 m_sceneGraph.UpdateEntityMovement();
818
819 physicsMS = System.Environment.TickCount;
820 if ((m_frame % m_update_physics == 0) && m_physics_enabled)
821 physicsFPS = m_sceneGraph.UpdatePhysics(
822 Math.Max(SinceLastFrame.TotalSeconds, m_timespan)
823 );
824 if (m_frame % m_update_physics == 0 && SynchronizeScene != null)
825 SynchronizeScene(this);
826
827 physicsMS = System.Environment.TickCount - physicsMS;
828 physicsMS += physicsMS2;
829
830 otherMS = System.Environment.TickCount;
831 // run through all entities looking for updates (slow)
832 if (m_frame % m_update_entities == 0)
833 m_sceneGraph.UpdateEntities();
834
835 // run through entities that have scheduled themselves for
836 // updates looking for updates(faster)
837 if (m_frame % m_update_entitiesquick == 0)
838 m_sceneGraph.ProcessUpdates();
839
840 // Run through scenepresences looking for updates
841 if (m_frame % m_update_presences == 0)
842 m_sceneGraph.UpdatePresences();
843
844 // Delete temp-on-rez stuff
845 if (m_frame % m_update_backup == 0)
846 CleanTempObjects();
847
848 if (Region_Status != RegionStatus.SlaveScene)
849 {
850 if (m_frame % m_update_events == 0)
851 UpdateEvents();
852
853 if (m_frame % m_update_backup == 0)
854 {
855 UpdateStorageBackup();
856 }
857
858 if (m_frame % m_update_terrain == 0)
859 UpdateTerrain();
860
861 if (m_frame % m_update_land == 0)
862 UpdateLand();
863 otherMS = System.Environment.TickCount - otherMS;
864 // if (m_frame%m_update_avatars == 0)
865 // UpdateInWorldTime();
866 StatsReporter.AddPhysicsFPS(physicsFPS);
867 StatsReporter.AddTimeDilation(m_timedilation);
868 StatsReporter.AddFPS(1);
869 StatsReporter.AddInPackets(0);
870 StatsReporter.SetRootAgents(m_sceneGraph.GetRootAgentCount());
871 StatsReporter.SetChildAgents(m_sceneGraph.GetChildAgentCount());
872 StatsReporter.SetObjects(m_sceneGraph.GetTotalObjectsCount());
873 StatsReporter.SetActiveObjects(m_sceneGraph.GetActiveObjectsCount());
874 frameMS = System.Environment.TickCount - frameMS;
875 StatsReporter.addFrameMS(frameMS);
876 StatsReporter.addPhysicsMS(physicsMS);
877 StatsReporter.addOtherMS(otherMS);
878 StatsReporter.SetActiveScripts(m_sceneGraph.GetActiveScriptsCount());
879 StatsReporter.addScriptLines(m_sceneGraph.GetScriptLPS());
880 }
881 }
882 catch (NotImplementedException)
883 {
884 throw;
885 }
886 catch (AccessViolationException e)
887 {
888 m_log.Error("[Scene]: Failed with exception " + e.ToString() + " On Region: " + RegionInfo.RegionName);
889 }
890 //catch (NullReferenceException e)
891 //{
892 // m_log.Error("[Scene]: Failed with exception " + e.ToString() + " On Region: " + RegionInfo.RegionName);
893 //}
894 catch (InvalidOperationException e)
895 {
896 m_log.Error("[Scene]: Failed with exception " + e.ToString() + " On Region: " + RegionInfo.RegionName);
897 }
898 catch (Exception e)
899 {
900 m_log.Error("[Scene]: Failed with exception " + e.ToString() + " On Region: " + RegionInfo.RegionName);
901 }
902 finally
903 {
904 //updateLock.ReleaseMutex();
905 // Get actual time dilation
906 float tmpval = (m_timespan / (float)SinceLastFrame.TotalSeconds);
907
908 // If actual time dilation is greater then one, we're catching up, so subtract
909 // the amount that's greater then 1 from the time dilation
910 if (tmpval > 1.0)
911 {
912 tmpval = tmpval - (tmpval - 1.0f);
913 }
914 m_timedilation = tmpval;
915
916 m_lastupdate = DateTime.Now;
917 }
918 maintc = System.Environment.TickCount - maintc;
919 maintc = (int)(m_timespan * 1000) - maintc;
920
921 if ((maintc < (m_timespan * 1000)) && maintc > 0)
922 Thread.Sleep(maintc);
923 }
924 }
925
926 private void SendSimStatsPackets(SimStats stats)
927 {
928 List<ScenePresence> StatSendAgents = GetScenePresences();
929 foreach (ScenePresence agent in StatSendAgents)
930 {
931 if (!agent.IsChildAgent)
932 {
933 agent.ControllingClient.SendSimStats(stats);
934 }
935 }
936 }
937
938 private void UpdateLand()
939 {
940 if (LandChannel != null)
941 {
942 if (LandChannel.IsLandPrimCountTainted())
943 {
944 EventManager.TriggerParcelPrimCountUpdate();
945 }
946 }
947 }
948
949 private void UpdateTerrain()
950 {
951 EventManager.TriggerTerrainTick();
952 }
953
954 private void UpdateStorageBackup()
955 {
956 if (!m_backingup)
957 {
958 m_backingup = true;
959 Thread backupthread = new Thread(Backup);
960 backupthread.Name = "BackupWriter";
961 backupthread.IsBackground = true;
962 backupthread.Start();
963 }
964 }
965
966 private void UpdateEvents()
967 {
968 m_eventManager.TriggerOnFrame();
969 }
970
971 /// <summary>
972 /// Perform delegate action on all clients subscribing to updates from this region.
973 /// </summary>
974 /// <returns></returns>
975 internal void Broadcast(Action<IClientAPI> whatToDo)
976 {
977 ForEachScenePresence(delegate(ScenePresence presence) { whatToDo(presence.ControllingClient); });
978 }
979
980 /// <summary>
981 /// Backup the scene. This acts as the main method of the backup thread.
982 /// </summary>
983 /// <returns></returns>
984 public void Backup()
985 {
986 lock (m_returns)
987 {
988 EventManager.TriggerOnBackup(m_storageManager.DataStore);
989 m_backingup = false;
990
991 foreach (KeyValuePair<UUID, ReturnInfo> ret in m_returns)
992 {
993 UUID transaction = UUID.Random();
994
995 GridInstantMessage msg = new GridInstantMessage();
996 msg.fromAgentID = new Guid(UUID.Zero.ToString()); // From server
997 msg.toAgentID = new Guid(ret.Key.ToString());
998 msg.imSessionID = new Guid(transaction.ToString());
999 msg.timestamp = (uint)Util.UnixTimeSinceEpoch();
1000 msg.fromAgentName = "Server";
1001 msg.dialog = (byte)19; // Object msg
1002 msg.fromGroup = false;
1003 msg.offline = (byte)1;
1004 msg.ParentEstateID = RegionInfo.EstateSettings.ParentEstateID;
1005 msg.Position = Vector3.Zero;
1006 msg.RegionID = RegionInfo.RegionID.Guid;
1007 msg.binaryBucket = new byte[0];
1008 if (ret.Value.count > 1)
1009 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);
1010 else
1011 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);
1012
1013 IMessageTransferModule tr = RequestModuleInterface<IMessageTransferModule>();
1014 if (tr != null)
1015 tr.SendInstantMessage(msg, delegate(bool success) {} );
1016 }
1017 m_returns.Clear();
1018 }
1019 }
1020
1021 public void ForceSceneObjectBackup(SceneObjectGroup group)
1022 {
1023 if (group != null)
1024 {
1025 group.ProcessBackup(m_storageManager.DataStore, true);
1026 }
1027 }
1028
1029 public void AddReturn(UUID agentID, string objectName, Vector3 location, string reason)
1030 {
1031 lock (m_returns)
1032 {
1033 if (m_returns.ContainsKey(agentID))
1034 {
1035 ReturnInfo info = m_returns[agentID];
1036 info.count++;
1037 m_returns[agentID] = info;
1038 }
1039 else
1040 {
1041 ReturnInfo info = new ReturnInfo();
1042 info.count = 1;
1043 info.objectName = objectName;
1044 info.location = location;
1045 info.reason = reason;
1046 m_returns[agentID] = info;
1047 }
1048 }
1049 }
1050
1051 #endregion
1052
1053 #region Load Terrain
1054
1055 public void ExportWorldMap(string fileName)
1056 {
1057 List<MapBlockData> mapBlocks =
1058 m_sceneGridService.RequestNeighbourMapBlocks((int)(RegionInfo.RegionLocX - 9),
1059 (int)(RegionInfo.RegionLocY - 9),
1060 (int)(RegionInfo.RegionLocX + 9),
1061 (int)(RegionInfo.RegionLocY + 9));
1062 List<AssetBase> textures = new List<AssetBase>();
1063 List<Image> bitImages = new List<Image>();
1064
1065 foreach (MapBlockData mapBlock in mapBlocks)
1066 {
1067 AssetBase texAsset = AssetCache.GetAsset(mapBlock.MapImageId, true);
1068
1069 if (texAsset != null)
1070 {
1071 textures.Add(texAsset);
1072 }
1073 else
1074 {
1075 texAsset = AssetCache.GetAsset(mapBlock.MapImageId, true);
1076 if (texAsset != null)
1077 {
1078 textures.Add(texAsset);
1079 }
1080 }
1081 }
1082
1083 foreach (AssetBase asset in textures)
1084 {
1085 ManagedImage managedImage;
1086 Image image;
1087
1088 if (OpenJPEG.DecodeToImage(asset.Data, out managedImage, out image))
1089 bitImages.Add(image);
1090 }
1091
1092 Bitmap mapTexture = new Bitmap(2560, 2560);
1093 Graphics g = Graphics.FromImage(mapTexture);
1094 SolidBrush sea = new SolidBrush(Color.DarkBlue);
1095 g.FillRectangle(sea, 0, 0, 2560, 2560);
1096
1097 for (int i = 0; i < mapBlocks.Count; i++)
1098 {
1099 ushort x = (ushort)((mapBlocks[i].X - RegionInfo.RegionLocX) + 10);
1100 ushort y = (ushort)((mapBlocks[i].Y - RegionInfo.RegionLocY) + 10);
1101 g.DrawImage(bitImages[i], (x * 128), (y * 128), 128, 128);
1102 }
1103 mapTexture.Save(fileName, ImageFormat.Jpeg);
1104 }
1105
1106 public void SaveTerrain()
1107 {
1108 m_storageManager.DataStore.StoreTerrain(Heightmap.GetDoubles(), RegionInfo.RegionID);
1109 }
1110
1111 /// <summary>
1112 /// Loads the World heightmap
1113 /// </summary>
1114 public override void LoadWorldMap()
1115 {
1116 try
1117 {
1118 double[,] map = m_storageManager.DataStore.LoadTerrain(RegionInfo.RegionID);
1119 if (map == null)
1120 {
1121 m_log.Info("[TERRAIN]: No default terrain. Generating a new terrain.");
1122 Heightmap = new TerrainChannel();
1123
1124 m_storageManager.DataStore.StoreTerrain(Heightmap.GetDoubles(), RegionInfo.RegionID);
1125 }
1126 else
1127 {
1128 Heightmap = new TerrainChannel(map);
1129 }
1130
1131 }
1132 catch (Exception e)
1133 {
1134 m_log.Warn("[TERRAIN]: Scene.cs: LoadWorldMap() - Failed with exception " + e.ToString());
1135 }
1136 }
1137
1138 /// <summary>
1139 /// Register this region with a grid service
1140 /// </summary>
1141 /// <exception cref="System.Exception">Thrown if registration of the region itself fails.</exception>
1142 public void RegisterRegionWithGrid()
1143 {
1144 RegisterCommsEvents();
1145
1146 // These two 'commands' *must be* next to each other or sim rebooting fails.
1147 m_sceneGridService.RegisterRegion(m_interregionCommsOut, RegionInfo);
1148 m_sceneGridService.InformNeighborsThatRegionisUp(RegionInfo);
1149
1150 Dictionary<string, string> dGridSettings = m_sceneGridService.GetGridSettings();
1151
1152 if (dGridSettings.ContainsKey("allow_forceful_banlines"))
1153 {
1154 if (dGridSettings["allow_forceful_banlines"] != "TRUE")
1155 {
1156 m_log.Info("[GRID]: Grid is disabling forceful parcel banlists");
1157 EventManager.TriggerSetAllowForcefulBan(false);
1158 }
1159 else
1160 {
1161 m_log.Info("[GRID]: Grid is allowing forceful parcel banlists");
1162 EventManager.TriggerSetAllowForcefulBan(true);
1163 }
1164 }
1165 }
1166
1167 /// <summary>
1168 ///
1169 /// </summary>
1170 public void CreateTerrainTexture(bool temporary)
1171 {
1172 //create a texture asset of the terrain
1173 IMapImageGenerator terrain = RequestModuleInterface<IMapImageGenerator>();
1174
1175 // Cannot create a map for a nonexistant heightmap yet.
1176 if (Heightmap == null)
1177 return;
1178
1179 if (terrain == null)
1180 {
1181 #region Fallback default maptile generation
1182
1183 int tc = System.Environment.TickCount;
1184 m_log.Info("[MAPTILE]: Generating Maptile Step 1: Terrain");
1185 Bitmap mapbmp = new Bitmap(256, 256);
1186 double[,] hm = Heightmap.GetDoubles();
1187 bool ShadowDebugContinue = true;
1188 //Color prim = Color.FromArgb(120, 120, 120);
1189 //Vector3 RayEnd = new Vector3(0, 0, 0);
1190 //Vector3 RayStart = new Vector3(0, 0, 0);
1191 //Vector3 direction = new Vector3(0, 0, -1);
1192 //Vector3 AXOrigin = new Vector3();
1193 //Vector3 AXdirection = new Vector3();
1194 //Ray testRay = new Ray();
1195 //EntityIntersection rt = new EntityIntersection();
1196 bool terraincorruptedwarningsaid = false;
1197
1198 float low = 255;
1199 float high = 0;
1200 for (int x = 0; x < 256; x++)
1201 {
1202 for (int y = 0; y < 256; y++)
1203 {
1204 float hmval = (float)hm[x, y];
1205 if (hmval < low)
1206 low = hmval;
1207 if (hmval > high)
1208 high = hmval;
1209 }
1210 }
1211
1212 float mid = (high + low) * 0.5f;
1213
1214 // temporary initializer
1215 float hfvalue = (float)m_regInfo.RegionSettings.WaterHeight;
1216 float hfvaluecompare = hfvalue;
1217 float hfdiff = hfvalue;
1218 int hfdiffi = 0;
1219
1220 for (int x = 0; x < 256; x++)
1221 {
1222 //int tc = System.Environment.TickCount;
1223 for (int y = 0; y < 256; y++)
1224 {
1225 //RayEnd = new Vector3(x, y, 0);
1226 //RayStart = new Vector3(x, y, 255);
1227
1228 //direction = Vector3.Norm(RayEnd - RayStart);
1229 //AXOrigin = new Vector3(RayStart.X, RayStart.Y, RayStart.Z);
1230 //AXdirection = new Vector3(direction.X, direction.Y, direction.Z);
1231
1232 //testRay = new Ray(AXOrigin, AXdirection);
1233 //rt = m_sceneGraph.GetClosestIntersectingPrim(testRay);
1234
1235 //if (rt.HitTF)
1236 //{
1237 //mapbmp.SetPixel(x, y, prim);
1238 //}
1239 //else
1240 //{
1241 //float tmpval = (float)hm[x, y];
1242 float heightvalue = (float)hm[x, y];
1243
1244 if (heightvalue > (float)m_regInfo.RegionSettings.WaterHeight)
1245 {
1246 // scale height value
1247 heightvalue = low + mid * (heightvalue - low) / mid;
1248
1249 if (heightvalue > 255)
1250 heightvalue = 255;
1251
1252 if (heightvalue < 0)
1253 heightvalue = 0;
1254
1255 if (Single.IsInfinity(heightvalue) || Single.IsNaN(heightvalue))
1256 heightvalue = 0;
1257
1258 try
1259 {
1260 Color green = Color.FromArgb((int)heightvalue, 100, (int)heightvalue);
1261
1262 // Y flip the cordinates
1263 mapbmp.SetPixel(x, (256 - y) - 1, green);
1264
1265 //X
1266 // .
1267 //
1268 // Shade the terrain for shadows
1269 if ((x - 1 > 0) && (y - 1 > 0))
1270 {
1271 hfvalue = (float)hm[x, y];
1272 hfvaluecompare = (float)hm[x - 1, y - 1];
1273
1274 if (Single.IsInfinity(hfvalue) || Single.IsNaN(hfvalue))
1275 hfvalue = 0;
1276
1277 if (Single.IsInfinity(hfvaluecompare) || Single.IsNaN(hfvaluecompare))
1278 hfvaluecompare = 0;
1279
1280 hfdiff = hfvaluecompare - hfvalue;
1281
1282 if (hfdiff > 0.3f)
1283 {
1284
1285 }
1286 else if (hfdiff < -0.3f)
1287 {
1288 // We have to desaturate and blacken the land at the same time
1289 // we use floats, colors use bytes, so shrink are space down to
1290 // 0-255
1291
1292 try
1293 {
1294 hfdiffi = Math.Abs((int)((hfdiff * 4) + (hfdiff * 0.5))) + 1;
1295 if (hfdiff % 1 != 0)
1296 {
1297 hfdiffi = hfdiffi + Math.Abs((int)(((hfdiff % 1) * 0.5f) * 10f) - 1);
1298 }
1299 }
1300 catch (System.OverflowException)
1301 {
1302 m_log.Debug("[MAPTILE]: Shadow failed at value: " + hfdiff.ToString());
1303 ShadowDebugContinue = false;
1304 }
1305
1306 if (ShadowDebugContinue)
1307 {
1308 if ((256 - y) - 1 > 0)
1309 {
1310 Color Shade = mapbmp.GetPixel(x - 1, (256 - y) - 1);
1311
1312 int r = Shade.R;
1313
1314 int g = Shade.G;
1315 int b = Shade.B;
1316 Shade = Color.FromArgb((r - hfdiffi > 0) ? r - hfdiffi : 0, (g - hfdiffi > 0) ? g - hfdiffi : 0, (b - hfdiffi > 0) ? b - hfdiffi : 0);
1317 //Console.WriteLine("d:" + hfdiff.ToString() + ", i:" + hfdiffi + ", pos: " + x + "," + y + " - R:" + Shade.R.ToString() + ", G:" + Shade.G.ToString() + ", B:" + Shade.G.ToString());
1318 mapbmp.SetPixel(x - 1, (256 - y) - 1, Shade);
1319 }
1320 }
1321 }
1322 }
1323 }
1324 catch (System.ArgumentException)
1325 {
1326 if (!terraincorruptedwarningsaid)
1327 {
1328 m_log.WarnFormat("[MAPIMAGE]: Your terrain is corrupted in region {0}, it might take a few minutes to generate the map image depending on the corruption level", RegionInfo.RegionName);
1329 terraincorruptedwarningsaid = true;
1330 }
1331 Color black = Color.Black;
1332 mapbmp.SetPixel(x, (256 - y) - 1, black);
1333 }
1334 }
1335 else
1336 {
1337 // Y flip the cordinates
1338 heightvalue = (float)m_regInfo.RegionSettings.WaterHeight - heightvalue;
1339 if (heightvalue > 19)
1340 heightvalue = 19;
1341 if (heightvalue < 0)
1342 heightvalue = 0;
1343
1344 heightvalue = 100 - (heightvalue * 100) / 19;
1345
1346 if (heightvalue > 255)
1347 heightvalue = 255;
1348
1349 if (heightvalue < 0)
1350 heightvalue = 0;
1351
1352 if (Single.IsInfinity(heightvalue) || Single.IsNaN(heightvalue))
1353 heightvalue = 0;
1354
1355 try
1356 {
1357 Color water = Color.FromArgb((int)heightvalue, (int)heightvalue, 255);
1358 mapbmp.SetPixel(x, (256 - y) - 1, water);
1359 }
1360 catch (System.ArgumentException)
1361 {
1362 if (!terraincorruptedwarningsaid)
1363 {
1364 m_log.WarnFormat("[MAPIMAGE]: Your terrain is corrupted in region {0}, it might take a few minutes to generate the map image depending on the corruption level", RegionInfo.RegionName);
1365 terraincorruptedwarningsaid = true;
1366 }
1367 Color black = Color.Black;
1368 mapbmp.SetPixel(x, (256 - y) - 1, black);
1369 }
1370 }
1371 }
1372 //}
1373
1374 //tc = System.Environment.TickCount - tc;
1375 //m_log.Info("[MAPTILE]: Completed One row in " + tc + " ms");
1376 }
1377
1378 m_log.Info("[MAPTILE]: Generating Maptile Step 1: Done in " + (System.Environment.TickCount - tc) + " ms");
1379
1380 bool drawPrimVolume = true;
1381
1382 try
1383 {
1384 IConfig startupConfig = m_config.Configs["Startup"];
1385 drawPrimVolume = startupConfig.GetBoolean("DrawPrimOnMapTile", true);
1386 }
1387 catch
1388 {
1389 m_log.Warn("[MAPTILE]: Failed to load StartupConfig");
1390 }
1391
1392 if (drawPrimVolume)
1393 {
1394 tc = System.Environment.TickCount;
1395 m_log.Info("[MAPTILE]: Generating Maptile Step 2: Object Volume Profile");
1396 List<EntityBase> objs = GetEntities();
1397
1398 lock (objs)
1399 {
1400 foreach (EntityBase obj in objs)
1401 {
1402 // Only draw the contents of SceneObjectGroup
1403 if (obj is SceneObjectGroup)
1404 {
1405 SceneObjectGroup mapdot = (SceneObjectGroup)obj;
1406 Color mapdotspot = Color.Gray; // Default color when prim color is white
1407 // Loop over prim in group
1408 foreach (SceneObjectPart part in mapdot.Children.Values)
1409 {
1410 if (part == null)
1411 continue;
1412
1413 // Draw if the object is at least 1 meter wide in any direction
1414 if (part.Scale.X > 1f || part.Scale.Y > 1f || part.Scale.Z > 1f)
1415 {
1416 // Try to get the RGBA of the default texture entry..
1417 //
1418 try
1419 {
1420 if (part == null)
1421 continue;
1422
1423 if (part.Shape == null)
1424 continue;
1425
1426 if (part.Shape.PCode == (byte)PCode.Tree || part.Shape.PCode == (byte)PCode.NewTree)
1427 continue; // eliminates trees from this since we don't really have a good tree representation
1428 // if you want tree blocks on the map comment the above line and uncomment the below line
1429 //mapdotspot = Color.PaleGreen;
1430
1431 if (part.Shape.Textures == null)
1432 continue;
1433
1434 if (part.Shape.Textures.DefaultTexture == null)
1435 continue;
1436
1437 Color4 texcolor = part.Shape.Textures.DefaultTexture.RGBA;
1438
1439 // Not sure why some of these are null, oh well.
1440
1441 int colorr = 255 - (int)(texcolor.R * 255f);
1442 int colorg = 255 - (int)(texcolor.G * 255f);
1443 int colorb = 255 - (int)(texcolor.B * 255f);
1444
1445 if (!(colorr == 255 && colorg == 255 && colorb == 255))
1446 {
1447 //Try to set the map spot color
1448 try
1449 {
1450 // If the color gets goofy somehow, skip it *shakes fist at Color4
1451 mapdotspot = Color.FromArgb(colorr, colorg, colorb);
1452 }
1453 catch (ArgumentException)
1454 {
1455 }
1456 }
1457 }
1458 catch (IndexOutOfRangeException)
1459 {
1460 // Windows Array
1461 }
1462 catch (ArgumentOutOfRangeException)
1463 {
1464 // Mono Array
1465 }
1466
1467 Vector3 pos = part.GetWorldPosition();
1468
1469 // skip prim outside of retion
1470 if (pos.X < 0f || pos.X > 256f || pos.Y < 0f || pos.Y > 256f)
1471 continue;
1472
1473 // skip prim in non-finite position
1474 if (Single.IsNaN(pos.X) || Single.IsNaN(pos.Y) || Single.IsInfinity(pos.X)
1475 || Single.IsInfinity(pos.Y))
1476 continue;
1477
1478 // Figure out if object is under 256m above the height of the terrain
1479 bool isBelow256AboveTerrain = false;
1480
1481 try
1482 {
1483 isBelow256AboveTerrain = (pos.Z < ((float)hm[(int)pos.X, (int)pos.Y] + 256f));
1484 }
1485 catch (Exception)
1486 {
1487 }
1488
1489 if (isBelow256AboveTerrain)
1490 {
1491 // Translate scale by rotation so scale is represented properly when object is rotated
1492 Vector3 scale = part.Shape.Scale;
1493 Quaternion rot = part.GetWorldRotation();
1494 scale *= rot;
1495
1496 // negative scales don't work in this situation
1497 scale.X = Math.Abs(scale.X);
1498 scale.Y = Math.Abs(scale.Y);
1499 scale.Z = Math.Abs(scale.Z);
1500
1501 // This scaling isn't very accurate and doesn't take into account the face rotation :P
1502 int mapdrawstartX = (int)(pos.X - scale.X);
1503 int mapdrawstartY = (int)(pos.Y - scale.Y);
1504 int mapdrawendX = (int)(pos.X + scale.X);
1505 int mapdrawendY = (int)(pos.Y + scale.Y);
1506
1507 // If object is beyond the edge of the map, don't draw it to avoid errors
1508 if (mapdrawstartX < 0 || mapdrawstartX > 255 || mapdrawendX < 0 || mapdrawendX > 255
1509 || mapdrawstartY < 0 || mapdrawstartY > 255 || mapdrawendY < 0
1510 || mapdrawendY > 255)
1511 continue;
1512
1513 int wy = 0;
1514
1515 bool breakYN = false; // If we run into an error drawing, break out of the
1516 // loop so we don't lag to death on error handling
1517 for (int wx = mapdrawstartX; wx < mapdrawendX; wx++)
1518 {
1519 for (wy = mapdrawstartY; wy < mapdrawendY; wy++)
1520 {
1521 //m_log.InfoFormat("[MAPDEBUG]: {0},{1}({2})", wx, (255 - wy),wy);
1522 try
1523 {
1524 // Remember, flip the y!
1525 mapbmp.SetPixel(wx, (255 - wy), mapdotspot);
1526 }
1527 catch (ArgumentException)
1528 {
1529 breakYN = true;
1530 }
1531
1532 if (breakYN)
1533 break;
1534 }
1535
1536 if (breakYN)
1537 break;
1538 }
1539 } // Object is within 256m Z of terrain
1540 } // object is at least a meter wide
1541 } // loop over group children
1542 } // entitybase is sceneobject group
1543 } // foreach loop over entities
1544 } // lock entities objs
1545
1546 m_log.Info("[MAPTILE]: Generating Maptile Step 2: Done in " + (System.Environment.TickCount - tc) + " ms");
1547 } // end if drawPrimOnMaptle
1548
1549 byte[] data;
1550 try
1551 {
1552 data = OpenJPEG.EncodeFromImage(mapbmp, false);
1553 }
1554 catch (Exception)
1555 {
1556 return;
1557 }
1558
1559 LazySaveGeneratedMaptile(data,temporary);
1560
1561 #endregion
1562 }
1563 else
1564 {
1565 // Use the module to generate the maptile.
1566 byte[] data = terrain.WriteJpeg2000Image("defaultstripe.png");
1567 if (data != null)
1568 {
1569 LazySaveGeneratedMaptile(data,temporary);
1570 }
1571 }
1572 }
1573
1574 public void LazySaveGeneratedMaptile(byte[] data, bool temporary)
1575 {
1576 // Overwrites the local Asset cache with new maptile data
1577 // Assets are single write, this causes the asset server to ignore this update,
1578 // but the local asset cache does not
1579
1580 // this is on purpose! The net result of this is the region always has the most up to date
1581 // map tile while protecting the (grid) asset database from bloat caused by a new asset each
1582 // time a mapimage is generated!
1583
1584 UUID lastMapRegionUUID = m_regInfo.lastMapUUID;
1585
1586 int lastMapRefresh = 0;
1587 int twoDays = 172800;
1588 int RefreshSeconds = twoDays;
1589
1590 try
1591 {
1592 lastMapRefresh = Convert.ToInt32(m_regInfo.lastMapRefresh);
1593 }
1594 catch (ArgumentException)
1595 {
1596 }
1597 catch (FormatException)
1598 {
1599 }
1600 catch (OverflowException)
1601 {
1602 }
1603
1604 UUID TerrainImageUUID = UUID.Random();
1605
1606 if (lastMapRegionUUID == UUID.Zero || (lastMapRefresh + RefreshSeconds) < Util.UnixTimeSinceEpoch())
1607 {
1608 m_regInfo.SaveLastMapUUID(TerrainImageUUID);
1609
1610 m_log.Warn("[MAPTILE]: STORING MAPTILE IMAGE");
1611 }
1612 else
1613 {
1614 TerrainImageUUID = lastMapRegionUUID;
1615 m_log.Warn("[MAPTILE]: REUSING OLD MAPTILE IMAGE ID");
1616 }
1617
1618 m_regInfo.RegionSettings.TerrainImageID = TerrainImageUUID;
1619
1620 AssetBase asset = new AssetBase();
1621 asset.Metadata.FullID = m_regInfo.RegionSettings.TerrainImageID;
1622 asset.Data = data;
1623 asset.Metadata.Name = "terrainImage_" + m_regInfo.RegionID.ToString() + "_" + lastMapRefresh.ToString();
1624 asset.Metadata.Description = RegionInfo.RegionName;
1625
1626 asset.Metadata.Type = 0;
1627 asset.Metadata.Temporary = temporary;
1628 AssetCache.AddAsset(asset);
1629 }
1630
1631 #endregion
1632
1633 #region Load Land
1634
1635 public void loadAllLandObjectsFromStorage(UUID regionID)
1636 {
1637 m_log.Info("[SCENE]: Loading land objects from storage");
1638 List<LandData> landData = m_storageManager.DataStore.LoadLandObjects(regionID);
1639
1640 if (LandChannel != null)
1641 {
1642 if (landData.Count == 0)
1643 {
1644 EventManager.TriggerNoticeNoLandDataFromStorage();
1645 }
1646 else
1647 {
1648 EventManager.TriggerIncomingLandDataFromStorage(landData);
1649 }
1650 }
1651 else
1652 {
1653 m_log.Error("[SCENE]: Land Channel is not defined. Cannot load from storage!");
1654 }
1655 }
1656
1657 #endregion
1658
1659 #region Primitives Methods
1660
1661 /// <summary>
1662 /// Loads the World's objects
1663 /// </summary>
1664 public virtual void LoadPrimsFromStorage(UUID regionID)
1665 {
1666 m_log.Info("[SCENE]: Loading objects from datastore");
1667
1668 List<SceneObjectGroup> PrimsFromDB = m_storageManager.DataStore.LoadObjects(regionID);
1669 foreach (SceneObjectGroup group in PrimsFromDB)
1670 {
1671 if (group.RootPart == null)
1672 {
1673 m_log.ErrorFormat("[SCENE] Found a SceneObjectGroup with m_rootPart == null and {0} children",
1674 group.Children == null ? 0 : group.Children.Count);
1675 }
1676
1677 AddRestoredSceneObject(group, true, true);
1678 SceneObjectPart rootPart = group.GetChildPart(group.UUID);
1679 rootPart.ObjectFlags &= ~(uint)PrimFlags.Scripted;
1680 rootPart.TrimPermissions();
1681 group.CheckSculptAndLoad();
1682 //rootPart.DoPhysicsPropertyUpdate(UsePhysics, true);
1683 }
1684
1685 m_log.Info("[SCENE]: Loaded " + PrimsFromDB.Count.ToString() + " SceneObject(s)");
1686 }
1687
1688 public Vector3 GetNewRezLocation(Vector3 RayStart, Vector3 RayEnd, UUID RayTargetID, Quaternion rot, byte bypassRayCast, byte RayEndIsIntersection, bool frontFacesOnly, Vector3 scale, bool FaceCenter)
1689 {
1690 Vector3 pos = Vector3.Zero;
1691 if (RayEndIsIntersection == (byte)1)
1692 {
1693 pos = RayEnd;
1694 return pos;
1695 }
1696
1697 if (RayTargetID != UUID.Zero)
1698 {
1699 SceneObjectPart target = GetSceneObjectPart(RayTargetID);
1700
1701 Vector3 direction = Vector3.Normalize(RayEnd - RayStart);
1702 Vector3 AXOrigin = new Vector3(RayStart.X, RayStart.Y, RayStart.Z);
1703 Vector3 AXdirection = new Vector3(direction.X, direction.Y, direction.Z);
1704
1705 if (target != null)
1706 {
1707 pos = target.AbsolutePosition;
1708 //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());
1709
1710 // TODO: Raytrace better here
1711
1712 //EntityIntersection ei = m_sceneGraph.GetClosestIntersectingPrim(new Ray(AXOrigin, AXdirection));
1713 Ray NewRay = new Ray(AXOrigin, AXdirection);
1714
1715 // Ray Trace against target here
1716 EntityIntersection ei = target.TestIntersectionOBB(NewRay, Quaternion.Identity, frontFacesOnly, FaceCenter);
1717
1718 // Un-comment out the following line to Get Raytrace results printed to the console.
1719 // m_log.Info("[RAYTRACERESULTS]: Hit:" + ei.HitTF.ToString() + " Point: " + ei.ipoint.ToString() + " Normal: " + ei.normal.ToString());
1720 float ScaleOffset = 0.5f;
1721
1722 // If we hit something
1723 if (ei.HitTF)
1724 {
1725 Vector3 scaleComponent = new Vector3(ei.AAfaceNormal.X, ei.AAfaceNormal.Y, ei.AAfaceNormal.Z);
1726 if (scaleComponent.X != 0) ScaleOffset = scale.X;
1727 if (scaleComponent.Y != 0) ScaleOffset = scale.Y;
1728 if (scaleComponent.Z != 0) ScaleOffset = scale.Z;
1729 ScaleOffset = Math.Abs(ScaleOffset);
1730 Vector3 intersectionpoint = new Vector3(ei.ipoint.X, ei.ipoint.Y, ei.ipoint.Z);
1731 Vector3 normal = new Vector3(ei.normal.X, ei.normal.Y, ei.normal.Z);
1732 // Set the position to the intersection point
1733 Vector3 offset = (normal * (ScaleOffset / 2f));
1734 pos = (intersectionpoint + offset);
1735
1736 // Un-offset the prim (it gets offset later by the consumer method)
1737 pos.Z -= 0.25F;
1738 }
1739
1740 return pos;
1741 }
1742 else
1743 {
1744 // We don't have a target here, so we're going to raytrace all the objects in the scene.
1745
1746 EntityIntersection ei = m_sceneGraph.GetClosestIntersectingPrim(new Ray(AXOrigin, AXdirection), true, false);
1747
1748 // Un-comment the following line to print the raytrace results to the console.
1749 //m_log.Info("[RAYTRACERESULTS]: Hit:" + ei.HitTF.ToString() + " Point: " + ei.ipoint.ToString() + " Normal: " + ei.normal.ToString());
1750
1751 if (ei.HitTF)
1752 {
1753 pos = new Vector3(ei.ipoint.X, ei.ipoint.Y, ei.ipoint.Z);
1754 } else
1755 {
1756 // fall back to our stupid functionality
1757 pos = RayEnd;
1758 }
1759
1760 return pos;
1761 }
1762 }
1763 else
1764 {
1765 // fall back to our stupid functionality
1766 pos = RayEnd;
1767 return pos;
1768 }
1769 }
1770
1771 public virtual void AddNewPrim(UUID ownerID, UUID groupID, Vector3 RayEnd, Quaternion rot, PrimitiveBaseShape shape,
1772 byte bypassRaycast, Vector3 RayStart, UUID RayTargetID,
1773 byte RayEndIsIntersection)
1774 {
1775 Vector3 pos = GetNewRezLocation(RayStart, RayEnd, RayTargetID, rot, bypassRaycast, RayEndIsIntersection, true, new Vector3(0.5f, 0.5f, 0.5f), false);
1776
1777 if (Permissions.CanRezObject(1, ownerID, pos))
1778 {
1779 // rez ON the ground, not IN the ground
1780 pos.Z += 0.25F;
1781
1782 AddNewPrim(ownerID, groupID, pos, rot, shape);
1783 }
1784 }
1785
1786 public virtual SceneObjectGroup AddNewPrim(
1787 UUID ownerID, UUID groupID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
1788 {
1789 //m_log.DebugFormat(
1790 // "[SCENE]: Scene.AddNewPrim() pcode {0} called for {1} in {2}", shape.PCode, ownerID, RegionInfo.RegionName);
1791
1792 // If an entity creator has been registered for this prim type then use that
1793 if (m_entityCreators.ContainsKey((PCode)shape.PCode))
1794 return m_entityCreators[(PCode)shape.PCode].CreateEntity(ownerID, groupID, pos, rot, shape);
1795
1796 // Otherwise, use this default creation code;
1797 SceneObjectGroup sceneObject = new SceneObjectGroup(ownerID, pos, rot, shape);
1798 AddNewSceneObject(sceneObject, true);
1799 sceneObject.SetGroup(groupID, null);
1800
1801 return sceneObject;
1802 }
1803
1804 /// <summary>
1805 /// Add an object into the scene that has come from storage
1806 /// </summary>
1807 ///
1808 /// <param name="sceneObject"></param>
1809 /// <param name="attachToBackup">
1810 /// If true, changes to the object will be reflected in its persisted data
1811 /// If false, the persisted data will not be changed even if the object in the scene is changed
1812 /// </param>
1813 /// <param name="alreadyPersisted">
1814 /// If true, we won't persist this object until it changes
1815 /// If false, we'll persist this object immediately
1816 /// </param>
1817 /// <returns>
1818 /// true if the object was added, false if an object with the same uuid was already in the scene
1819 /// </returns>
1820 public bool AddRestoredSceneObject(
1821 SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted)
1822 {
1823 return m_sceneGraph.AddRestoredSceneObject(sceneObject, attachToBackup, alreadyPersisted);
1824 }
1825
1826 /// <summary>
1827 /// Add a newly created object to the scene
1828 /// </summary>
1829 /// <param name="sceneObject"></param>
1830 /// <param name="attachToBackup">
1831 /// If true, the object is made persistent into the scene.
1832 /// If false, the object will not persist over server restarts
1833 /// </param>
1834 public bool AddNewSceneObject(SceneObjectGroup sceneObject, bool attachToBackup)
1835 {
1836 return m_sceneGraph.AddNewSceneObject(sceneObject, attachToBackup);
1837 }
1838
1839 /// <summary>
1840 /// Delete every object from the scene
1841 /// </summary>
1842 public void DeleteAllSceneObjects()
1843 {
1844 lock (Entities)
1845 {
1846 ICollection<EntityBase> entities = new List<EntityBase>(Entities);
1847
1848 foreach (EntityBase e in entities)
1849 {
1850 if (e is SceneObjectGroup)
1851 DeleteSceneObject((SceneObjectGroup)e, false);
1852 }
1853 }
1854 }
1855
1856 /// <summary>
1857 /// Synchronously delete the given object from the scene.
1858 /// </summary>
1859 /// <param name="group">Object Id</param>
1860 /// <param name="silent">Suppress broadcasting changes to other clients.</param>
1861 public void DeleteSceneObject(SceneObjectGroup group, bool silent)
1862 {
1863 //SceneObjectPart rootPart = group.GetChildPart(group.UUID);
1864
1865 // Serialise calls to RemoveScriptInstances to avoid
1866 // deadlocking on m_parts inside SceneObjectGroup
1867 lock (m_deleting_scene_object)
1868 {
1869 group.RemoveScriptInstances();
1870 }
1871
1872 foreach (SceneObjectPart part in group.Children.Values)
1873 {
1874 if (part.IsJoint() && ((part.ObjectFlags&(uint)PrimFlags.Physics) != 0) )
1875 {
1876 PhysicsScene.RequestJointDeletion(part.Name); // FIXME: what if the name changed?
1877 }
1878 else if (part.PhysActor != null)
1879 {
1880 PhysicsScene.RemovePrim(part.PhysActor);
1881 part.PhysActor = null;
1882 }
1883 }
1884// if (rootPart.PhysActor != null)
1885// {
1886// PhysicsScene.RemovePrim(rootPart.PhysActor);
1887// rootPart.PhysActor = null;
1888// }
1889
1890 if (UnlinkSceneObject(group.UUID, false))
1891 {
1892 EventManager.TriggerObjectBeingRemovedFromScene(group);
1893 EventManager.TriggerParcelPrimCountTainted();
1894 }
1895
1896 group.DeleteGroup(silent);
1897 }
1898
1899 /// <summary>
1900 /// Unlink the given object from the scene. Unlike delete, this just removes the record of the object - the
1901 /// object itself is not destroyed.
1902 /// </summary>
1903 /// <param name="uuid">Id of object.</param>
1904 /// <returns>true if the object was in the scene, false if it was not</returns>
1905 /// <param name="softDelete">If true, only deletes from scene, but keeps object in database.</param>
1906 public bool UnlinkSceneObject(UUID uuid, bool softDelete)
1907 {
1908 if (m_sceneGraph.DeleteSceneObject(uuid, softDelete))
1909 {
1910 if (!softDelete)
1911 {
1912 m_storageManager.DataStore.RemoveObject(uuid,
1913 m_regInfo.RegionID);
1914 }
1915
1916 return true;
1917 }
1918
1919 return false;
1920 }
1921
1922 /// <summary>
1923 /// Move the given scene object into a new region depending on which region its absolute position has moved
1924 /// into.
1925 ///
1926 /// This method locates the new region handle and offsets the prim position for the new region
1927 /// </summary>
1928 /// <param name="attemptedPosition">the attempted out of region position of the scene object</param>
1929 /// <param name="grp">the scene object that we're crossing</param>
1930 public void CrossPrimGroupIntoNewRegion(Vector3 attemptedPosition, SceneObjectGroup grp, bool silent)
1931 {
1932 if (grp == null)
1933 return;
1934 if (grp.IsDeleted)
1935 return;
1936
1937 if (grp.RootPart.DIE_AT_EDGE)
1938 {
1939 // We remove the object here
1940 try
1941 {
1942 DeleteSceneObject(grp, false);
1943 }
1944 catch (Exception)
1945 {
1946 m_log.Warn("[DATABASE]: exception when trying to remove the prim that crossed the border.");
1947 }
1948 return;
1949 }
1950
1951 int thisx = (int)RegionInfo.RegionLocX;
1952 int thisy = (int)RegionInfo.RegionLocY;
1953
1954 ulong newRegionHandle = 0;
1955 Vector3 pos = attemptedPosition;
1956
1957 if (attemptedPosition.X > Constants.RegionSize + 0.1f)
1958 {
1959 pos.X = ((pos.X - Constants.RegionSize));
1960 newRegionHandle
1961 = Util.UIntsToLong((uint)((thisx + 1) * Constants.RegionSize), (uint)(thisy * Constants.RegionSize));
1962 // x + 1
1963 }
1964 else if (attemptedPosition.X < -0.1f)
1965 {
1966 pos.X = ((pos.X + Constants.RegionSize));
1967 newRegionHandle
1968 = Util.UIntsToLong((uint)((thisx - 1) * Constants.RegionSize), (uint)(thisy * Constants.RegionSize));
1969 // x - 1
1970 }
1971
1972 if (attemptedPosition.Y > Constants.RegionSize + 0.1f)
1973 {
1974 pos.Y = ((pos.Y - Constants.RegionSize));
1975 newRegionHandle
1976 = Util.UIntsToLong((uint)(thisx * Constants.RegionSize), (uint)((thisy + 1) * Constants.RegionSize));
1977 // y + 1
1978 }
1979 else if (attemptedPosition.Y < -0.1f)
1980 {
1981 pos.Y = ((pos.Y + Constants.RegionSize));
1982 newRegionHandle
1983 = Util.UIntsToLong((uint)(thisx * Constants.RegionSize), (uint)((thisy - 1) * Constants.RegionSize));
1984 // y - 1
1985 }
1986
1987 // Offset the positions for the new region across the border
1988 Vector3 oldGroupPosition = grp.RootPart.GroupPosition;
1989 grp.OffsetForNewRegion(pos);
1990
1991 // If we fail to cross the border, then reset the position of the scene object on that border.
1992 if (!CrossPrimGroupIntoNewRegion(newRegionHandle, grp, silent))
1993 {
1994 grp.OffsetForNewRegion(oldGroupPosition);
1995 grp.ScheduleGroupForFullUpdate();
1996 }
1997 }
1998
1999 /// <summary>
2000 /// Move the given scene object into a new region
2001 /// </summary>
2002 /// <param name="newRegionHandle"></param>
2003 /// <param name="grp">Scene Object Group that we're crossing</param>
2004 /// <returns>
2005 /// true if the crossing itself was successful, false on failure
2006 /// FIMXE: we still return true if the crossing object was not successfully deleted from the originating region
2007 /// </returns>
2008 public bool CrossPrimGroupIntoNewRegion(ulong newRegionHandle, SceneObjectGroup grp, bool silent)
2009 {
2010 bool successYN = false;
2011 grp.RootPart.UpdateFlag = 0;
2012 int primcrossingXMLmethod = 0;
2013
2014 if (newRegionHandle != 0)
2015 {
2016 string objectState = grp.GetStateSnapshot();
2017
2018 successYN
2019 = m_sceneGridService.PrimCrossToNeighboringRegion(
2020 newRegionHandle, grp.UUID, m_serialiser.SaveGroupToXml2(grp), primcrossingXMLmethod);
2021 if (successYN && (objectState != "") && m_allowScriptCrossings)
2022 {
2023 successYN = m_sceneGridService.PrimCrossToNeighboringRegion(
2024 newRegionHandle, grp.UUID, objectState, 100);
2025 }
2026
2027 if (successYN)
2028 {
2029 // We remove the object here
2030 try
2031 {
2032 DeleteSceneObject(grp, silent);
2033 }
2034 catch (Exception e)
2035 {
2036 m_log.ErrorFormat(
2037 "[INTERREGION]: Exception deleting the old object left behind on a border crossing for {0}, {1}",
2038 grp, e);
2039 }
2040 }
2041 else
2042 {
2043 if (!grp.IsDeleted)
2044 {
2045 if (grp.RootPart.PhysActor != null)
2046 {
2047 grp.RootPart.PhysActor.CrossingFailure();
2048 }
2049 }
2050
2051 m_log.ErrorFormat("[INTERREGION]: Prim crossing failed for {0}", grp);
2052 }
2053 }
2054 else
2055 {
2056 m_log.Error("[INTERREGION]: region handle was unexpectedly 0 in Scene.CrossPrimGroupIntoNewRegion()");
2057 }
2058
2059 return successYN;
2060 }
2061
2062 /// <summary>
2063 /// Handle a scene object that is crossing into this region from another.
2064 /// </summary>
2065 /// <param name="regionHandle"></param>
2066 /// <param name="primID"></param>
2067 /// <param name="objXMLData"></param>
2068 /// <param name="XMLMethod"></param>
2069 /// <returns></returns>
2070 public bool IncomingInterRegionPrimGroup(UUID primID, string objXMLData, int XMLMethod)
2071 {
2072
2073 if (XMLMethod == 0)
2074 {
2075 m_log.DebugFormat("[INTERREGION]: A new prim {0} arrived from a neighbor", primID);
2076 SceneObjectGroup sceneObject = m_serialiser.DeserializeGroupFromXml2(objXMLData);
2077
2078 // If the user is banned, we won't let any of their objects
2079 // enter. Period.
2080 //
2081 if (m_regInfo.EstateSettings.IsBanned(sceneObject.OwnerID))
2082 {
2083 m_log.Info("[INTERREGION]: Denied prim crossing for "+
2084 "banned avatar");
2085
2086 return false;
2087 }
2088
2089 // Force allocation of new LocalId
2090 //
2091 foreach (SceneObjectPart p in sceneObject.Children.Values)
2092 p.LocalId = 0;
2093
2094 if (sceneObject.RootPart.Shape.PCode == (byte)PCode.Prim)
2095 {
2096 if (sceneObject.RootPart.Shape.State != 0)
2097 {
2098 // Fix up attachment Parent Local ID
2099 //
2100 ScenePresence sp = GetScenePresence(sceneObject.OwnerID);
2101
2102 uint parentLocalID = 0;
2103 if (sp != null)
2104 parentLocalID = sp.LocalId;
2105
2106 sceneObject.RootPart.IsAttachment = true;
2107 sceneObject.RootPart.SetParentLocalId(parentLocalID);
2108
2109 AddRestoredSceneObject(sceneObject, false, false);
2110
2111 // Handle attachment special case
2112 //
2113 SceneObjectPart RootPrim = GetSceneObjectPart(primID);
2114
2115 if (RootPrim != null)
2116 {
2117 SceneObjectGroup grp = RootPrim.ParentGroup;
2118
2119 RootPrim.SetParentLocalId(parentLocalID);
2120
2121 if (grp != null)
2122 {
2123 m_log.DebugFormat("[ATTACHMENT]: Received "+
2124 "attachment {0}, inworld asset id {1}",
2125 grp.RootPart.LastOwnerID.ToString(),
2126 grp.UUID.ToString());
2127
2128 if (sp != null)
2129 {
2130 grp.SetFromAssetID(grp.RootPart.LastOwnerID);
2131 m_log.DebugFormat("[ATTACHMENT]: Attach "+
2132 "to avatar {0}",
2133 sp.UUID.ToString());
2134 AttachObject(sp.ControllingClient,
2135 grp.LocalId, (uint)0,
2136 grp.GroupRotation,
2137 grp.AbsolutePosition, false);
2138 grp.SendGroupFullUpdate();
2139 }
2140 else
2141 {
2142 RootPrim.RemFlag(PrimFlags.TemporaryOnRez);
2143 RootPrim.AddFlag(PrimFlags.TemporaryOnRez);
2144 }
2145 }
2146 }
2147 }
2148 else
2149 {
2150 AddRestoredSceneObject(sceneObject, true, false);
2151
2152 if (!Permissions.CanObjectEntry(sceneObject.UUID,
2153 true, sceneObject.AbsolutePosition))
2154 {
2155 // Deny non attachments based on parcel settings
2156 //
2157 m_log.Info("[INTERREGION]: Denied prim crossing "+
2158 "because of parcel settings");
2159
2160 DeleteSceneObject(sceneObject, false);
2161
2162 return false;
2163 }
2164 }
2165 }
2166 }
2167 else if ((XMLMethod == 100) && m_allowScriptCrossings)
2168 {
2169 m_log.Warn("[INTERREGION]: Prim state data arrived from a neighbor");
2170 XmlDocument doc = new XmlDocument();
2171 doc.LoadXml(objXMLData);
2172
2173 XmlNodeList rootL = doc.GetElementsByTagName("ScriptData");
2174 if (rootL.Count == 1)
2175 {
2176 XmlNode rootNode = rootL[0];
2177 if (rootNode != null)
2178 {
2179 XmlNodeList partL = rootNode.ChildNodes;
2180
2181 foreach (XmlNode part in partL)
2182 {
2183 XmlNodeList nodeL = part.ChildNodes;
2184
2185 switch (part.Name)
2186 {
2187 case "Assemblies":
2188 foreach (XmlNode asm in nodeL)
2189 {
2190 string fn = asm.Attributes.GetNamedItem("Filename").Value;
2191
2192 Byte[] filedata = Convert.FromBase64String(asm.InnerText);
2193 string path = Path.Combine("ScriptEngines", RegionInfo.RegionID.ToString());
2194 path = Path.Combine(path, fn);
2195
2196 if (!File.Exists(path))
2197 {
2198 FileStream fs = File.Create(path);
2199 fs.Write(filedata, 0, filedata.Length);
2200 fs.Close();
2201 }
2202 }
2203 break;
2204 case "ScriptStates":
2205 foreach (XmlNode st in nodeL)
2206 {
2207 string id = st.Attributes.GetNamedItem("UUID").Value;
2208 UUID uuid = new UUID(id);
2209 XmlNode state = st.ChildNodes[0];
2210
2211 XmlDocument sdoc = new XmlDocument();
2212 XmlNode sxmlnode = sdoc.CreateNode(
2213 XmlNodeType.XmlDeclaration,
2214 "", "");
2215 sdoc.AppendChild(sxmlnode);
2216
2217 XmlNode newnode = sdoc.ImportNode(state, true);
2218 sdoc.AppendChild(newnode);
2219
2220 string spath = Path.Combine("ScriptEngines", RegionInfo.RegionID.ToString());
2221 spath = Path.Combine(spath, uuid.ToString());
2222 FileStream sfs = File.Create(spath + ".state");
2223 System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
2224 Byte[] buf = enc.GetBytes(sdoc.InnerXml);
2225 sfs.Write(buf, 0, buf.Length);
2226 sfs.Close();
2227 }
2228 break;
2229 }
2230 }
2231 }
2232 }
2233
2234 SceneObjectPart RootPrim = GetSceneObjectPart(primID);
2235 RootPrim.ParentGroup.CreateScriptInstances(0, false, DefaultScriptEngine, 1);
2236
2237 return true;
2238 }
2239
2240 return true;
2241 }
2242
2243 #endregion
2244
2245 #region Add/Remove Avatar Methods
2246
2247 public override void AddNewClient(IClientAPI client)
2248 {
2249 SubscribeToClientEvents(client);
2250 ScenePresence presence;
2251
2252 if (m_restorePresences.ContainsKey(client.AgentId))
2253 {
2254 m_log.DebugFormat("[SCENE]: Restoring agent {0} {1} in {2}", client.Name, client.AgentId, RegionInfo.RegionName);
2255
2256 presence = m_restorePresences[client.AgentId];
2257 m_restorePresences.Remove(client.AgentId);
2258
2259 // This is one of two paths to create avatars that are
2260 // used. This tends to get called more in standalone
2261 // than grid, not really sure why, but as such needs
2262 // an explicity appearance lookup here.
2263 AvatarAppearance appearance = null;
2264 GetAvatarAppearance(client, out appearance);
2265 presence.Appearance = appearance;
2266
2267 presence.initializeScenePresence(client, RegionInfo, this);
2268
2269 m_sceneGraph.AddScenePresence(presence);
2270
2271 lock (m_restorePresences)
2272 {
2273 Monitor.PulseAll(m_restorePresences);
2274 }
2275 }
2276 else
2277 {
2278 m_log.DebugFormat(
2279 "[SCENE]: Adding new child agent for {0} in {1}",
2280 client.Name, RegionInfo.RegionName);
2281
2282 CommsManager.UserProfileCacheService.AddNewUser(client.AgentId);
2283
2284 CreateAndAddScenePresence(client);
2285 }
2286
2287 m_LastLogin = System.Environment.TickCount;
2288 EventManager.TriggerOnNewClient(client);
2289 }
2290
2291 protected virtual void SubscribeToClientEvents(IClientAPI client)
2292 {
2293 client.OnRegionHandShakeReply += SendLayerData;
2294 client.OnAddPrim += AddNewPrim;
2295 client.OnUpdatePrimGroupPosition += m_sceneGraph.UpdatePrimPosition;
2296 client.OnUpdatePrimSinglePosition += m_sceneGraph.UpdatePrimSinglePosition;
2297 client.OnUpdatePrimGroupRotation += m_sceneGraph.UpdatePrimRotation;
2298 client.OnUpdatePrimGroupMouseRotation += m_sceneGraph.UpdatePrimRotation;
2299 client.OnUpdatePrimSingleRotation += m_sceneGraph.UpdatePrimSingleRotation;
2300 client.OnUpdatePrimScale += m_sceneGraph.UpdatePrimScale;
2301 client.OnUpdatePrimGroupScale += m_sceneGraph.UpdatePrimGroupScale;
2302 client.OnUpdateExtraParams += m_sceneGraph.UpdateExtraParam;
2303 client.OnUpdatePrimShape += m_sceneGraph.UpdatePrimShape;
2304 client.OnUpdatePrimTexture += m_sceneGraph.UpdatePrimTexture;
2305 client.OnTeleportLocationRequest += RequestTeleportLocation;
2306 client.OnTeleportLandmarkRequest += RequestTeleportLandmark;
2307 client.OnObjectSelect += SelectPrim;
2308 client.OnObjectDeselect += DeselectPrim;
2309 client.OnGrabUpdate += m_sceneGraph.MoveObject;
2310 client.OnDeRezObject += DeRezObject;
2311 client.OnRezObject += RezObject;
2312 client.OnRezSingleAttachmentFromInv += RezSingleAttachment;
2313 client.OnDetachAttachmentIntoInv += DetachSingleAttachmentToInv;
2314 client.OnObjectAttach += m_sceneGraph.AttachObject;
2315 client.OnObjectDetach += m_sceneGraph.DetachObject;
2316 client.OnObjectDrop += m_sceneGraph.DropObject;
2317 client.OnNameFromUUIDRequest += CommsManager.HandleUUIDNameRequest;
2318 client.OnObjectDescription += m_sceneGraph.PrimDescription;
2319 client.OnObjectName += m_sceneGraph.PrimName;
2320 client.OnObjectClickAction += m_sceneGraph.PrimClickAction;
2321 client.OnObjectMaterial += m_sceneGraph.PrimMaterial;
2322 client.OnLinkObjects += m_sceneGraph.LinkObjects;
2323 client.OnDelinkObjects += m_sceneGraph.DelinkObjects;
2324 client.OnObjectDuplicate += m_sceneGraph.DuplicateObject;
2325 client.OnObjectDuplicateOnRay += doObjectDuplicateOnRay;
2326 client.OnUpdatePrimFlags += m_sceneGraph.UpdatePrimFlags;
2327 client.OnRequestObjectPropertiesFamily += m_sceneGraph.RequestObjectPropertiesFamily;
2328 client.OnRequestGodlikePowers += handleRequestGodlikePowers;
2329 client.OnGodKickUser += HandleGodlikeKickUser;
2330 client.OnObjectPermissions += HandleObjectPermissionsUpdate;
2331 client.OnCreateNewInventoryItem += CreateNewInventoryItem;
2332 client.OnCreateNewInventoryFolder += HandleCreateInventoryFolder;
2333 client.OnUpdateInventoryFolder += HandleUpdateInventoryFolder;
2334 client.OnMoveInventoryFolder += HandleMoveInventoryFolder;
2335 client.OnFetchInventoryDescendents += HandleFetchInventoryDescendents;
2336 client.OnPurgeInventoryDescendents += HandlePurgeInventoryDescendents;
2337 client.OnFetchInventory += HandleFetchInventory;
2338 client.OnUpdateInventoryItem += UpdateInventoryItemAsset;
2339 client.OnCopyInventoryItem += CopyInventoryItem;
2340 client.OnMoveInventoryItem += MoveInventoryItem;
2341 client.OnRemoveInventoryItem += RemoveInventoryItem;
2342 client.OnRemoveInventoryFolder += RemoveInventoryFolder;
2343 client.OnRezScript += RezScript;
2344 client.OnRequestTaskInventory += RequestTaskInventory;
2345 client.OnRemoveTaskItem += RemoveTaskInventory;
2346 client.OnUpdateTaskInventory += UpdateTaskInventory;
2347 client.OnMoveTaskItem += ClientMoveTaskInventoryItem;
2348 client.OnGrabObject += ProcessObjectGrab;
2349 client.OnDeGrabObject += ProcessObjectDeGrab;
2350 client.OnMoneyTransferRequest += ProcessMoneyTransferRequest;
2351 client.OnParcelBuy += ProcessParcelBuy;
2352 client.OnAvatarPickerRequest += ProcessAvatarPickerRequest;
2353 client.OnObjectIncludeInSearch += m_sceneGraph.MakeObjectSearchable;
2354 client.OnTeleportHomeRequest += TeleportClientHome;
2355 client.OnSetStartLocationRequest += SetHomeRezPoint;
2356 client.OnUndo += m_sceneGraph.HandleUndo;
2357 client.OnObjectGroupRequest += m_sceneGraph.HandleObjectGroupUpdate;
2358 client.OnParcelReturnObjectsRequest += LandChannel.ReturnObjectsInParcel;
2359 client.OnParcelSetOtherCleanTime += LandChannel.SetParcelOtherCleanTime;
2360 client.OnObjectSaleInfo += ObjectSaleInfo;
2361 client.OnScriptReset += ProcessScriptReset;
2362 client.OnGetScriptRunning += GetScriptRunning;
2363 client.OnSetScriptRunning += SetScriptRunning;
2364 client.OnRegionHandleRequest += RegionHandleRequest;
2365 client.OnUnackedTerrain += TerrainUnAcked;
2366
2367 client.OnObjectOwner += ObjectOwner;
2368
2369 if (StatsReporter != null)
2370 client.OnNetworkStatsUpdate += StatsReporter.AddPacketsFromClientStats;
2371
2372 // EventManager.TriggerOnNewClient(client);
2373 }
2374
2375 /// <summary>
2376 /// Teleport an avatar to their home region
2377 /// </summary>
2378 /// <param name="agentId"></param>
2379 /// <param name="client"></param>
2380 public virtual void TeleportClientHome(UUID agentId, IClientAPI client)
2381 {
2382 UserProfileData UserProfile = CommsManager.UserService.GetUserProfile(agentId);
2383 if (UserProfile != null)
2384 {
2385 RegionInfo regionInfo = CommsManager.GridService.RequestNeighbourInfo(UserProfile.HomeRegionID);
2386 if (regionInfo == null)
2387 {
2388 regionInfo = CommsManager.GridService.RequestNeighbourInfo(UserProfile.HomeRegion);
2389 if (regionInfo != null) // home region can be away temporarily, too
2390 {
2391 UserProfile.HomeRegionID = regionInfo.RegionID;
2392 CommsManager.UserService.UpdateUserProfile(UserProfile);
2393 }
2394 }
2395 if (regionInfo == null)
2396 {
2397 // can't find the Home region: Tell viewer and abort
2398 client.SendTeleportFailed("Your home-region could not be found.");
2399 return;
2400 }
2401 RequestTeleportLocation(
2402 client, regionInfo.RegionHandle, UserProfile.HomeLocation, UserProfile.HomeLookAt,
2403 (uint)(TPFlags.SetLastToTarget | TPFlags.ViaHome));
2404 }
2405 }
2406
2407 public void doObjectDuplicateOnRay(uint localID, uint dupeFlags, UUID AgentID, UUID GroupID,
2408 UUID RayTargetObj, Vector3 RayEnd, Vector3 RayStart,
2409 bool BypassRaycast, bool RayEndIsIntersection, bool CopyCenters, bool CopyRotates)
2410 {
2411 Vector3 pos;
2412 const bool frontFacesOnly = true;
2413 //m_log.Info("HITTARGET: " + RayTargetObj.ToString() + ", COPYTARGET: " + localID.ToString());
2414 SceneObjectPart target = GetSceneObjectPart(localID);
2415 SceneObjectPart target2 = GetSceneObjectPart(RayTargetObj);
2416
2417 if (target != null && target2 != null)
2418 {
2419 Vector3 direction = Vector3.Normalize(RayEnd - RayStart);
2420 Vector3 AXOrigin = new Vector3(RayStart.X, RayStart.Y, RayStart.Z);
2421 Vector3 AXdirection = new Vector3(direction.X, direction.Y, direction.Z);
2422
2423 if (target2.ParentGroup != null)
2424 {
2425 pos = target2.AbsolutePosition;
2426 //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());
2427
2428 // TODO: Raytrace better here
2429
2430 //EntityIntersection ei = m_sceneGraph.GetClosestIntersectingPrim(new Ray(AXOrigin, AXdirection));
2431 Ray NewRay = new Ray(AXOrigin, AXdirection);
2432
2433 // Ray Trace against target here
2434 EntityIntersection ei = target2.TestIntersectionOBB(NewRay, Quaternion.Identity, frontFacesOnly, CopyCenters);
2435
2436 // Un-comment out the following line to Get Raytrace results printed to the console.
2437 //m_log.Info("[RAYTRACERESULTS]: Hit:" + ei.HitTF.ToString() + " Point: " + ei.ipoint.ToString() + " Normal: " + ei.normal.ToString());
2438 float ScaleOffset = 0.5f;
2439
2440 // If we hit something
2441 if (ei.HitTF)
2442 {
2443 Vector3 scale = target.Scale;
2444 Vector3 scaleComponent = new Vector3(ei.AAfaceNormal.X, ei.AAfaceNormal.Y, ei.AAfaceNormal.Z);
2445 if (scaleComponent.X != 0) ScaleOffset = scale.X;
2446 if (scaleComponent.Y != 0) ScaleOffset = scale.Y;
2447 if (scaleComponent.Z != 0) ScaleOffset = scale.Z;
2448 ScaleOffset = Math.Abs(ScaleOffset);
2449 Vector3 intersectionpoint = new Vector3(ei.ipoint.X, ei.ipoint.Y, ei.ipoint.Z);
2450 Vector3 normal = new Vector3(ei.normal.X, ei.normal.Y, ei.normal.Z);
2451 Vector3 offset = normal * (ScaleOffset / 2f);
2452 pos = intersectionpoint + offset;
2453
2454 // stick in offset format from the original prim
2455 pos = pos - target.ParentGroup.AbsolutePosition;
2456 if (CopyRotates)
2457 {
2458 Quaternion worldRot = target2.GetWorldRotation();
2459
2460 // SceneObjectGroup obj = m_sceneGraph.DuplicateObject(localID, pos, target.GetEffectiveObjectFlags(), AgentID, GroupID, worldRot);
2461 m_sceneGraph.DuplicateObject(localID, pos, target.GetEffectiveObjectFlags(), AgentID, GroupID, worldRot);
2462 //obj.Rotation = worldRot;
2463 //obj.UpdateGroupRotation(worldRot);
2464 }
2465 else
2466 {
2467 m_sceneGraph.DuplicateObject(localID, pos, target.GetEffectiveObjectFlags(), AgentID, GroupID);
2468 }
2469 }
2470
2471 return;
2472 }
2473
2474 return;
2475 }
2476 }
2477
2478 public virtual void SetHomeRezPoint(IClientAPI remoteClient, ulong regionHandle, Vector3 position, Vector3 lookAt, uint flags)
2479 {
2480 UserProfileData UserProfile = CommsManager.UserService.GetUserProfile(remoteClient.AgentId);
2481 if (UserProfile != null)
2482 {
2483 // I know I'm ignoring the regionHandle provided by the teleport location request.
2484 // reusing the TeleportLocationRequest delegate, so regionHandle isn't valid
2485 UserProfile.HomeRegionID = RegionInfo.RegionID;
2486 // TODO: The next line can be removed, as soon as only homeRegionID based UserServers are around.
2487 // TODO: The HomeRegion property can be removed then, too
2488 UserProfile.HomeRegion = RegionInfo.RegionHandle;
2489 UserProfile.HomeLocation = position;
2490 UserProfile.HomeLookAt = lookAt;
2491 CommsManager.UserService.UpdateUserProfile(UserProfile);
2492
2493 // FUBAR ALERT: this needs to be "Home position set." so the viewer saves a home-screenshot.
2494 m_dialogModule.SendAlertToUser(remoteClient, "Home position set.");
2495 }
2496 else
2497 {
2498 m_dialogModule.SendAlertToUser(remoteClient, "Set Home request Failed.");
2499 }
2500 }
2501
2502 /// <summary>
2503 /// Create a child agent scene presence and add it to this scene.
2504 /// </summary>
2505 /// <param name="client"></param>
2506 /// <returns></returns>
2507 protected virtual ScenePresence CreateAndAddScenePresence(IClientAPI client)
2508 {
2509 AvatarAppearance appearance = null;
2510 GetAvatarAppearance(client, out appearance);
2511
2512 ScenePresence avatar = m_sceneGraph.CreateAndAddChildScenePresence(client, appearance);
2513 //avatar.KnownRegions = GetChildrenSeeds(avatar.UUID);
2514 return avatar;
2515 }
2516
2517 /// <summary>
2518 /// Get the avatar apperance for the given client.
2519 /// </summary>
2520 /// <param name="client"></param>
2521 /// <param name="appearance"></param>
2522 public void GetAvatarAppearance(IClientAPI client, out AvatarAppearance appearance)
2523 {
2524 appearance = new AvatarAppearance();
2525
2526 try
2527 {
2528 if (m_AvatarFactory != null)
2529 {
2530 if (m_AvatarFactory.TryGetAvatarAppearance(client.AgentId, out appearance))
2531 return;
2532 }
2533 }
2534 catch (Exception e)
2535 {
2536 m_log.ErrorFormat("[APPEARANCE]: Problem fetching appearance for avatar {0}, {1}",
2537 client.Name, e);
2538 }
2539
2540 m_log.Warn("[APPEARANCE]: Appearance not found, returning default");
2541 }
2542
2543 /// <summary>
2544 /// Remove the given client from the scene.
2545 /// </summary>
2546 /// <param name="agentID"></param>
2547 public override void RemoveClient(UUID agentID)
2548 {
2549 bool childagentYN = false;
2550 ScenePresence avatar = GetScenePresence(agentID);
2551 if (avatar != null)
2552 {
2553 childagentYN = avatar.IsChildAgent;
2554 }
2555
2556 try
2557 {
2558 m_log.DebugFormat(
2559 "[SCENE]: Removing {0} agent {1} from region {2}",
2560 (childagentYN ? "child" : "root"), agentID, RegionInfo.RegionName);
2561
2562 m_sceneGraph.removeUserCount(!childagentYN);
2563 CapsModule.RemoveCapsHandler(agentID);
2564
2565 if (avatar.Scene.NeedSceneCacheClear(avatar.UUID))
2566 {
2567 CommsManager.UserProfileCacheService.RemoveUser(agentID);
2568 }
2569
2570 if (!avatar.IsChildAgent)
2571 {
2572 m_sceneGridService.LogOffUser(agentID, RegionInfo.RegionID, RegionInfo.RegionHandle, avatar.AbsolutePosition, avatar.Lookat);
2573 //List<ulong> childknownRegions = new List<ulong>();
2574 //List<ulong> ckn = avatar.KnownChildRegionHandles;
2575 //for (int i = 0; i < ckn.Count; i++)
2576 //{
2577 // childknownRegions.Add(ckn[i]);
2578 //}
2579 List<ulong> regions = new List<ulong>(avatar.KnownChildRegionHandles);
2580 regions.Remove(RegionInfo.RegionHandle);
2581 m_sceneGridService.SendCloseChildAgentConnections(agentID, regions);
2582
2583 }
2584 m_eventManager.TriggerClientClosed(agentID);
2585 }
2586 catch (NullReferenceException)
2587 {
2588 // We don't know which count to remove it from
2589 // Avatar is already disposed :/
2590 }
2591
2592 m_eventManager.TriggerOnRemovePresence(agentID);
2593 Broadcast(delegate(IClientAPI client)
2594 {
2595 try
2596 {
2597 client.SendKillObject(avatar.RegionHandle, avatar.LocalId);
2598 }
2599 catch (NullReferenceException)
2600 {
2601 //We can safely ignore null reference exceptions. It means the avatar are dead and cleaned up anyway.
2602 }
2603 });
2604
2605 ForEachScenePresence(
2606 delegate(ScenePresence presence) { presence.CoarseLocationChange(); });
2607
2608 IAgentAssetTransactions agentTransactions = this.RequestModuleInterface<IAgentAssetTransactions>();
2609 if (agentTransactions != null)
2610 {
2611 agentTransactions.RemoveAgentAssetTransactions(agentID);
2612 }
2613
2614 m_sceneGraph.RemoveScenePresence(agentID);
2615
2616 try
2617 {
2618 avatar.Close();
2619 }
2620 catch (NullReferenceException)
2621 {
2622 //We can safely ignore null reference exceptions. It means the avatar are dead and cleaned up anyway.
2623 }
2624 catch (Exception e)
2625 {
2626 m_log.Error("[SCENE] Scene.cs:RemoveClient exception: " + e.ToString());
2627 }
2628
2629 // Remove client agent from profile, so new logins will work
2630 if (!childagentYN)
2631 {
2632 m_sceneGridService.ClearUserAgent(agentID);
2633 }
2634
2635 //m_log.InfoFormat("[SCENE] Memory pre GC {0}", System.GC.GetTotalMemory(false));
2636 //m_log.InfoFormat("[SCENE] Memory post GC {0}", System.GC.GetTotalMemory(true));
2637 }
2638
2639 public void HandleRemoveKnownRegionsFromAvatar(UUID avatarID, List<ulong> regionslst)
2640 {
2641 ScenePresence av = GetScenePresence(avatarID);
2642 if (av != null)
2643 {
2644 lock (av)
2645 {
2646
2647 for (int i = 0; i < regionslst.Count; i++)
2648 {
2649 av.KnownChildRegionHandles.Remove(regionslst[i]);
2650 }
2651 }
2652 }
2653 }
2654
2655 public override void CloseAllAgents(uint circuitcode)
2656 {
2657 // Called by ClientView to kill all circuit codes
2658 ClientManager.CloseAllAgents(circuitcode);
2659 }
2660
2661 public void NotifyMyCoarseLocationChange()
2662 {
2663 ForEachScenePresence(delegate(ScenePresence presence) { presence.CoarseLocationChange(); });
2664 }
2665
2666 #endregion
2667
2668 #region Entities
2669
2670 public void SendKillObject(uint localID)
2671 {
2672 SceneObjectPart part = GetSceneObjectPart(localID);
2673 if (part != null) // It is a prim
2674 {
2675 if (part.ParentGroup != null && !part.ParentGroup.IsDeleted) // Valid
2676 {
2677 if (part.ParentGroup.RootPart != part) // Child part
2678 return;
2679 }
2680 }
2681 Broadcast(delegate(IClientAPI client) { client.SendKillObject(m_regionHandle, localID); });
2682 }
2683
2684 #endregion
2685
2686 #region RegionComms
2687
2688 /// <summary>
2689 /// Register the methods that should be invoked when this scene receives various incoming events
2690 /// </summary>
2691 public void RegisterCommsEvents()
2692 {
2693 m_sceneGridService.OnExpectUser += NewUserConnection;
2694 m_sceneGridService.OnAvatarCrossingIntoRegion += AgentCrossing;
2695 m_sceneGridService.OnCloseAgentConnection += IncomingCloseAgent;
2696 m_sceneGridService.OnRegionUp += OtherRegionUp;
2697 //m_sceneGridService.OnChildAgentUpdate += IncomingChildAgentDataUpdate;
2698 m_sceneGridService.OnExpectPrim += IncomingInterRegionPrimGroup;
2699 //m_sceneGridService.OnRemoveKnownRegionFromAvatar += HandleRemoveKnownRegionsFromAvatar;
2700 m_sceneGridService.OnLogOffUser += HandleLogOffUserFromGrid;
2701 m_sceneGridService.KiPrimitive += SendKillObject;
2702 m_sceneGridService.OnGetLandData += GetLandData;
2703
2704 if (m_interregionCommsIn != null)
2705 {
2706 m_log.Debug("[SCENE]: Registering with InterregionCommsIn");
2707 m_interregionCommsIn.OnChildAgentUpdate += IncomingChildAgentDataUpdate;
2708 }
2709 else
2710 m_log.Debug("[SCENE]: Unable to register with InterregionCommsIn");
2711
2712 }
2713
2714 /// <summary>
2715 /// Deregister this scene from receiving incoming region events
2716 /// </summary>
2717 public void UnRegisterRegionWithComms()
2718 {
2719 m_sceneGridService.KiPrimitive -= SendKillObject;
2720 m_sceneGridService.OnLogOffUser -= HandleLogOffUserFromGrid;
2721 //m_sceneGridService.OnRemoveKnownRegionFromAvatar -= HandleRemoveKnownRegionsFromAvatar;
2722 m_sceneGridService.OnExpectPrim -= IncomingInterRegionPrimGroup;
2723 //m_sceneGridService.OnChildAgentUpdate -= IncomingChildAgentDataUpdate;
2724 m_sceneGridService.OnRegionUp -= OtherRegionUp;
2725 m_sceneGridService.OnExpectUser -= NewUserConnection;
2726 m_sceneGridService.OnAvatarCrossingIntoRegion -= AgentCrossing;
2727 m_sceneGridService.OnCloseAgentConnection -= IncomingCloseAgent;
2728 m_sceneGridService.OnGetLandData -= GetLandData;
2729
2730 if (m_interregionCommsIn != null)
2731 m_interregionCommsIn.OnChildAgentUpdate -= IncomingChildAgentDataUpdate;
2732
2733 m_sceneGridService.Close();
2734 }
2735
2736 /// <summary>
2737 /// Do the work necessary to initiate a new user connection for a particular scene.
2738 /// At the moment, this consists of setting up the caps infrastructure
2739 /// </summary>
2740 /// <param name="regionHandle"></param>
2741 /// <param name="agent"></param>
2742 public void NewUserConnection(AgentCircuitData agent)
2743 {
2744 CapsModule.NewUserConnection(agent);
2745
2746 ScenePresence sp = m_sceneGraph.GetScenePresence(agent.AgentID);
2747 if (sp != null)
2748 {
2749 m_log.DebugFormat(
2750 "[SCENE]: Adjusting known seeds for existing agent {0} in {1}",
2751 agent.AgentID, RegionInfo.RegionName);
2752
2753 sp.AdjustKnownSeeds();
2754
2755 return;
2756 }
2757
2758 // Don't disable this log message - it's too helpful
2759 m_log.DebugFormat(
2760 "[CONNECTION BEGIN]: Region {0} told of incoming client {1} {2} {3} (circuit code {4})",
2761 RegionInfo.RegionName, agent.firstname, agent.lastname, agent.AgentID, agent.circuitcode);
2762
2763 if (m_regInfo.EstateSettings.IsBanned(agent.AgentID))
2764 {
2765 m_log.WarnFormat(
2766 "[CONNECTION BEGIN]: Denied access to: {0} at {1} because the user is on the region banlist",
2767 agent.AgentID, RegionInfo.RegionName);
2768 }
2769
2770 CapsModule.AddCapsHandler(agent.AgentID);
2771
2772 if (!agent.child)
2773 {
2774 // Honor parcel landing type and position.
2775 ILandObject land = LandChannel.GetLandObject(agent.startpos.X, agent.startpos.Y);
2776 if (land != null)
2777 {
2778 if (land.landData.LandingType == (byte)1 && land.landData.UserLocation != Vector3.Zero)
2779 {
2780 agent.startpos = land.landData.UserLocation;
2781 }
2782 }
2783 }
2784
2785 m_authenticateHandler.AddNewCircuit(agent.circuitcode, agent);
2786
2787 // rewrite session_id
2788 CachedUserInfo userinfo = CommsManager.UserProfileCacheService.GetUserDetails(agent.AgentID);
2789
2790 if (userinfo != null)
2791 {
2792 userinfo.SessionID = agent.SessionID;
2793 }
2794 else
2795 {
2796 m_log.WarnFormat(
2797 "[CONNECTION BEGIN]: We couldn't find a User Info record for {0}. This is usually an indication that the UUID we're looking up is invalid", agent.AgentID);
2798 }
2799 }
2800
2801 public void UpdateCircuitData(AgentCircuitData data)
2802 {
2803 m_authenticateHandler.UpdateAgentData(data);
2804 }
2805
2806 public bool ChangeCircuitCode(uint oldcc, uint newcc)
2807 {
2808 return m_authenticateHandler.TryChangeCiruitCode(oldcc, newcc);
2809 }
2810
2811 protected void HandleLogOffUserFromGrid(UUID AvatarID, UUID RegionSecret, string message)
2812 {
2813 ScenePresence loggingOffUser = null;
2814 loggingOffUser = GetScenePresence(AvatarID);
2815 if (loggingOffUser != null)
2816 {
2817 UUID localRegionSecret = UUID.Zero;
2818 bool parsedsecret = UUID.TryParse(m_regInfo.regionSecret, out localRegionSecret);
2819
2820 // Region Secret is used here in case a new sessionid overwrites an old one on the user server.
2821 // Will update the user server in a few revisions to use it.
2822
2823 if (RegionSecret == loggingOffUser.ControllingClient.SecureSessionId || (parsedsecret && RegionSecret == localRegionSecret))
2824 {
2825 m_sceneGridService.SendCloseChildAgentConnections(loggingOffUser.UUID, new List<ulong>(loggingOffUser.KnownRegions.Keys));
2826 loggingOffUser.ControllingClient.Kick(message);
2827 // Give them a second to receive the message!
2828 System.Threading.Thread.Sleep(1000);
2829 loggingOffUser.ControllingClient.Close(true);
2830 }
2831 else
2832 {
2833 m_log.Info("[USERLOGOFF]: System sending the LogOff user message failed to sucessfully authenticate");
2834 }
2835 }
2836 else
2837 {
2838 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());
2839 }
2840 }
2841
2842 /// <summary>
2843 /// Triggered when an agent crosses into this sim. Also happens on initial login.
2844 /// </summary>
2845 /// <param name="agentID"></param>
2846 /// <param name="position"></param>
2847 /// <param name="isFlying"></param>
2848 public virtual void AgentCrossing(UUID agentID, Vector3 position, bool isFlying)
2849 {
2850 ScenePresence presence;
2851
2852 lock (m_scenePresences)
2853 {
2854 m_scenePresences.TryGetValue(agentID, out presence);
2855 }
2856
2857 if (presence != null)
2858 {
2859 try
2860 {
2861 presence.MakeRootAgent(position, isFlying);
2862 }
2863 catch (Exception e)
2864 {
2865 m_log.ErrorFormat("[SCENE]: Unable to do agent crossing, exception {0}", e);
2866 }
2867 }
2868 else
2869 {
2870 m_log.ErrorFormat(
2871 "[SCENE]: Could not find presence for agent {0} crossing into scene {1}",
2872 agentID, RegionInfo.RegionName);
2873 }
2874 }
2875
2876 public virtual bool IncomingChildAgentDataUpdate(AgentData cAgentData)
2877 {
2878// m_log.DebugFormat(
2879// "[SCENE]: Incoming child agent update for {0} in {1}", cAgentData.AgentID, RegionInfo.RegionName);
2880
2881 // We have to wait until the viewer contacts this region after receiving EAC.
2882 // That calls AddNewClient, which finally creates the ScenePresence
2883 ScenePresence childAgentUpdate = WaitGetScenePresence(cAgentData.AgentID);
2884 if (childAgentUpdate != null)
2885 {
2886 childAgentUpdate.ChildAgentDataUpdate(cAgentData);
2887 return true;
2888 }
2889
2890 return false;
2891 }
2892
2893 public virtual bool IncomingChildAgentDataUpdate(AgentPosition cAgentData)
2894 {
2895 //Console.WriteLine(" XXX Scene IncomingChildAgentDataUpdate POSITION in " + RegionInfo.RegionName);
2896 ScenePresence childAgentUpdate = GetScenePresence(cAgentData.AgentID);
2897 if (childAgentUpdate != null)
2898 {
2899 // I can't imagine *yet* why we would get an update if the agent is a root agent..
2900 // however to avoid a race condition crossing borders..
2901 if (childAgentUpdate.IsChildAgent)
2902 {
2903 uint rRegionX = (uint)(cAgentData.RegionHandle >> 40);
2904 uint rRegionY = (((uint)(cAgentData.RegionHandle)) >> 8);
2905 uint tRegionX = RegionInfo.RegionLocX;
2906 uint tRegionY = RegionInfo.RegionLocY;
2907 //Send Data to ScenePresence
2908 childAgentUpdate.ChildAgentDataUpdate(cAgentData, tRegionX, tRegionY, rRegionX, rRegionY);
2909 // Not Implemented:
2910 //TODO: Do we need to pass the message on to one of our neighbors?
2911 }
2912
2913 return true;
2914 }
2915
2916 return false;
2917 }
2918
2919 protected virtual ScenePresence WaitGetScenePresence(UUID agentID)
2920 {
2921 int ntimes = 10;
2922 ScenePresence childAgentUpdate = null;
2923 while ((childAgentUpdate = GetScenePresence(agentID)) == null && (ntimes-- > 0))
2924 Thread.Sleep(1000);
2925 return childAgentUpdate;
2926
2927 }
2928
2929 public virtual bool IncomingReleaseAgent(UUID id)
2930 {
2931 return m_sceneGridService.ReleaseAgent(id);
2932 }
2933
2934 public void SendReleaseAgent(ulong regionHandle, UUID id, string uri)
2935 {
2936 m_interregionCommsOut.SendReleaseAgent(regionHandle, id, uri);
2937 }
2938
2939 /// <summary>
2940 /// Tell a single agent to disconnect from the region.
2941 /// </summary>
2942 /// <param name="regionHandle"></param>
2943 /// <param name="agentID"></param>
2944 public bool IncomingCloseAgent(UUID agentID)
2945 {
2946 //m_log.DebugFormat("[SCENE]: Processing incoming close agent for {0}", agentID);
2947
2948 ScenePresence presence = m_sceneGraph.GetScenePresence(agentID);
2949 if (presence != null)
2950 {
2951 // Nothing is removed here, so down count it as such
2952 if (presence.IsChildAgent)
2953 {
2954 m_sceneGraph.removeUserCount(false);
2955 }
2956 else
2957 {
2958 m_sceneGraph.removeUserCount(true);
2959 }
2960
2961 // Don't do this to root agents on logout, it's not nice for the viewer
2962 if (presence.IsChildAgent)
2963 {
2964 // Tell a single agent to disconnect from the region.
2965 IEventQueue eq = RequestModuleInterface<IEventQueue>();
2966 if (eq != null)
2967 {
2968 OSD Item = EventQueueHelper.DisableSimulator(RegionInfo.RegionHandle);
2969 eq.Enqueue(Item, agentID);
2970 }
2971 else
2972 presence.ControllingClient.SendShutdownConnectionNotice();
2973 }
2974
2975 presence.ControllingClient.Close(true);
2976 return true;
2977 }
2978
2979 // Agent not here
2980 return false;
2981 }
2982
2983 /// <summary>
2984 /// Tell neighboring regions about this agent
2985 /// When the regions respond with a true value,
2986 /// tell the agents about the region.
2987 ///
2988 /// We have to tell the regions about the agents first otherwise it'll deny them access
2989 ///
2990 /// </summary>
2991 /// <param name="presence"></param>
2992 public void InformClientOfNeighbours(ScenePresence presence)
2993 {
2994 m_sceneGridService.EnableNeighbourChildAgents(presence, m_neighbours);
2995 }
2996
2997 /// <summary>
2998 /// Tell a neighboring region about this agent
2999 /// </summary>
3000 /// <param name="presence"></param>
3001 /// <param name="region"></param>
3002 public void InformClientOfNeighbor(ScenePresence presence, RegionInfo region)
3003 {
3004 m_sceneGridService.InformNeighborChildAgent(presence, region, m_neighbours);
3005 }
3006
3007 /// <summary>
3008 /// Requests information about this region from gridcomms
3009 /// </summary>
3010 /// <param name="regionHandle"></param>
3011 /// <returns></returns>
3012 public RegionInfo RequestNeighbouringRegionInfo(ulong regionHandle)
3013 {
3014 return m_sceneGridService.RequestNeighbouringRegionInfo(regionHandle);
3015 }
3016
3017 /// <summary>
3018 /// Requests textures for map from minimum region to maximum region in world cordinates
3019 /// </summary>
3020 /// <param name="remoteClient"></param>
3021 /// <param name="minX"></param>
3022 /// <param name="minY"></param>
3023 /// <param name="maxX"></param>
3024 /// <param name="maxY"></param>
3025 public void RequestMapBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY)
3026 {
3027 m_log.InfoFormat("[MAPBLOCK]: {0}-{1}, {2}-{3}", minX, minY, maxX, maxY);
3028 m_sceneGridService.RequestMapBlocks(remoteClient, minX, minY, maxX, maxY);
3029 }
3030
3031 /// <summary>
3032 /// Tries to teleport agent to other region.
3033 /// </summary>
3034 /// <param name="remoteClient"></param>
3035 /// <param name="regionName"></param>
3036 /// <param name="position"></param>
3037 /// <param name="lookAt"></param>
3038 /// <param name="teleportFlags"></param>
3039 public void RequestTeleportLocation(IClientAPI remoteClient, string regionName, Vector3 position,
3040 Vector3 lookat, uint teleportFlags)
3041 {
3042 RegionInfo regionInfo = m_sceneGridService.RequestClosestRegion(regionName);
3043 if (regionInfo == null)
3044 {
3045 // can't find the region: Tell viewer and abort
3046 remoteClient.SendTeleportFailed("The region '" + regionName + "' could not be found.");
3047 return;
3048 }
3049
3050 RequestTeleportLocation(remoteClient, regionInfo.RegionHandle, position, lookat, teleportFlags);
3051 }
3052
3053 /// <summary>
3054 /// Tries to teleport agent to other region.
3055 /// </summary>
3056 /// <param name="remoteClient"></param>
3057 /// <param name="regionHandle"></param>
3058 /// <param name="position"></param>
3059 /// <param name="lookAt"></param>
3060 /// <param name="teleportFlags"></param>
3061 public void RequestTeleportLocation(IClientAPI remoteClient, ulong regionHandle, Vector3 position,
3062 Vector3 lookAt, uint teleportFlags)
3063 {
3064 ScenePresence sp = null;
3065 lock (m_scenePresences)
3066 {
3067 if (m_scenePresences.ContainsKey(remoteClient.AgentId))
3068 sp = m_scenePresences[remoteClient.AgentId];
3069 }
3070
3071 if (sp != null)
3072 {
3073 m_sceneGridService.RequestTeleportToLocation(sp, regionHandle,
3074 position, lookAt, teleportFlags);
3075 }
3076 }
3077
3078 /// <summary>
3079 /// Tries to teleport agent to landmark.
3080 /// </summary>
3081 /// <param name="remoteClient"></param>
3082 /// <param name="regionHandle"></param>
3083 /// <param name="position"></param>
3084 public void RequestTeleportLandmark(IClientAPI remoteClient, UUID regionID, Vector3 position)
3085 {
3086 RegionInfo info = CommsManager.GridService.RequestNeighbourInfo(regionID);
3087
3088 if (info == null)
3089 {
3090 // can't find the region: Tell viewer and abort
3091 remoteClient.SendTeleportFailed("The teleport destination could not be found.");
3092 return;
3093 }
3094
3095 ScenePresence sp = null;
3096 lock (m_scenePresences)
3097 {
3098 if (m_scenePresences.ContainsKey(remoteClient.AgentId))
3099 sp = m_scenePresences[remoteClient.AgentId];
3100 }
3101 if (sp != null)
3102 {
3103 m_sceneGridService.RequestTeleportToLocation(sp, info.RegionHandle,
3104 position, Vector3.Zero, (uint)(TPFlags.SetLastToTarget | TPFlags.ViaLandmark));
3105 }
3106 }
3107
3108 /// <summary>
3109 /// Agent is crossing the border into a neighbouring region. Tell the neighbour about it!
3110 /// </summary>
3111 /// <param name="regionHandle"></param>
3112 /// <param name="agentID"></param>
3113 /// <param name="position"></param>
3114 /// <param name="isFlying"></param>
3115 /// <returns></returns>
3116 public bool InformNeighbourOfCrossing(ulong regionHandle, UUID agentID, Vector3 position, bool isFlying)
3117 {
3118 return m_sceneGridService.CrossToNeighbouringRegion(regionHandle, agentID, position, isFlying);
3119 }
3120
3121 public void SendOutChildAgentUpdates(AgentPosition cadu, ScenePresence presence)
3122 {
3123 m_sceneGridService.SendChildAgentDataUpdate(cadu, presence);
3124 }
3125
3126 #endregion
3127
3128 #region Other Methods
3129
3130 public void SetObjectCapacity(int objects)
3131 {
3132 // Region specific config overrides global
3133 //
3134 if (RegionInfo.ObjectCapacity != 0)
3135 objects = RegionInfo.ObjectCapacity;
3136
3137 if (StatsReporter != null)
3138 {
3139 StatsReporter.SetObjectCapacity(objects);
3140 }
3141 objectCapacity = objects;
3142 }
3143
3144 public List<FriendListItem> GetFriendList(UUID avatarID)
3145 {
3146 return CommsManager.GetUserFriendList(avatarID);
3147 }
3148
3149 public Dictionary<UUID, FriendRegionInfo> GetFriendRegionInfos(List<UUID> uuids)
3150 {
3151 return CommsManager.GetFriendRegionInfos(uuids);
3152 }
3153
3154 public List<UUID> InformFriendsInOtherRegion(UUID agentId, ulong destRegionHandle, List<UUID> friends, bool online)
3155 {
3156 return CommsManager.InformFriendsInOtherRegion(agentId, destRegionHandle, friends, online);
3157 }
3158
3159 public bool TriggerTerminateFriend(ulong regionHandle, UUID agentID, UUID exFriendID)
3160 {
3161 return CommsManager.TriggerTerminateFriend(regionHandle, agentID, exFriendID);
3162 }
3163
3164 public virtual void StoreAddFriendship(UUID ownerID, UUID friendID, uint perms)
3165 {
3166 m_sceneGridService.AddNewUserFriend(ownerID, friendID, perms);
3167 }
3168
3169 public virtual void StoreUpdateFriendship(UUID ownerID, UUID friendID, uint perms)
3170 {
3171 m_sceneGridService.UpdateUserFriendPerms(ownerID, friendID, perms);
3172 }
3173
3174 public virtual void StoreRemoveFriendship(UUID ownerID, UUID ExfriendID)
3175 {
3176 m_sceneGridService.RemoveUserFriend(ownerID, ExfriendID);
3177 }
3178
3179 public void AddPacketStats(int inPackets, int outPackets, int unAckedBytes)
3180 {
3181 StatsReporter.AddInPackets(inPackets);
3182 StatsReporter.AddOutPackets(outPackets);
3183 StatsReporter.AddunAckedBytes(unAckedBytes);
3184 }
3185
3186 public void AddAgentTime(int ms)
3187 {
3188 StatsReporter.addFrameMS(ms);
3189 StatsReporter.addAgentMS(ms);
3190 }
3191
3192 public void AddAgentUpdates(int count)
3193 {
3194 StatsReporter.AddAgentUpdates(count);
3195 }
3196
3197 public void AddPendingDownloads(int count)
3198 {
3199 StatsReporter.addPendingDownload(count);
3200 }
3201
3202 #endregion
3203
3204 #region Alert Methods
3205
3206 /// <summary>
3207 /// Handle a request for admin rights
3208 /// </summary>
3209 /// <param name="agentID"></param>
3210 /// <param name="sessionID"></param>
3211 /// <param name="token"></param>
3212 /// <param name="controllingClient"></param>
3213 public void handleRequestGodlikePowers(UUID agentID, UUID sessionID, UUID token, bool godLike,
3214 IClientAPI controllingClient)
3215 {
3216 ScenePresence sp = null;
3217
3218 lock (m_scenePresences)
3219 {
3220 // User needs to be logged into this sim
3221 m_scenePresences.TryGetValue(agentID, out sp);
3222 }
3223
3224 if (sp != null)
3225 {
3226 if (godLike == false)
3227 {
3228 sp.GrantGodlikePowers(agentID, sessionID, token, godLike);
3229 return;
3230 }
3231
3232 // First check that this is the sim owner
3233 if (Permissions.IsGod(agentID))
3234 {
3235 // Next we check for spoofing.....
3236 UUID testSessionID = sp.ControllingClient.SessionId;
3237 if (sessionID == testSessionID)
3238 {
3239 if (sessionID == controllingClient.SessionId)
3240 {
3241 //m_log.Info("godlike: " + godLike.ToString());
3242 sp.GrantGodlikePowers(agentID, testSessionID, token, godLike);
3243 }
3244 }
3245 }
3246 else
3247 {
3248 m_dialogModule.SendAlertToUser(agentID, "Request for god powers denied");
3249 }
3250 }
3251 }
3252
3253 /// <summary>
3254 /// Kicks User specified from the simulator. This logs them off of the grid
3255 /// If the client gets the UUID: 44e87126e7944ded05b37c42da3d5cdb it assumes
3256 /// that you're kicking it even if the avatar's UUID isn't the UUID that the
3257 /// agent is assigned
3258 /// </summary>
3259 /// <param name="godID">The person doing the kicking</param>
3260 /// <param name="sessionID">The session of the person doing the kicking</param>
3261 /// <param name="agentID">the person that is being kicked</param>
3262 /// <param name="kickflags">This isn't used apparently</param>
3263 /// <param name="reason">The message to send to the user after it's been turned into a field</param>
3264 public void HandleGodlikeKickUser(UUID godID, UUID sessionID, UUID agentID, uint kickflags, byte[] reason)
3265 {
3266 // For some reason the client sends this seemingly hard coded UUID for kicking everyone. Dun-know.
3267 UUID kickUserID = new UUID("44e87126e7944ded05b37c42da3d5cdb");
3268 lock (m_scenePresences)
3269 {
3270 if (m_scenePresences.ContainsKey(agentID) || agentID == kickUserID)
3271 {
3272 if (Permissions.IsGod(godID))
3273 {
3274 if (agentID == kickUserID)
3275 {
3276 ClientManager.ForEachClient(delegate(IClientAPI controller)
3277 {
3278 if (controller.AgentId != godID)
3279 controller.Kick(Utils.BytesToString(reason));
3280 }
3281 );
3282
3283 // This is a bit crude. It seems the client will be null before it actually stops the thread
3284 // The thread will kill itself eventually :/
3285 // Is there another way to make sure *all* clients get this 'inter region' message?
3286 ClientManager.ForEachClient(delegate(IClientAPI controller)
3287 {
3288 ScenePresence p = GetScenePresence(controller.AgentId);
3289 bool childagent = p != null && p.IsChildAgent;
3290 if (controller.AgentId != godID && !childagent)
3291 // Do we really want to kick the initiator of this madness?
3292 {
3293 controller.Close(true);
3294 }
3295 }
3296 );
3297 }
3298 else
3299 {
3300 m_sceneGraph.removeUserCount(!m_scenePresences[agentID].IsChildAgent);
3301
3302 m_scenePresences[agentID].ControllingClient.Kick(Utils.BytesToString(reason));
3303 m_scenePresences[agentID].ControllingClient.Close(true);
3304 }
3305 }
3306 else
3307 {
3308 m_dialogModule.SendAlertToUser(godID, "Kick request denied");
3309 }
3310 }
3311 }
3312 }
3313
3314 public void HandleObjectPermissionsUpdate(IClientAPI controller, UUID agentID, UUID sessionID, byte field, uint localId, uint mask, byte set)
3315 {
3316 // Check for spoofing.. since this is permissions we're talking about here!
3317 if ((controller.SessionId == sessionID) && (controller.AgentId == agentID))
3318 {
3319 // Tell the object to do permission update
3320 if (localId != 0)
3321 {
3322 SceneObjectGroup chObjectGroup = GetGroupByPrim(localId);
3323 if (chObjectGroup != null)
3324 {
3325 chObjectGroup.UpdatePermissions(agentID, field, localId, mask, set);
3326 }
3327 }
3328 }
3329 }
3330
3331 /// <summary>
3332 /// Handle an alert command from the console.
3333 /// FIXME: Command parsing code really shouldn't be in this core Scene class.
3334 /// </summary>
3335 /// <param name="commandParams"></param>
3336 public void HandleAlertCommand(string[] commandParams)
3337 {
3338 if (commandParams[0] == "general")
3339 {
3340 string message = CombineParams(commandParams, 1);
3341 m_dialogModule.SendGeneralAlert(message);
3342 }
3343 else
3344 {
3345 string message = CombineParams(commandParams, 2);
3346 m_dialogModule.SendAlertToUser(commandParams[0], commandParams[1], message, false);
3347 }
3348 }
3349
3350 private string CombineParams(string[] commandParams, int pos)
3351 {
3352 string result = String.Empty;
3353 for (int i = pos; i < commandParams.Length; i++)
3354 {
3355 result += commandParams[i] + " ";
3356 }
3357 return result;
3358 }
3359
3360 #endregion
3361
3362 /// <summary>
3363 /// Causes all clients to get a full object update on all of the objects in the scene.
3364 /// </summary>
3365 public void ForceClientUpdate()
3366 {
3367 List<EntityBase> EntityList = GetEntities();
3368
3369 foreach (EntityBase ent in EntityList)
3370 {
3371 if (ent is SceneObjectGroup)
3372 {
3373 ((SceneObjectGroup)ent).ScheduleGroupForFullUpdate();
3374 }
3375 }
3376 }
3377
3378 /// <summary>
3379 /// This is currently only used for scale (to scale to MegaPrim size)
3380 /// There is a console command that calls this in OpenSimMain
3381 /// </summary>
3382 /// <param name="cmdparams"></param>
3383 public void HandleEditCommand(string[] cmdparams)
3384 {
3385 Console.WriteLine("Searching for Primitive: '" + cmdparams[0] + "'");
3386
3387 List<EntityBase> EntityList = GetEntities();
3388
3389 foreach (EntityBase ent in EntityList)
3390 {
3391 if (ent is SceneObjectGroup)
3392 {
3393 SceneObjectPart part = ((SceneObjectGroup)ent).GetChildPart(((SceneObjectGroup)ent).UUID);
3394 if (part != null)
3395 {
3396 if (part.Name == cmdparams[0])
3397 {
3398 part.Resize(
3399 new Vector3(Convert.ToSingle(cmdparams[1]), Convert.ToSingle(cmdparams[2]),
3400 Convert.ToSingle(cmdparams[3])));
3401
3402 Console.WriteLine("Edited scale of Primitive: " + part.Name);
3403 }
3404 }
3405 }
3406 }
3407 }
3408
3409 public override void Show(string[] showParams)
3410 {
3411 base.Show(showParams);
3412
3413 switch (showParams[0])
3414 {
3415 case "users":
3416 m_log.Error("Current Region: " + RegionInfo.RegionName);
3417 m_log.ErrorFormat("{0,-16}{1,-16}{2,-25}{3,-25}{4,-16}{5,-16}{6,-16}", "Firstname", "Lastname",
3418 "Agent ID", "Session ID", "Circuit", "IP", "World");
3419
3420 foreach (ScenePresence scenePresence in GetAvatars())
3421 {
3422 m_log.ErrorFormat("{0,-16}{1,-16}{2,-25}{3,-25}{4,-16},{5,-16}{6,-16}",
3423 scenePresence.Firstname,
3424 scenePresence.Lastname,
3425 scenePresence.UUID,
3426 scenePresence.ControllingClient.AgentId,
3427 "Unknown",
3428 "Unknown",
3429 RegionInfo.RegionName);
3430 }
3431
3432 break;
3433 }
3434 }
3435
3436 #region Script Handling Methods
3437
3438 /// <summary>
3439 /// Console command handler to send script command to script engine.
3440 /// </summary>
3441 /// <param name="args"></param>
3442 public void SendCommandToPlugins(string[] args)
3443 {
3444 m_eventManager.TriggerOnPluginConsole(args);
3445 }
3446
3447 public double GetLandHeight(int x, int y)
3448 {
3449 return Heightmap[x, y];
3450 }
3451
3452 public UUID GetLandOwner(float x, float y)
3453 {
3454 ILandObject land = LandChannel.GetLandObject(x, y);
3455 if (land == null)
3456 {
3457 return UUID.Zero;
3458 }
3459 else
3460 {
3461 return land.landData.OwnerID;
3462 }
3463 }
3464
3465 public LandData GetLandData(float x, float y)
3466 {
3467 return LandChannel.GetLandObject(x, y).landData;
3468 }
3469
3470 public LandData GetLandData(uint x, uint y)
3471 {
3472 m_log.DebugFormat("[SCENE] returning land for {0},{1}", x, y);
3473 return LandChannel.GetLandObject((int)x, (int)y).landData;
3474 }
3475
3476 public void SetLandMusicURL(float x, float y, string url)
3477 {
3478 ILandObject land = LandChannel.GetLandObject(x, y);
3479 if (land == null)
3480 {
3481 return;
3482 }
3483 else
3484 {
3485 land.landData.MusicURL = url;
3486 land.sendLandUpdateToAvatarsOverMe();
3487 return;
3488 }
3489 }
3490
3491 public void SetLandMediaURL(float x, float y, string url)
3492 {
3493 ILandObject land = LandChannel.GetLandObject(x, y);
3494
3495 if (land == null)
3496 {
3497 return;
3498 }
3499
3500 else
3501 {
3502 land.landData.MediaURL = url;
3503 land.sendLandUpdateToAvatarsOverMe();
3504 return;
3505 }
3506 }
3507
3508 public RegionInfo RequestClosestRegion(string name)
3509 {
3510 return m_sceneGridService.RequestClosestRegion(name);
3511 }
3512
3513 #endregion
3514
3515 #region Script Engine
3516
3517 private List<ScriptEngineInterface> ScriptEngines = new List<ScriptEngineInterface>();
3518 public bool DumpAssetsToFile;
3519
3520 /// <summary>
3521 ///
3522 /// </summary>
3523 /// <param name="scriptEngine"></param>
3524 public void AddScriptEngine(ScriptEngineInterface scriptEngine)
3525 {
3526 ScriptEngines.Add(scriptEngine);
3527 scriptEngine.InitializeEngine(this);
3528 }
3529
3530 public void TriggerObjectChanged(uint localID, uint change)
3531 {
3532 m_eventManager.TriggerOnScriptChangedEvent(localID, change);
3533 }
3534
3535 public void TriggerAtTargetEvent(uint localID, uint handle, Vector3 targetpos, Vector3 currentpos)
3536 {
3537 m_eventManager.TriggerAtTargetEvent(localID, handle, targetpos, currentpos);
3538 }
3539
3540 public void TriggerNotAtTargetEvent(uint localID)
3541 {
3542 m_eventManager.TriggerNotAtTargetEvent(localID);
3543 }
3544
3545 private bool ScriptDanger(SceneObjectPart part,Vector3 pos)
3546 {
3547 ILandObject parcel = LandChannel.GetLandObject(pos.X, pos.Y);
3548 if (part != null)
3549 {
3550 if (parcel != null)
3551 {
3552 if ((parcel.landData.Flags & (uint)Parcel.ParcelFlags.AllowOtherScripts) != 0)
3553 {
3554 return true;
3555 }
3556 else if ((parcel.landData.Flags & (uint)Parcel.ParcelFlags.AllowGroupScripts) != 0)
3557 {
3558 if (part.OwnerID == parcel.landData.OwnerID || (parcel.landData.IsGroupOwned && part.GroupID == parcel.landData.GroupID) || Permissions.IsGod(part.OwnerID))
3559 {
3560 return true;
3561 }
3562 else
3563 {
3564 return false;
3565 }
3566 }
3567 else
3568 {
3569 if (part.OwnerID == parcel.landData.OwnerID)
3570 {
3571 return true;
3572 }
3573 else
3574 {
3575 return false;
3576 }
3577 }
3578 }
3579 else
3580 {
3581
3582 if (pos.X > 0f && pos.X < Constants.RegionSize && pos.Y > 0f && pos.Y < Constants.RegionSize)
3583 {
3584 // The only time parcel != null when an object is inside a region is when
3585 // there is nothing behind the landchannel. IE, no land plugin loaded.
3586 return true;
3587 }
3588 else
3589 {
3590 // The object is outside of this region. Stop piping events to it.
3591 return false;
3592 }
3593 }
3594 }
3595 else
3596 {
3597 return false;
3598 }
3599 }
3600
3601 public bool ScriptDanger(uint localID, Vector3 pos)
3602 {
3603 SceneObjectPart part = GetSceneObjectPart(localID);
3604 if (part != null)
3605 {
3606 return ScriptDanger(part, pos);
3607 }
3608 else
3609 {
3610 return false;
3611 }
3612 }
3613
3614 public bool PipeEventsForScript(uint localID)
3615 {
3616 SceneObjectPart part = GetSceneObjectPart(localID);
3617 if (part != null)
3618 {
3619 // Changed so that child prims of attachments return ScriptDanger for their parent, so that
3620 // their scripts will actually run.
3621 // -- Leaf, Tue Aug 12 14:17:05 EDT 2008
3622 SceneObjectPart parent = part.ParentGroup.RootPart;
3623 if (parent != null && parent.IsAttachment)
3624 return ScriptDanger(parent, parent.GetWorldPosition());
3625 else
3626 return ScriptDanger(part, part.GetWorldPosition());
3627 }
3628 else
3629 {
3630 return false;
3631 }
3632 }
3633
3634 #endregion
3635
3636 #region SceneGraph wrapper methods
3637
3638 /// <summary>
3639 ///
3640 /// </summary>
3641 /// <param name="localID"></param>
3642 /// <returns></returns>
3643 public UUID ConvertLocalIDToFullID(uint localID)
3644 {
3645 return m_sceneGraph.ConvertLocalIDToFullID(localID);
3646 }
3647
3648 public void SwapRootAgentCount(bool rootChildChildRootTF)
3649 {
3650 m_sceneGraph.SwapRootChildAgent(rootChildChildRootTF);
3651 }
3652
3653 public void AddPhysicalPrim(int num)
3654 {
3655 m_sceneGraph.AddPhysicalPrim(num);
3656 }
3657
3658 public void RemovePhysicalPrim(int num)
3659 {
3660 m_sceneGraph.RemovePhysicalPrim(num);
3661 }
3662
3663 //The idea is to have a group of method that return a list of avatars meeting some requirement
3664 // ie it could be all m_scenePresences within a certain range of the calling prim/avatar.
3665
3666 /// <summary>
3667 /// Return a list of all avatars in this region.
3668 /// This list is a new object, so it can be iterated over without locking.
3669 /// </summary>
3670 /// <returns></returns>
3671 public List<ScenePresence> GetAvatars()
3672 {
3673 return m_sceneGraph.GetAvatars();
3674 }
3675
3676 /// <summary>
3677 /// Return a list of all ScenePresences in this region. This returns child agents as well as root agents.
3678 /// This list is a new object, so it can be iterated over without locking.
3679 /// </summary>
3680 /// <returns></returns>
3681 public List<ScenePresence> GetScenePresences()
3682 {
3683 return m_sceneGraph.GetScenePresences();
3684 }
3685
3686 /// <summary>
3687 /// Request a filtered list of ScenePresences in this region.
3688 /// This list is a new object, so it can be iterated over without locking.
3689 /// </summary>
3690 /// <param name="filter"></param>
3691 /// <returns></returns>
3692 public List<ScenePresence> GetScenePresences(FilterAvatarList filter)
3693 {
3694 return m_sceneGraph.GetScenePresences(filter);
3695 }
3696
3697 /// <summary>
3698 /// Request a scene presence by UUID
3699 /// </summary>
3700 /// <param name="avatarID"></param>
3701 /// <returns></returns>
3702 public ScenePresence GetScenePresence(UUID avatarID)
3703 {
3704 return m_sceneGraph.GetScenePresence(avatarID);
3705 }
3706
3707 public override bool PresenceChildStatus(UUID avatarID)
3708 {
3709 ScenePresence cp = GetScenePresence(avatarID);
3710
3711 // FIXME: This is really crap - some logout code is relying on a NullReferenceException to halt its processing
3712 // This needs to be fixed properly by cleaning up the logout code.
3713 //if (cp != null)
3714 // return cp.IsChildAgent;
3715
3716 //return false;
3717
3718 return cp.IsChildAgent;
3719 }
3720
3721 /// <summary>
3722 ///
3723 /// </summary>
3724 /// <param name="action"></param>
3725 public void ForEachScenePresence(Action<ScenePresence> action)
3726 {
3727 // We don't want to try to send messages if there are no avatars.
3728 if (m_scenePresences != null)
3729 {
3730 try
3731 {
3732 List<ScenePresence> presenceList = GetScenePresences();
3733 foreach (ScenePresence presence in presenceList)
3734 {
3735 action(presence);
3736 }
3737 }
3738 catch (Exception e)
3739 {
3740 m_log.Info("[BUG]: " + e.ToString());
3741 }
3742 }
3743 }
3744
3745 /// <summary>
3746 ///
3747 /// </summary>
3748 /// <param name="action"></param>
3749 // public void ForEachObject(Action<SceneObjectGroup> action)
3750 // {
3751 // List<SceneObjectGroup> presenceList;
3752 //
3753 // lock (m_sceneObjects)
3754 // {
3755 // presenceList = new List<SceneObjectGroup>(m_sceneObjects.Values);
3756 // }
3757 //
3758 // foreach (SceneObjectGroup presence in presenceList)
3759 // {
3760 // action(presence);
3761 // }
3762 // }
3763
3764 /// <summary>
3765 /// Get a named prim contained in this scene (will return the first
3766 /// found, if there are more than one prim with the same name)
3767 /// </summary>
3768 /// <param name="name"></param>
3769 /// <returns></returns>
3770 public SceneObjectPart GetSceneObjectPart(string name)
3771 {
3772 return m_sceneGraph.GetSceneObjectPart(name);
3773 }
3774
3775 /// <summary>
3776 /// Get a prim via its local id
3777 /// </summary>
3778 /// <param name="localID"></param>
3779 /// <returns></returns>
3780 public SceneObjectPart GetSceneObjectPart(uint localID)
3781 {
3782 return m_sceneGraph.GetSceneObjectPart(localID);
3783 }
3784
3785 /// <summary>
3786 /// Get a prim via its UUID
3787 /// </summary>
3788 /// <param name="fullID"></param>
3789 /// <returns></returns>
3790 public SceneObjectPart GetSceneObjectPart(UUID fullID)
3791 {
3792 return m_sceneGraph.GetSceneObjectPart(fullID);
3793 }
3794
3795 internal bool TryGetAvatar(UUID avatarId, out ScenePresence avatar)
3796 {
3797 return m_sceneGraph.TryGetAvatar(avatarId, out avatar);
3798 }
3799
3800 internal bool TryGetAvatarByName(string avatarName, out ScenePresence avatar)
3801 {
3802 return m_sceneGraph.TryGetAvatarByName(avatarName, out avatar);
3803 }
3804
3805 public void ForEachClient(Action<IClientAPI> action)
3806 {
3807 m_sceneGraph.ForEachClient(action);
3808 }
3809
3810 /// <summary>
3811 /// Returns a list of the entities in the scene. This is a new list so operations perform on the list itself
3812 /// will not affect the original list of objects in the scene.
3813 /// </summary>
3814 /// <returns></returns>
3815 public List<EntityBase> GetEntities()
3816 {
3817 return m_sceneGraph.GetEntities();
3818 }
3819
3820 #endregion
3821
3822 #region Avatar Appearance Default
3823
3824 public static void GetDefaultAvatarAppearance(out AvatarWearable[] wearables, out byte[] visualParams)
3825 {
3826 visualParams = GetDefaultVisualParams();
3827 wearables = AvatarWearable.DefaultWearables;
3828 }
3829
3830 private static byte[] GetDefaultVisualParams()
3831 {
3832 byte[] visualParams;
3833 visualParams = new byte[218];
3834 for (int i = 0; i < 218; i++)
3835 {
3836 visualParams[i] = 100;
3837 }
3838 return visualParams;
3839 }
3840
3841 #endregion
3842
3843 public void ParcelMediaSetTime(float time)
3844 {
3845 //should be doing this by parcel, but as its only for testing
3846 // The use of Thread.Sleep here causes the following compiler error under mono 1.2.4
3847 // OpenSim/Region/Environment/Scenes/Scene.cs(3675,17): error CS0103: The name `Thread' does not exist
3848 // in the context of `<>c__CompilerGenerated17'
3849 // MW said it was okay to comment the body of this method out for now since the code is experimental
3850 // and will be replaced anyway
3851// ForEachClient(delegate(IClientAPI client)
3852// {
3853// client.SendParcelMediaCommand((uint)(2), ParcelMediaCommandEnum.Pause, 0);
3854// Thread.Sleep(10);
3855// client.SendParcelMediaCommand((uint)(64), ParcelMediaCommandEnum.Time, time);
3856// Thread.Sleep(200);
3857// client.SendParcelMediaCommand((uint)(4), ParcelMediaCommandEnum.Play, 0);
3858// });
3859 }
3860
3861 public void RegionHandleRequest(IClientAPI client, UUID regionID)
3862 {
3863 RegionInfo info;
3864 if (regionID == RegionInfo.RegionID)
3865 info = RegionInfo;
3866 else
3867 info = CommsManager.GridService.RequestNeighbourInfo(regionID);
3868
3869 if (info != null)
3870 client.SendRegionHandle(regionID, info.RegionHandle);
3871 }
3872
3873 public void TerrainUnAcked(IClientAPI client, int patchX, int patchY)
3874 {
3875 //Console.WriteLine("Terrain packet unacked, resending patch: " + patchX + " , " + patchY);
3876 client.SendLayerData(patchX, patchY, Heightmap.GetFloatsSerialised());
3877 }
3878
3879 public void SetRootAgentScene(UUID agentID)
3880 {
3881 IInventoryTransferModule inv = RequestModuleInterface<IInventoryTransferModule>();
3882 if (inv == null)
3883 return;
3884
3885 inv.SetRootAgentScene(agentID, this);
3886
3887 EventManager.TriggerSetRootAgentScene(agentID, this);
3888 }
3889
3890 public bool NeedSceneCacheClear(UUID agentID)
3891 {
3892 IInventoryTransferModule inv = RequestModuleInterface<IInventoryTransferModule>();
3893 if (inv == null)
3894 return true;
3895
3896 return inv.NeedSceneCacheClear(agentID, this);
3897 }
3898
3899 public void ObjectSaleInfo(IClientAPI client, UUID agentID, UUID sessionID, uint localID, byte saleType, int salePrice)
3900 {
3901 SceneObjectPart part = GetSceneObjectPart(localID);
3902 if (part == null || part.ParentGroup == null)
3903 return;
3904
3905 if (part.ParentGroup.IsDeleted)
3906 return;
3907
3908 part = part.ParentGroup.RootPart;
3909
3910 part.ObjectSaleType = saleType;
3911 part.SalePrice = salePrice;
3912
3913 part.ParentGroup.HasGroupChanged = true;
3914
3915 part.GetProperties(client);
3916 }
3917
3918 public bool PerformObjectBuy(IClientAPI remoteClient, UUID categoryID,
3919 uint localID, byte saleType)
3920 {
3921 SceneObjectPart part = GetSceneObjectPart(localID);
3922
3923 if (part == null)
3924 return false;
3925
3926 if (part.ParentGroup == null)
3927 return false;
3928
3929 SceneObjectGroup group = part.ParentGroup;
3930
3931 switch (saleType)
3932 {
3933 case 1: // Sell as original (in-place sale)
3934 uint effectivePerms=group.GetEffectivePermissions();
3935
3936 if ((effectivePerms & (uint)PermissionMask.Transfer) == 0)
3937 {
3938 m_dialogModule.SendAlertToUser(remoteClient, "This item doesn't appear to be for sale");
3939 return false;
3940 }
3941
3942 group.SetOwnerId(remoteClient.AgentId);
3943 group.SetRootPartOwner(part, remoteClient.AgentId,
3944 remoteClient.ActiveGroupId);
3945
3946 List<SceneObjectPart> partList =
3947 new List<SceneObjectPart>(group.Children.Values);
3948
3949 if (Permissions.PropagatePermissions())
3950 {
3951 foreach (SceneObjectPart child in partList)
3952 {
3953 child.Inventory.ChangeInventoryOwner(remoteClient.AgentId);
3954 child.ApplyNextOwnerPermissions();
3955 }
3956 }
3957
3958 part.ObjectSaleType = 0;
3959 part.SalePrice = 10;
3960
3961 group.HasGroupChanged = true;
3962 part.GetProperties(remoteClient);
3963 part.ScheduleFullUpdate();
3964
3965 break;
3966
3967 case 2: // Sell a copy
3968 string sceneObjectXml = group.ToXmlString();
3969
3970 CachedUserInfo userInfo =
3971 CommsManager.UserProfileCacheService.GetUserDetails(remoteClient.AgentId);
3972
3973 if (userInfo != null)
3974 {
3975 uint perms=group.GetEffectivePermissions();
3976
3977 if ((perms & (uint)PermissionMask.Transfer) == 0)
3978 {
3979 m_dialogModule.SendAlertToUser(remoteClient, "This item doesn't appear to be for sale");
3980 return false;
3981 }
3982
3983 AssetBase asset = CreateAsset(
3984 group.GetPartName(localID),
3985 group.GetPartDescription(localID),
3986 (sbyte)AssetType.Object,
3987 Utils.StringToBytes(sceneObjectXml));
3988 AssetCache.AddAsset(asset);
3989
3990 InventoryItemBase item = new InventoryItemBase();
3991 item.Creator = part.CreatorID;
3992
3993 item.ID = UUID.Random();
3994 item.Owner = remoteClient.AgentId;
3995 item.AssetID = asset.Metadata.FullID;
3996 item.Description = asset.Metadata.Description;
3997 item.Name = asset.Metadata.Name;
3998 item.AssetType = asset.Metadata.Type;
3999 item.InvType = (int)InventoryType.Object;
4000 item.Folder = categoryID;
4001
4002 uint nextPerms=(perms & 7) << 13;
4003 if ((nextPerms & (uint)PermissionMask.Copy) == 0)
4004 perms &= ~(uint)PermissionMask.Copy;
4005 if ((nextPerms & (uint)PermissionMask.Transfer) == 0)
4006 perms &= ~(uint)PermissionMask.Transfer;
4007 if ((nextPerms & (uint)PermissionMask.Modify) == 0)
4008 perms &= ~(uint)PermissionMask.Modify;
4009
4010 item.BasePermissions = perms & part.NextOwnerMask;
4011 item.CurrentPermissions = perms & part.NextOwnerMask;
4012 item.NextPermissions = part.NextOwnerMask;
4013 item.EveryOnePermissions = part.EveryoneMask &
4014 part.NextOwnerMask;
4015 item.GroupPermissions = part.GroupMask &
4016 part.NextOwnerMask;
4017 item.CurrentPermissions |= 8; // Slam!
4018 item.CreationDate = Util.UnixTimeSinceEpoch();
4019
4020 userInfo.AddItem(item);
4021 remoteClient.SendInventoryItemCreateUpdate(item);
4022 }
4023 else
4024 {
4025 m_dialogModule.SendAlertToUser(remoteClient, "Cannot buy now. Your inventory is unavailable");
4026 return false;
4027 }
4028 break;
4029
4030 case 3: // Sell contents
4031 List<UUID> invList = part.Inventory.GetInventoryList();
4032
4033 bool okToSell = true;
4034
4035 foreach (UUID invID in invList)
4036 {
4037 TaskInventoryItem item = part.Inventory.GetInventoryItem(invID);
4038 if ((item.CurrentPermissions &
4039 (uint)PermissionMask.Transfer) == 0)
4040 {
4041 okToSell = false;
4042 break;
4043 }
4044 }
4045
4046 if (!okToSell)
4047 {
4048 m_dialogModule.SendAlertToUser(
4049 remoteClient, "This item's inventory doesn't appear to be for sale");
4050 return false;
4051 }
4052
4053 if (invList.Count > 0)
4054 MoveTaskInventoryItems(remoteClient.AgentId, part.Name,
4055 part, invList);
4056 break;
4057 }
4058
4059 return true;
4060 }
4061
4062 public void CleanTempObjects()
4063 {
4064 List<EntityBase> objs = GetEntities();
4065
4066 foreach (EntityBase obj in objs)
4067 {
4068 if (obj is SceneObjectGroup)
4069 {
4070 SceneObjectGroup grp = (SceneObjectGroup)obj;
4071
4072 if (!grp.IsDeleted)
4073 {
4074 if ((grp.RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
4075 {
4076 if (grp.RootPart.Expires <= DateTime.Now)
4077 DeleteSceneObject(grp, false);
4078 }
4079 }
4080 }
4081 }
4082 }
4083
4084 public void DeleteFromStorage(UUID uuid)
4085 {
4086 m_storageManager.DataStore.RemoveObject(uuid, m_regInfo.RegionID);
4087 }
4088
4089 public int GetHealth()
4090 {
4091 int health=1; // Start at 1, means we're up
4092
4093 // A login in the last 4 mins? We can't be doing too badly
4094 //
4095 if ((System.Environment.TickCount - m_LastLogin) < 240000)
4096 health++;
4097
4098 return 0;
4099 }
4100
4101 // This callback allows the PhysicsScene to call back to its caller (the SceneGraph) and
4102 // update non-physical objects like the joint proxy objects that represent the position
4103 // of the joints in the scene.
4104
4105 // This routine is normally called from within a lock (OdeLock) from within the OdePhysicsScene
4106 // WARNING: be careful of deadlocks here if you manipulate the scene. Remember you are being called
4107 // from within the OdePhysicsScene.
4108
4109 protected internal void jointMoved(PhysicsJoint joint)
4110 {
4111 // m_parentScene.PhysicsScene.DumpJointInfo(); // non-thread-locked version; we should already be in a lock (OdeLock) when this callback is invoked
4112 // FIXME: this causes a sequential lookup of all objects in the scene; use a dictionary
4113 SceneObjectPart jointProxyObject = GetSceneObjectPart(joint.ObjectNameInScene);
4114 if (jointProxyObject == null)
4115 {
4116 jointErrorMessage(joint, "WARNING, joint proxy not found, name " + joint.ObjectNameInScene);
4117 return;
4118 }
4119
4120 // now update the joint proxy object in the scene to have the position of the joint as returned by the physics engine
4121 SceneObjectPart trackedBody = GetSceneObjectPart(joint.TrackedBodyName); // FIXME: causes a sequential lookup
4122 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.
4123 jointProxyObject.Velocity = trackedBody.Velocity;
4124 jointProxyObject.RotationalVelocity = trackedBody.RotationalVelocity;
4125 switch (joint.Type)
4126 {
4127 case PhysicsJointType.Ball:
4128 {
4129 PhysicsVector jointAnchor = PhysicsScene.GetJointAnchor(joint);
4130 Vector3 proxyPos = new Vector3(jointAnchor.X, jointAnchor.Y, jointAnchor.Z);
4131 jointProxyObject.ParentGroup.UpdateGroupPosition(proxyPos); // schedules the entire group for a terse update
4132 }
4133 break;
4134
4135 case PhysicsJointType.Hinge:
4136 {
4137 PhysicsVector jointAnchor = PhysicsScene.GetJointAnchor(joint);
4138
4139 // Normally, we would just ask the physics scene to return the axis for the joint.
4140 // Unfortunately, ODE sometimes returns <0,0,0> for the joint axis, which should
4141 // never occur. Therefore we cannot rely on ODE to always return a correct joint axis.
4142 // Therefore the following call does not always work:
4143 //PhysicsVector phyJointAxis = _PhyScene.GetJointAxis(joint);
4144
4145 // instead we compute the joint orientation by saving the original joint orientation
4146 // relative to one of the jointed bodies, and applying this transformation
4147 // to the current position of the jointed bodies (the tracked body) to compute the
4148 // current joint orientation.
4149
4150 if (joint.TrackedBodyName == null)
4151 {
4152 jointErrorMessage(joint, "joint.TrackedBodyName is null, joint " + joint.ObjectNameInScene);
4153 }
4154
4155 Vector3 proxyPos = new Vector3(jointAnchor.X, jointAnchor.Y, jointAnchor.Z);
4156 Quaternion q = trackedBody.RotationOffset * joint.LocalRotation;
4157
4158 jointProxyObject.ParentGroup.UpdateGroupPosition(proxyPos); // schedules the entire group for a terse update
4159 jointProxyObject.ParentGroup.UpdateGroupRotation(q); // schedules the entire group for a terse update
4160 }
4161 break;
4162 }
4163 }
4164
4165 // This callback allows the PhysicsScene to call back to its caller (the SceneGraph) and
4166 // update non-physical objects like the joint proxy objects that represent the position
4167 // of the joints in the scene.
4168
4169 // This routine is normally called from within a lock (OdeLock) from within the OdePhysicsScene
4170 // WARNING: be careful of deadlocks here if you manipulate the scene. Remember you are being called
4171 // from within the OdePhysicsScene.
4172 protected internal void jointDeactivated(PhysicsJoint joint)
4173 {
4174 //m_log.Debug("[NINJA] SceneGraph.jointDeactivated, joint:" + joint.ObjectNameInScene);
4175 // FIXME: this causes a sequential lookup of all objects in the scene; use a dictionary
4176 SceneObjectPart jointProxyObject = GetSceneObjectPart(joint.ObjectNameInScene);
4177 if (jointProxyObject == null)
4178 {
4179 jointErrorMessage(joint, "WARNING, trying to deactivate (stop interpolation of) joint proxy, but not found, name " + joint.ObjectNameInScene);
4180 return;
4181 }
4182
4183 // turn the proxy non-physical, which also stops its client-side interpolation
4184 bool wasUsingPhysics = ((jointProxyObject.ObjectFlags & (uint)PrimFlags.Physics) != 0);
4185 if (wasUsingPhysics)
4186 {
4187 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
4188 }
4189 }
4190
4191 // This callback allows the PhysicsScene to call back to its caller (the SceneGraph) and
4192 // alert the user of errors by using the debug channel in the same way that scripts alert
4193 // the user of compile errors.
4194
4195 // This routine is normally called from within a lock (OdeLock) from within the OdePhysicsScene
4196 // WARNING: be careful of deadlocks here if you manipulate the scene. Remember you are being called
4197 // from within the OdePhysicsScene.
4198 public void jointErrorMessage(PhysicsJoint joint, string message)
4199 {
4200 // FIXME: this causes a sequential lookup of all objects in the scene; use a dictionary
4201 if (joint != null)
4202 {
4203 if (joint.ErrorMessageCount > PhysicsJoint.maxErrorMessages)
4204 return;
4205
4206 SceneObjectPart jointProxyObject = GetSceneObjectPart(joint.ObjectNameInScene);
4207 if (jointProxyObject != null)
4208 {
4209 SimChat(Utils.StringToBytes("[NINJA] " + message),
4210 ChatTypeEnum.DebugChannel,
4211 2147483647,
4212 jointProxyObject.AbsolutePosition,
4213 jointProxyObject.Name,
4214 jointProxyObject.UUID,
4215 false);
4216
4217 joint.ErrorMessageCount++;
4218
4219 if (joint.ErrorMessageCount > PhysicsJoint.maxErrorMessages)
4220 {
4221 SimChat(Utils.StringToBytes("[NINJA] Too many messages for this joint, suppressing further messages."),
4222 ChatTypeEnum.DebugChannel,
4223 2147483647,
4224 jointProxyObject.AbsolutePosition,
4225 jointProxyObject.Name,
4226 jointProxyObject.UUID,
4227 false);
4228 }
4229 }
4230 else
4231 {
4232 // couldn't find the joint proxy object; the error message is silently suppressed
4233 }
4234 }
4235 }
4236 }
4237}