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