From 134f86e8d5c414409631b25b8c6f0ee45fbd8631 Mon Sep 17 00:00:00 2001
From: David Walter Seikel
Date: Thu, 3 Nov 2016 21:44:39 +1000
Subject: Initial update to OpenSim 0.8.2.1 source code.
---
.../Framework/Scenes/Animation/AnimationSet.cs | 119 +
.../Framework/Scenes/Animation/BinBVHAnimation.cs | 49 +-
.../Scenes/Animation/DefaultAvatarAnimations.cs | 26 +
.../Scenes/Animation/ScenePresenceAnimator.cs | 38 +-
.../Scenes/AsyncSceneObjectGroupDeleter.cs | 10 +-
OpenSim/Region/Framework/Scenes/Border.cs | 7 +-
OpenSim/Region/Framework/Scenes/EventManager.cs | 291 ++-
OpenSim/Region/Framework/Scenes/KeyframeMotion.cs | 829 +++++++
OpenSim/Region/Framework/Scenes/Prioritizer.cs | 2 +-
.../Region/Framework/Scenes/RegionStatsHandler.cs | 27 +-
OpenSim/Region/Framework/Scenes/Scene.Inventory.cs | 575 +++--
.../Framework/Scenes/Scene.PacketHandlers.cs | 68 +-
OpenSim/Region/Framework/Scenes/Scene.cs | 2597 ++++++++++++--------
OpenSim/Region/Framework/Scenes/SceneBase.cs | 78 +-
.../Framework/Scenes/SceneCommunicationService.cs | 64 +-
OpenSim/Region/Framework/Scenes/SceneGraph.cs | 175 +-
OpenSim/Region/Framework/Scenes/SceneManager.cs | 48 +-
.../Framework/Scenes/SceneObjectGroup.Inventory.cs | 8 +
.../Region/Framework/Scenes/SceneObjectGroup.cs | 509 +++-
OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 918 +++++--
.../Framework/Scenes/SceneObjectPartInventory.cs | 132 +-
OpenSim/Region/Framework/Scenes/ScenePresence.cs | 2595 +++++++++++++------
.../Framework/Scenes/ScenePresenceStateMachine.cs | 113 +
.../Framework/Scenes/Scripting/IScriptHost.cs | 46 -
.../Framework/Scenes/Scripting/NullScriptHost.cs | 91 -
.../Scenes/Scripting/ScriptEngineInterface.cs | 38 -
.../Scenes/Scripting/ScriptEngineLoader.cs | 119 -
.../Framework/Scenes/Scripting/ScriptUtils.cs | 107 +
.../CoalescedSceneObjectsSerializer.cs | 87 +-
.../Scenes/Serialization/SceneObjectSerializer.cs | 604 +++--
.../Scenes/Serialization/SceneXmlLoader.cs | 2 +-
.../Region/Framework/Scenes/SimStatsReporter.cs | 259 +-
OpenSim/Region/Framework/Scenes/TerrainChannel.cs | 346 ++-
.../Region/Framework/Scenes/TerrainCompressor.cs | 948 +++++++
.../Framework/Scenes/Tests/EntityManagerTests.cs | 1 -
.../Framework/Scenes/Tests/SceneGraphTests.cs | 2 -
.../Framework/Scenes/Tests/SceneManagerTests.cs | 2 -
.../Scenes/Tests/SceneObjectBasicTests.cs | 2 -
.../Framework/Scenes/Tests/SceneObjectCopyTests.cs | 346 +++
.../Scenes/Tests/SceneObjectCrossingTests.cs | 259 ++
.../Scenes/Tests/SceneObjectDeRezTests.cs | 111 +-
.../Scenes/Tests/SceneObjectLinkingTests.cs | 39 +-
.../Scenes/Tests/SceneObjectResizeTests.cs | 2 -
.../Scenes/Tests/SceneObjectScriptTests.cs | 2 -
.../Scenes/Tests/SceneObjectSerializationTests.cs | 135 +
.../Scenes/Tests/SceneObjectSpatialTests.cs | 2 -
.../Scenes/Tests/SceneObjectStatusTests.cs | 21 +-
.../Scenes/Tests/SceneObjectUndoRedoTests.cs | 6 +-
.../Scenes/Tests/SceneObjectUserGroupTests.cs | 2 -
.../Scenes/Tests/ScenePresenceAgentTests.cs | 218 +-
.../Scenes/Tests/ScenePresenceAnimationTests.cs | 4 +-
.../Scenes/Tests/ScenePresenceAutopilotTests.cs | 2 -
.../Scenes/Tests/ScenePresenceCapabilityTests.cs | 86 +
.../Scenes/Tests/ScenePresenceCrossingTests.cs | 247 ++
.../Scenes/Tests/ScenePresenceSitTests.cs | 81 +-
.../Scenes/Tests/ScenePresenceTeleportTests.cs | 302 ++-
.../Framework/Scenes/Tests/SceneStatisticsTests.cs | 69 +
.../Framework/Scenes/Tests/SceneTelehubTests.cs | 118 +
.../Region/Framework/Scenes/Tests/SceneTests.cs | 25 +-
.../Scenes/Tests/SharedRegionModuleTests.cs | 249 ++
.../Framework/Scenes/Tests/TaskInventoryTests.cs | 18 +-
.../Framework/Scenes/Tests/UserInventoryTests.cs | 18 +-
.../Framework/Scenes/Tests/UuidGathererTests.cs | 91 +-
OpenSim/Region/Framework/Scenes/UuidGatherer.cs | 604 +++--
64 files changed, 11162 insertions(+), 3827 deletions(-)
create mode 100644 OpenSim/Region/Framework/Scenes/KeyframeMotion.cs
mode change 100644 => 100755 OpenSim/Region/Framework/Scenes/Scene.cs
mode change 100644 => 100755 OpenSim/Region/Framework/Scenes/SceneGraph.cs
create mode 100644 OpenSim/Region/Framework/Scenes/ScenePresenceStateMachine.cs
delete mode 100644 OpenSim/Region/Framework/Scenes/Scripting/IScriptHost.cs
delete mode 100644 OpenSim/Region/Framework/Scenes/Scripting/NullScriptHost.cs
delete mode 100644 OpenSim/Region/Framework/Scenes/Scripting/ScriptEngineInterface.cs
delete mode 100644 OpenSim/Region/Framework/Scenes/Scripting/ScriptEngineLoader.cs
create mode 100644 OpenSim/Region/Framework/Scenes/Scripting/ScriptUtils.cs
mode change 100644 => 100755 OpenSim/Region/Framework/Scenes/SimStatsReporter.cs
create mode 100644 OpenSim/Region/Framework/Scenes/TerrainCompressor.cs
create mode 100644 OpenSim/Region/Framework/Scenes/Tests/SceneObjectCopyTests.cs
create mode 100644 OpenSim/Region/Framework/Scenes/Tests/SceneObjectCrossingTests.cs
create mode 100644 OpenSim/Region/Framework/Scenes/Tests/SceneObjectSerializationTests.cs
create mode 100644 OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCapabilityTests.cs
create mode 100644 OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs
create mode 100644 OpenSim/Region/Framework/Scenes/Tests/SceneStatisticsTests.cs
create mode 100644 OpenSim/Region/Framework/Scenes/Tests/SceneTelehubTests.cs
create mode 100644 OpenSim/Region/Framework/Scenes/Tests/SharedRegionModuleTests.cs
(limited to 'OpenSim/Region/Framework/Scenes')
diff --git a/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs b/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs
index 66edfed..eb1a970 100644
--- a/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs
+++ b/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs
@@ -28,8 +28,11 @@
using System;
using System.Collections.Generic;
using System.Reflection;
+using System.Text;
using log4net;
using OpenMetaverse;
+using OpenMetaverse.StructuredData;
+
using OpenSim.Framework;
using Animation = OpenSim.Framework.Animation;
@@ -60,6 +63,12 @@ namespace OpenSim.Region.Framework.Scenes.Animation
ResetDefaultAnimation();
}
+ public AnimationSet(OSDArray pArray)
+ {
+ ResetDefaultAnimation();
+ FromOSDArray(pArray);
+ }
+
public bool HasAnimation(UUID animID)
{
if (m_defaultAnimation.AnimID == animID)
@@ -218,5 +227,115 @@ namespace OpenSim.Region.Framework.Scenes.Animation
foreach (OpenSim.Framework.Animation anim in theArray)
m_animations.Add(anim);
}
+
+ // Create representation of this AnimationSet as an OSDArray.
+ // First two entries in the array are the default and implicitDefault animations
+ // followed by the other animations.
+ public OSDArray ToOSDArray()
+ {
+ OSDArray ret = new OSDArray();
+ ret.Add(DefaultAnimation.PackUpdateMessage());
+ ret.Add(ImplicitDefaultAnimation.PackUpdateMessage());
+
+ foreach (OpenSim.Framework.Animation anim in m_animations)
+ ret.Add(anim.PackUpdateMessage());
+
+ return ret;
+ }
+
+ public void FromOSDArray(OSDArray pArray)
+ {
+ this.Clear();
+
+ if (pArray.Count >= 1)
+ {
+ m_defaultAnimation = new OpenSim.Framework.Animation((OSDMap)pArray[0]);
+ }
+ if (pArray.Count >= 2)
+ {
+ m_implicitDefaultAnimation = new OpenSim.Framework.Animation((OSDMap)pArray[1]);
+ }
+ for (int ii = 2; ii < pArray.Count; ii++)
+ {
+ m_animations.Add(new OpenSim.Framework.Animation((OSDMap)pArray[ii]));
+ }
+ }
+
+ // Compare two AnimationSets and return 'true' if the default animations are the same
+ // and all of the animations in the list are equal.
+ public override bool Equals(object obj)
+ {
+ AnimationSet other = obj as AnimationSet;
+ if (other != null)
+ {
+ if (this.DefaultAnimation.Equals(other.DefaultAnimation)
+ && this.ImplicitDefaultAnimation.Equals(other.ImplicitDefaultAnimation))
+ {
+ // The defaults are the same. Is the list of animations the same?
+ OpenSim.Framework.Animation[] thisAnims = this.ToArray();
+ OpenSim.Framework.Animation[] otherAnims = other.ToArray();
+ if (thisAnims.Length == 0 && otherAnims.Length == 0)
+ return true; // the common case
+ if (thisAnims.Length == otherAnims.Length)
+ {
+ // Do this the hard way but since the list is usually short this won't take long.
+ foreach (OpenSim.Framework.Animation thisAnim in thisAnims)
+ {
+ bool found = false;
+ foreach (OpenSim.Framework.Animation otherAnim in otherAnims)
+ {
+ if (thisAnim.Equals(otherAnim))
+ {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ {
+ // If anything is not in the other list, these are not equal
+ return false;
+ }
+ }
+ // Found everything in the other list. Since lists are equal length, they must be equal.
+ return true;
+ }
+ }
+ return false;
+ }
+ // Don't know what was passed, but the base system will figure it out for me.
+ return base.Equals(obj);
+ }
+
+ public override int GetHashCode()
+ {
+ return base.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ StringBuilder buff = new StringBuilder();
+ buff.Append("dflt=");
+ buff.Append(DefaultAnimation.ToString());
+ buff.Append(",iDflt=");
+ if (DefaultAnimation.Equals(ImplicitDefaultAnimation))
+ buff.Append("same");
+ else
+ buff.Append(ImplicitDefaultAnimation.ToString());
+ if (m_animations.Count > 0)
+ {
+ buff.Append(",anims=");
+ bool firstTime = true;
+ foreach (OpenSim.Framework.Animation anim in m_animations)
+ {
+ if (!firstTime)
+ buff.Append(",");
+ buff.Append("<");
+ buff.Append(anim.ToString());
+ buff.Append(">");
+ firstTime = false;
+ }
+ }
+ return buff.ToString();
+ }
}
}
diff --git a/OpenSim/Region/Framework/Scenes/Animation/BinBVHAnimation.cs b/OpenSim/Region/Framework/Scenes/Animation/BinBVHAnimation.cs
index 3afc87f..b3b38b2 100644
--- a/OpenSim/Region/Framework/Scenes/Animation/BinBVHAnimation.cs
+++ b/OpenSim/Region/Framework/Scenes/Animation/BinBVHAnimation.cs
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
@@ -113,31 +113,34 @@ namespace OpenSim.Region.Framework.Scenes.Animation
public byte[] ToBytes()
{
- byte[] outputbytes = new byte[0];
+ byte[] outputbytes;
- BinaryWriter iostream = new BinaryWriter(new MemoryStream());
- iostream.Write(BinBVHUtil.ES(Utils.UInt16ToBytes(unknown0)));
- iostream.Write(BinBVHUtil.ES(Utils.UInt16ToBytes(unknown1)));
- iostream.Write(BinBVHUtil.ES(Utils.IntToBytes(Priority)));
- iostream.Write(BinBVHUtil.ES(Utils.FloatToBytes(Length)));
- iostream.Write(BinBVHUtil.WriteNullTerminatedString(ExpressionName));
- iostream.Write(BinBVHUtil.ES(Utils.FloatToBytes(InPoint)));
- iostream.Write(BinBVHUtil.ES(Utils.FloatToBytes(OutPoint)));
- iostream.Write(BinBVHUtil.ES(Utils.IntToBytes(Loop ? 1 : 0)));
- iostream.Write(BinBVHUtil.ES(Utils.FloatToBytes(EaseInTime)));
- iostream.Write(BinBVHUtil.ES(Utils.FloatToBytes(EaseOutTime)));
- iostream.Write(BinBVHUtil.ES(Utils.UIntToBytes(HandPose)));
- iostream.Write(BinBVHUtil.ES(Utils.UIntToBytes((uint)(Joints.Length))));
-
- for (int i = 0; i < Joints.Length; i++)
+ using (MemoryStream ms = new MemoryStream())
+ using (BinaryWriter iostream = new BinaryWriter(ms))
{
- Joints[i].WriteBytesToStream(iostream, InPoint, OutPoint);
+ iostream.Write(BinBVHUtil.ES(Utils.UInt16ToBytes(unknown0)));
+ iostream.Write(BinBVHUtil.ES(Utils.UInt16ToBytes(unknown1)));
+ iostream.Write(BinBVHUtil.ES(Utils.IntToBytes(Priority)));
+ iostream.Write(BinBVHUtil.ES(Utils.FloatToBytes(Length)));
+ iostream.Write(BinBVHUtil.WriteNullTerminatedString(ExpressionName));
+ iostream.Write(BinBVHUtil.ES(Utils.FloatToBytes(InPoint)));
+ iostream.Write(BinBVHUtil.ES(Utils.FloatToBytes(OutPoint)));
+ iostream.Write(BinBVHUtil.ES(Utils.IntToBytes(Loop ? 1 : 0)));
+ iostream.Write(BinBVHUtil.ES(Utils.FloatToBytes(EaseInTime)));
+ iostream.Write(BinBVHUtil.ES(Utils.FloatToBytes(EaseOutTime)));
+ iostream.Write(BinBVHUtil.ES(Utils.UIntToBytes(HandPose)));
+ iostream.Write(BinBVHUtil.ES(Utils.UIntToBytes((uint)(Joints.Length))));
+
+ for (int i = 0; i < Joints.Length; i++)
+ {
+ Joints[i].WriteBytesToStream(iostream, InPoint, OutPoint);
+ }
+ iostream.Write(BinBVHUtil.ES(Utils.IntToBytes(0)));
+
+ using (MemoryStream ms2 = (MemoryStream)iostream.BaseStream)
+ outputbytes = ms2.ToArray();
}
- iostream.Write(BinBVHUtil.ES(Utils.IntToBytes(0)));
- MemoryStream ms = (MemoryStream)iostream.BaseStream;
- outputbytes = ms.ToArray();
- ms.Close();
- iostream.Close();
+
return outputbytes;
}
diff --git a/OpenSim/Region/Framework/Scenes/Animation/DefaultAvatarAnimations.cs b/OpenSim/Region/Framework/Scenes/Animation/DefaultAvatarAnimations.cs
index c2b0468..b79dd8f 100644
--- a/OpenSim/Region/Framework/Scenes/Animation/DefaultAvatarAnimations.cs
+++ b/OpenSim/Region/Framework/Scenes/Animation/DefaultAvatarAnimations.cs
@@ -104,5 +104,31 @@ namespace OpenSim.Region.Framework.Scenes.Animation
return UUID.Zero;
}
+
+ ///
+ /// Get the name of the animation given a UUID. If there is no matching animation
+ /// return the UUID as a string.
+ ///
+ public static string GetDefaultAnimationName(UUID uuid)
+ {
+ string ret = "unknown";
+ if (AnimsUUID.ContainsValue(uuid))
+ {
+ foreach (KeyValuePair kvp in AnimsUUID)
+ {
+ if (kvp.Value == uuid)
+ {
+ ret = kvp.Key;
+ break;
+ }
+ }
+ }
+ else
+ {
+ ret = uuid.ToString();
+ }
+
+ return ret;
+ }
}
}
\ No newline at end of file
diff --git a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs
index e92a087..6d51029 100644
--- a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs
+++ b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs
@@ -35,7 +35,7 @@ using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
-using OpenSim.Region.Physics.Manager;
+using OpenSim.Region.PhysicsModules.SharedBase;
namespace OpenSim.Region.Framework.Scenes.Animation
{
@@ -92,7 +92,10 @@ namespace OpenSim.Region.Framework.Scenes.Animation
GetAnimName(animID), animID, m_scenePresence.Name);
if (m_animations.Add(animID, m_scenePresence.ControllingClient.NextAnimationSequenceNumber, objectID))
+ {
SendAnimPack();
+ m_scenePresence.TriggerScenePresenceUpdated();
+ }
}
// Called from scripts
@@ -131,7 +134,10 @@ namespace OpenSim.Region.Framework.Scenes.Animation
GetAnimName(animID), animID, m_scenePresence.Name);
if (m_animations.Remove(animID, allowNoDefault))
+ {
SendAnimPack();
+ m_scenePresence.TriggerScenePresenceUpdated();
+ }
}
// Called from scripts
@@ -163,8 +169,10 @@ namespace OpenSim.Region.Framework.Scenes.Animation
/// The movement animation is reserved for "main" animations
/// that are mutually exclusive, e.g. flying and sitting.
///
- public void TrySetMovementAnimation(string anim)
+ /// 'true' if the animation was updated
+ public bool TrySetMovementAnimation(string anim)
{
+ bool ret = false;
if (!m_scenePresence.IsChildAgent)
{
// m_log.DebugFormat(
@@ -181,6 +189,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation
// 16384 is CHANGED_ANIMATION
m_scenePresence.SendScriptEventToAttachments("changed", new Object[] { (int)Changed.ANIMATION});
SendAnimPack();
+ ret = true;
}
}
else
@@ -189,6 +198,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation
"[SCENE PRESENCE ANIMATOR]: Tried to set movement animation {0} on child presence {1}",
anim, m_scenePresence.Name);
}
+ return ret;
}
///
@@ -393,11 +403,18 @@ namespace OpenSim.Region.Framework.Scenes.Animation
Falling = false;
// Walking / crouchwalking / running
if (move.Z < 0f)
+ {
return "CROUCHWALK";
- else if (m_scenePresence.SetAlwaysRun)
- return "RUN";
- else
- return "WALK";
+ }
+ // We need to prevent these animations if the user tries to make their avatar walk or run whilst
+ // specifying AGENT_CONTROL_STOP (pressing down space on viewers).
+ else if (!m_scenePresence.AgentControlStopActive)
+ {
+ if (m_scenePresence.SetAlwaysRun)
+ return "RUN";
+ else
+ return "WALK";
+ }
}
else if (!m_jumping)
{
@@ -422,8 +439,12 @@ namespace OpenSim.Region.Framework.Scenes.Animation
///
/// Update the movement animation of this avatar according to its current state
///
- public void UpdateMovementAnimations()
+ /// 'true' if the animation was changed
+ public bool UpdateMovementAnimations()
{
+// m_log.DebugFormat("[SCENE PRESENCE ANIMATOR]: Updating movement animations for {0}", m_scenePresence.Name);
+
+ bool ret = false;
lock (m_animations)
{
string newMovementAnimation = DetermineMovementAnimation();
@@ -437,9 +458,10 @@ namespace OpenSim.Region.Framework.Scenes.Animation
// Only set it if it's actually changed, give a script
// a chance to stop a default animation
- TrySetMovementAnimation(CurrentMovementAnimation);
+ ret = TrySetMovementAnimation(CurrentMovementAnimation);
}
}
+ return ret;
}
public UUID[] GetAnimationArray()
diff --git a/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs b/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs
index f555b49..11a0146 100644
--- a/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs
+++ b/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs
@@ -104,14 +104,8 @@ namespace OpenSim.Region.Framework.Scenes
// better than losing the object for now.
if (permissionToDelete)
{
- List killIDs = new List();
-
foreach (SceneObjectGroup g in objectGroups)
- { killIDs.Add(g.LocalId);
- g.DeleteGroupFromScene(true);
- }
-
- m_scene.SendKillObject(killIDs);
+ g.DeleteGroupFromScene(false);
}
}
@@ -160,7 +154,7 @@ namespace OpenSim.Region.Framework.Scenes
if (x.permissionToDelete)
{
foreach (SceneObjectGroup g in x.objectGroups)
- m_scene.DeleteSceneObject(g, false);
+ m_scene.DeleteSceneObject(g, true);
}
}
catch (Exception e)
diff --git a/OpenSim/Region/Framework/Scenes/Border.cs b/OpenSim/Region/Framework/Scenes/Border.cs
index c6a6511..08c0c31 100644
--- a/OpenSim/Region/Framework/Scenes/Border.cs
+++ b/OpenSim/Region/Framework/Scenes/Border.cs
@@ -33,8 +33,7 @@ using OpenMetaverse;
namespace OpenSim.Region.Framework.Scenes
{
public class Border
- {
-
+ {
///
/// Line perpendicular to the Direction Cardinal. Z value is the
///
@@ -81,6 +80,10 @@ namespace OpenSim.Region.Framework.Scenes
TriggerRegionY = triggerRegionY;
}
+ ///
+ /// Tests to see if the given position would cross this border.
+ ///
+ ///
public bool TestCross(Vector3 position)
{
bool result = false;
diff --git a/OpenSim/Region/Framework/Scenes/EventManager.cs b/OpenSim/Region/Framework/Scenes/EventManager.cs
index 4c49b71..97b9482 100644
--- a/OpenSim/Region/Framework/Scenes/EventManager.cs
+++ b/OpenSim/Region/Framework/Scenes/EventManager.cs
@@ -144,7 +144,7 @@ namespace OpenSim.Region.Framework.Scenes
/// Triggered when a new presence is added to the scene
///
///
- /// Triggered in which is used by both
+ /// Triggered in which is used by both
/// users and NPCs
///
public event OnNewPresenceDelegate OnNewPresence;
@@ -155,7 +155,7 @@ namespace OpenSim.Region.Framework.Scenes
/// Triggered when a presence is removed from the scene
///
///
- /// Triggered in which is used by both
+ /// Triggered in which is used by both
/// users and NPCs
///
/// Triggered under per-agent lock. So if you want to perform any long-running operations, please
@@ -339,6 +339,8 @@ namespace OpenSim.Region.Framework.Scenes
/// in
/// via ,
/// via
+ /// XXX: This is only triggered when it is the client that starts the script, not in other situations where
+ /// a script is started, unlike OnStopScript!
///
public event StartScript OnStartScript;
@@ -352,6 +354,7 @@ namespace OpenSim.Region.Framework.Scenes
/// in ,
/// ,
///
+ /// XXX: This is triggered when a sciprt is stopped for any reason, unlike OnStartScript!
///
public event StopScript OnStopScript;
@@ -427,6 +430,9 @@ namespace OpenSim.Region.Framework.Scenes
public delegate void IncomingInstantMessage(GridInstantMessage message);
public event IncomingInstantMessage OnIncomingInstantMessage;
+ public delegate void CrossAgentToNewRegion(ScenePresence sp, bool isFlying, GridRegion newRegion);
+ public event CrossAgentToNewRegion OnCrossAgentToNewRegion;
+
public event IncomingInstantMessage OnUnhandledInstantMessage;
public delegate void ClientClosed(UUID clientID, Scene scene);
@@ -546,6 +552,20 @@ namespace OpenSim.Region.Framework.Scenes
///
public event ScriptControlEvent OnScriptControlEvent;
+ public delegate void ScriptMovingStartEvent(uint localID);
+
+ ///
+ /// TODO: Should be triggered when a physics object starts moving.
+ ///
+ public event ScriptMovingStartEvent OnScriptMovingStartEvent;
+
+ public delegate void ScriptMovingEndEvent(uint localID);
+
+ ///
+ /// TODO: Should be triggered when a physics object stops moving.
+ ///
+ public event ScriptMovingEndEvent OnScriptMovingEndEvent;
+
public delegate void ScriptAtTargetEvent(uint localID, uint handle, Vector3 targetpos, Vector3 atpos);
///
@@ -612,8 +632,8 @@ namespace OpenSim.Region.Framework.Scenes
/// Triggered by
/// in
/// via
- /// via
- /// via
+ /// via
+ /// via
///
public event ScriptColliding OnScriptColliderStart;
@@ -626,8 +646,8 @@ namespace OpenSim.Region.Framework.Scenes
/// Triggered by
/// in
/// via
- /// via
- /// via
+ /// via
+ /// via
///
public event ScriptColliding OnScriptColliding;
@@ -639,8 +659,8 @@ namespace OpenSim.Region.Framework.Scenes
/// Triggered by
/// in
/// via
- /// via
- /// via
+ /// via
+ /// via
///
public event ScriptColliding OnScriptCollidingEnd;
@@ -652,8 +672,8 @@ namespace OpenSim.Region.Framework.Scenes
/// Triggered by
/// in
/// via
- /// via
- /// via
+ /// via
+ /// via
///
public event ScriptColliding OnScriptLandColliderStart;
@@ -665,8 +685,8 @@ namespace OpenSim.Region.Framework.Scenes
/// Triggered by
/// in
/// via
- /// via
- /// via
+ /// via
+ /// via
///
public event ScriptColliding OnScriptLandColliding;
@@ -678,8 +698,8 @@ namespace OpenSim.Region.Framework.Scenes
/// Triggered by
/// in
/// via
- /// via
- /// via
+ /// via
+ /// via
///
public event ScriptColliding OnScriptLandColliderEnd;
@@ -725,7 +745,7 @@ namespace OpenSim.Region.Framework.Scenes
public event OnIncomingSceneObjectDelegate OnIncomingSceneObject;
public delegate void OnIncomingSceneObjectDelegate(SceneObjectGroup so);
- public delegate void NewInventoryItemUploadComplete(UUID avatarID, UUID assetID, string name, int userlevel);
+ public delegate void NewInventoryItemUploadComplete(UUID avatarID, AssetType type, UUID assetID, string name, int userlevel);
public event NewInventoryItemUploadComplete OnNewInventoryItemUploadComplete;
@@ -751,7 +771,7 @@ namespace OpenSim.Region.Framework.Scenes
public event ScriptTimerEvent OnScriptTimerEvent;
*/
- public delegate void EstateToolsSunUpdate(ulong regionHandle, bool FixedTime, bool EstateSun, float LindenHour);
+ public delegate void EstateToolsSunUpdate(ulong regionHandle);
public delegate void GetScriptRunning(IClientAPI controllingClient, UUID objectID, UUID itemID);
public event EstateToolsSunUpdate OnEstateToolsSunUpdate;
@@ -766,12 +786,20 @@ namespace OpenSim.Region.Framework.Scenes
///
///
public event Action OnObjectAddedToScene;
-
+
///
- /// Delegate for
+ /// When a client sends a derez request for an object inworld
+ /// but before the object is deleted
///
- /// The object being removed from the scene
- public delegate void ObjectBeingRemovedFromScene(SceneObjectGroup obj);
+ public event DeRezRequested OnDeRezRequested;
+ ///
+ /// Triggered when a client sends a derez request for an object inworld
+ ///
+ /// The client question (it can be null)
+ /// The object in question
+ /// The exact derez action
+ /// Flag indicating whether the object should be deleted from the scene or not
+ public delegate bool DeRezRequested(IClientAPI remoteClient, List objs, DeRezAction action);
///
/// Triggered when an object is removed from the scene.
@@ -781,6 +809,24 @@ namespace OpenSim.Region.Framework.Scenes
/// in
///
public event ObjectBeingRemovedFromScene OnObjectBeingRemovedFromScene;
+ ///
+ /// Delegate for
+ ///
+ /// The object being removed from the scene
+ public delegate void ObjectBeingRemovedFromScene(SceneObjectGroup obj);
+
+ ///
+ /// Triggered when an object is placed into the physical scene (PhysicsActor created).
+ ///
+ public event Action OnObjectAddedToPhysicalScene;
+ ///
+ /// Triggered when an object is removed from the physical scene (PhysicsActor destroyed).
+ ///
+ ///
+ /// Note: this is triggered just before the PhysicsActor is removed from the
+ /// physics engine so the receiver can do any necessary cleanup before its destruction.
+ ///
+ public event Action OnObjectRemovedFromPhysicalScene;
public delegate void NoticeNoLandDataFromStorage();
public event NoticeNoLandDataFromStorage OnNoticeNoLandDataFromStorage;
@@ -939,6 +985,8 @@ namespace OpenSim.Region.Framework.Scenes
public delegate void RegionStarted(Scene scene);
public event RegionStarted OnRegionStarted;
+ public delegate void RegionHeartbeatStart(Scene scene);
+ public event RegionHeartbeatStart OnRegionHeartbeatStart;
public delegate void RegionHeartbeatEnd(Scene scene);
public event RegionHeartbeatEnd OnRegionHeartbeatEnd;
@@ -989,6 +1037,16 @@ namespace OpenSim.Region.Framework.Scenes
///
public event TeleportFail OnTeleportFail;
+// public delegate void GatherUuids(SceneObjectPart sop, IDictionary assetUuids);
+//
+// ///
+// /// Triggered when UUIDs referenced by a scene object are being gathered for archiving, hg transfer, etc.
+// ///
+// ///
+// /// The listener should add references to the IDictionary as appropriate.
+// ///
+// public event GatherUuids OnGatherUuids;
+
public class MoneyTransferArgs : EventArgs
{
public UUID sender;
@@ -1060,7 +1118,7 @@ namespace OpenSim.Region.Framework.Scenes
/// Triggered in
/// via
/// via
- /// via
+ /// via
///
public event MoneyTransferEvent OnMoneyTransfer;
@@ -1476,8 +1534,33 @@ namespace OpenSim.Region.Framework.Scenes
}
}
}
- }
-
+ }
+
+ public bool TriggerDeRezRequested(IClientAPI client, List objs, DeRezAction action)
+ {
+ bool canDeRez = true;
+
+ DeRezRequested handlerDeRezRequested = OnDeRezRequested;
+ if (handlerDeRezRequested != null)
+ {
+ foreach (DeRezRequested d in handlerDeRezRequested.GetInvocationList())
+ {
+ try
+ {
+ canDeRez &= d(client, objs, action);
+ }
+ catch (Exception e)
+ {
+ m_log.ErrorFormat(
+ "[EVENT MANAGER]: Delegate for TriggerDeRezRequested failed - continuing. {0} {1}",
+ e.Message, e.StackTrace);
+ }
+ }
+ }
+
+ return canDeRez;
+ }
+
public void TriggerObjectBeingRemovedFromScene(SceneObjectGroup obj)
{
ObjectBeingRemovedFromScene handlerObjectBeingRemovedFromScene = OnObjectBeingRemovedFromScene;
@@ -1499,6 +1582,48 @@ namespace OpenSim.Region.Framework.Scenes
}
}
+ public void TriggerObjectAddedToPhysicalScene(SceneObjectPart obj)
+ {
+ Action handler = OnObjectAddedToPhysicalScene;
+ if (handler != null)
+ {
+ foreach (Action d in handler.GetInvocationList())
+ {
+ try
+ {
+ d(obj);
+ }
+ catch (Exception e)
+ {
+ m_log.ErrorFormat(
+ "[EVENT MANAGER]: Delegate for TriggerObjectAddedToPhysicalScene failed - continuing. {0} {1}",
+ e.Message, e.StackTrace);
+ }
+ }
+ }
+ }
+
+ public void TriggerObjectRemovedFromPhysicalScene(SceneObjectPart obj)
+ {
+ Action handler = OnObjectRemovedFromPhysicalScene;
+ if (handler != null)
+ {
+ foreach (Action d in handler.GetInvocationList())
+ {
+ try
+ {
+ d(obj);
+ }
+ catch (Exception e)
+ {
+ m_log.ErrorFormat(
+ "[EVENT MANAGER]: Delegate for TriggerObjectRemovedFromPhysicalScene failed - continuing. {0} {1}",
+ e.Message, e.StackTrace);
+ }
+ }
+ }
+ }
+
public void TriggerShutdown()
{
Action handlerShutdown = OnShutdown;
@@ -1876,6 +2001,27 @@ namespace OpenSim.Region.Framework.Scenes
}
}
+ public void TriggerCrossAgentToNewRegion(ScenePresence agent, bool isFlying, GridRegion newRegion)
+ {
+ CrossAgentToNewRegion handlerCrossAgentToNewRegion = OnCrossAgentToNewRegion;
+ if (handlerCrossAgentToNewRegion != null)
+ {
+ foreach (CrossAgentToNewRegion d in handlerCrossAgentToNewRegion.GetInvocationList())
+ {
+ try
+ {
+ d(agent, isFlying, newRegion);
+ }
+ catch (Exception e)
+ {
+ m_log.ErrorFormat(
+ "[EVENT MANAGER]: Delegate for TriggerCrossAgentToNewRegion failed - continuing. {0} {1}",
+ e.Message, e.StackTrace);
+ }
+ }
+ }
+ }
+
public void TriggerIncomingInstantMessage(GridInstantMessage message)
{
IncomingInstantMessage handlerIncomingInstantMessage = OnIncomingInstantMessage;
@@ -2062,7 +2208,7 @@ namespace OpenSim.Region.Framework.Scenes
}
}
- public void TriggerOnNewInventoryItemUploadComplete(UUID agentID, UUID AssetID, String AssetName, int userlevel)
+ public void TriggerOnNewInventoryItemUploadComplete(UUID agentID, AssetType type, UUID AssetID, String AssetName, int userlevel)
{
NewInventoryItemUploadComplete handlerNewInventoryItemUpdateComplete = OnNewInventoryItemUploadComplete;
if (handlerNewInventoryItemUpdateComplete != null)
@@ -2071,7 +2217,7 @@ namespace OpenSim.Region.Framework.Scenes
{
try
{
- d(agentID, AssetID, AssetName, userlevel);
+ d(agentID, type, AssetID, AssetName, userlevel);
}
catch (Exception e)
{
@@ -2209,6 +2355,48 @@ namespace OpenSim.Region.Framework.Scenes
}
}
+ public void TriggerMovingStartEvent(uint localID)
+ {
+ ScriptMovingStartEvent handlerScriptMovingStartEvent = OnScriptMovingStartEvent;
+ if (handlerScriptMovingStartEvent != null)
+ {
+ foreach (ScriptMovingStartEvent d in handlerScriptMovingStartEvent.GetInvocationList())
+ {
+ try
+ {
+ d(localID);
+ }
+ catch (Exception e)
+ {
+ m_log.ErrorFormat(
+ "[EVENT MANAGER]: Delegate for TriggerMovingStartEvent failed - continuing. {0} {1}",
+ e.Message, e.StackTrace);
+ }
+ }
+ }
+ }
+
+ public void TriggerMovingEndEvent(uint localID)
+ {
+ ScriptMovingEndEvent handlerScriptMovingEndEvent = OnScriptMovingEndEvent;
+ if (handlerScriptMovingEndEvent != null)
+ {
+ foreach (ScriptMovingEndEvent d in handlerScriptMovingEndEvent.GetInvocationList())
+ {
+ try
+ {
+ d(localID);
+ }
+ catch (Exception e)
+ {
+ m_log.ErrorFormat(
+ "[EVENT MANAGER]: Delegate for TriggerMovingEndEvent failed - continuing. {0} {1}",
+ e.Message, e.StackTrace);
+ }
+ }
+ }
+ }
+
public void TriggerRequestChangeWaterHeight(float height)
{
if (height < 0)
@@ -2507,13 +2695,10 @@ namespace OpenSim.Region.Framework.Scenes
}
///
- /// Updates the system as to how the position of the sun should be handled.
+ /// Called when the sun's position parameters have changed in the Region and/or Estate
///
- ///
- /// True if the Sun Position is fixed
- /// True if the Estate Settings should be used instead of region
- /// The hour 0.0 <= FixedSunHour <= 24.0 at which the sun is fixed at. Sun Hour 0 is sun-rise, when Day/Night ratio is 1:1
- public void TriggerEstateToolsSunUpdate(ulong regionHandle, bool FixedTime, bool useEstateTime, float FixedSunHour)
+ /// The region that changed
+ public void TriggerEstateToolsSunUpdate(ulong regionHandle)
{
EstateToolsSunUpdate handlerEstateToolsSunUpdate = OnEstateToolsSunUpdate;
if (handlerEstateToolsSunUpdate != null)
@@ -2522,7 +2707,7 @@ namespace OpenSim.Region.Framework.Scenes
{
try
{
- d(regionHandle, FixedTime, useEstateTime, FixedSunHour);
+ d(regionHandle);
}
catch (Exception e)
{
@@ -2957,6 +3142,27 @@ namespace OpenSim.Region.Framework.Scenes
}
}
+ public void TriggerRegionHeartbeatStart(Scene scene)
+ {
+ RegionHeartbeatStart handler = OnRegionHeartbeatStart;
+
+ if (handler != null)
+ {
+ foreach (RegionHeartbeatStart d in handler.GetInvocationList())
+ {
+ try
+ {
+ d(scene);
+ }
+ catch (Exception e)
+ {
+ m_log.ErrorFormat("[EVENT MANAGER]: Delegate for OnRegionHeartbeatStart failed - continuing {0} - {1}",
+ e.Message, e.StackTrace);
+ }
+ }
+ }
+ }
+
public void TriggerRegionHeartbeatEnd(Scene scene)
{
RegionHeartbeatEnd handler = OnRegionHeartbeatEnd;
@@ -3103,5 +3309,26 @@ namespace OpenSim.Region.Framework.Scenes
}
}
}
+
+// public void TriggerGatherUuids(SceneObjectPart sop, IDictionary assetUuids)
+// {
+// GatherUuids handler = OnGatherUuids;
+//
+// if (handler != null)
+// {
+// foreach (GatherUuids d in handler.GetInvocationList())
+// {
+// try
+// {
+// d(sop, assetUuids);
+// }
+// catch (Exception e)
+// {
+// m_log.ErrorFormat("[EVENT MANAGER]: Delegate for TriggerUuidGather failed - continuing {0} - {1}",
+// e.Message, e.StackTrace);
+// }
+// }
+// }
+// }
}
}
diff --git a/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs
new file mode 100644
index 0000000..bbf3b51
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs
@@ -0,0 +1,829 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Timers;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Diagnostics;
+using System.Reflection;
+using System.Threading;
+using OpenMetaverse;
+using OpenSim.Framework;
+using OpenSim.Region.Framework.Interfaces;
+using OpenSim.Region.PhysicsModules.SharedBase;
+using OpenSim.Region.Framework.Scenes.Serialization;
+using System.Runtime.Serialization.Formatters.Binary;
+using System.Runtime.Serialization;
+using Timer = System.Timers.Timer;
+using log4net;
+
+namespace OpenSim.Region.Framework.Scenes
+{
+ public class KeyframeTimer
+ {
+ private static Dictionary m_timers =
+ new Dictionary();
+
+ private Timer m_timer;
+ private Dictionary m_motions = new Dictionary();
+ private object m_lockObject = new object();
+ private object m_timerLock = new object();
+ private const double m_tickDuration = 50.0;
+
+ public double TickDuration
+ {
+ get { return m_tickDuration; }
+ }
+
+ public KeyframeTimer(Scene scene)
+ {
+ m_timer = new Timer();
+ m_timer.Interval = TickDuration;
+ m_timer.AutoReset = true;
+ m_timer.Elapsed += OnTimer;
+ }
+
+ public void Start()
+ {
+ lock (m_timer)
+ {
+ if (!m_timer.Enabled)
+ m_timer.Start();
+ }
+ }
+
+ private void OnTimer(object sender, ElapsedEventArgs ea)
+ {
+ if (!Monitor.TryEnter(m_timerLock))
+ return;
+
+ try
+ {
+ List motions;
+
+ lock (m_lockObject)
+ {
+ motions = new List(m_motions.Keys);
+ }
+
+ foreach (KeyframeMotion m in motions)
+ {
+ try
+ {
+ m.OnTimer(TickDuration);
+ }
+ catch (Exception)
+ {
+ // Don't stop processing
+ }
+ }
+ }
+ catch (Exception)
+ {
+ // Keep running no matter what
+ }
+ finally
+ {
+ Monitor.Exit(m_timerLock);
+ }
+ }
+
+ public static void Add(KeyframeMotion motion)
+ {
+ KeyframeTimer timer;
+
+ if (motion.Scene == null)
+ return;
+
+ lock (m_timers)
+ {
+ if (!m_timers.TryGetValue(motion.Scene, out timer))
+ {
+ timer = new KeyframeTimer(motion.Scene);
+ m_timers[motion.Scene] = timer;
+
+ if (!SceneManager.Instance.AllRegionsReady)
+ {
+ // Start the timers only once all the regions are ready. This is required
+ // when using megaregions, because the megaregion is correctly configured
+ // only after all the regions have been loaded. (If we don't do this then
+ // when the prim moves it might think that it crossed into a region.)
+ SceneManager.Instance.OnRegionsReadyStatusChange += delegate(SceneManager sm)
+ {
+ if (sm.AllRegionsReady)
+ timer.Start();
+ };
+ }
+
+ // Check again, in case the regions were started while we were adding the event handler
+ if (SceneManager.Instance.AllRegionsReady)
+ {
+ timer.Start();
+ }
+ }
+ }
+
+ lock (timer.m_lockObject)
+ {
+ timer.m_motions[motion] = null;
+ }
+ }
+
+ public static void Remove(KeyframeMotion motion)
+ {
+ KeyframeTimer timer;
+
+ if (motion.Scene == null)
+ return;
+
+ lock (m_timers)
+ {
+ if (!m_timers.TryGetValue(motion.Scene, out timer))
+ {
+ return;
+ }
+ }
+
+ lock (timer.m_lockObject)
+ {
+ timer.m_motions.Remove(motion);
+ }
+ }
+ }
+
+ [Serializable]
+ public class KeyframeMotion
+ {
+ //private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+
+ public enum PlayMode : int
+ {
+ Forward = 0,
+ Reverse = 1,
+ Loop = 2,
+ PingPong = 3
+ };
+
+ [Flags]
+ public enum DataFormat : int
+ {
+ Translation = 2,
+ Rotation = 1
+ }
+
+ [Serializable]
+ public struct Keyframe
+ {
+ public Vector3? Position;
+ public Quaternion? Rotation;
+ public Quaternion StartRotation;
+ public int TimeMS;
+ public int TimeTotal;
+ public Vector3 AngularVelocity;
+ public Vector3 StartPosition;
+ };
+
+ private Vector3 m_serializedPosition;
+ private Vector3 m_basePosition;
+ private Quaternion m_baseRotation;
+
+ private Keyframe m_currentFrame;
+
+ private List m_frames = new List();
+
+ private Keyframe[] m_keyframes;
+
+ // skip timer events.
+ //timer.stop doesn't assure there aren't event threads still being fired
+ [NonSerialized()]
+ private bool m_timerStopped;
+
+ [NonSerialized()]
+ private bool m_isCrossing;
+
+ [NonSerialized()]
+ private bool m_waitingCrossing;
+
+ // retry position for cross fail
+ [NonSerialized()]
+ private Vector3 m_nextPosition;
+
+ [NonSerialized()]
+ private SceneObjectGroup m_group;
+
+ private PlayMode m_mode = PlayMode.Forward;
+ private DataFormat m_data = DataFormat.Translation | DataFormat.Rotation;
+
+ private bool m_running = false;
+
+ [NonSerialized()]
+ private bool m_selected = false;
+
+ private int m_iterations = 0;
+
+ private int m_skipLoops = 0;
+
+ [NonSerialized()]
+ private Scene m_scene;
+
+ public Scene Scene
+ {
+ get { return m_scene; }
+ }
+
+ public DataFormat Data
+ {
+ get { return m_data; }
+ }
+
+ public bool Selected
+ {
+ set
+ {
+ if (m_group != null)
+ {
+ if (!value)
+ {
+ // Once we're let go, recompute positions
+ if (m_selected)
+ UpdateSceneObject(m_group);
+ }
+ else
+ {
+ // Save selection position in case we get moved
+ if (!m_selected)
+ {
+ StopTimer();
+ m_serializedPosition = m_group.AbsolutePosition;
+ }
+ }
+ }
+ m_isCrossing = false;
+ m_waitingCrossing = false;
+ m_selected = value;
+ }
+ }
+
+ private void StartTimer()
+ {
+ KeyframeTimer.Add(this);
+ m_timerStopped = false;
+ }
+
+ private void StopTimer()
+ {
+ m_timerStopped = true;
+ KeyframeTimer.Remove(this);
+ }
+
+ public static KeyframeMotion FromData(SceneObjectGroup grp, Byte[] data)
+ {
+ KeyframeMotion newMotion = null;
+
+ try
+ {
+ using (MemoryStream ms = new MemoryStream(data))
+ {
+ BinaryFormatter fmt = new BinaryFormatter();
+ newMotion = (KeyframeMotion)fmt.Deserialize(ms);
+ }
+
+ newMotion.m_group = grp;
+
+ if (grp != null)
+ {
+ newMotion.m_scene = grp.Scene;
+ if (grp.IsSelected)
+ newMotion.m_selected = true;
+ }
+
+ newMotion.m_timerStopped = false;
+ newMotion.m_running = true;
+ newMotion.m_isCrossing = false;
+ newMotion.m_waitingCrossing = false;
+ }
+ catch
+ {
+ newMotion = null;
+ }
+
+ return newMotion;
+ }
+
+ public void UpdateSceneObject(SceneObjectGroup grp)
+ {
+ m_isCrossing = false;
+ m_waitingCrossing = false;
+ StopTimer();
+
+ if (grp == null)
+ return;
+
+ m_group = grp;
+ m_scene = grp.Scene;
+
+ Vector3 grppos = grp.AbsolutePosition;
+ Vector3 offset = grppos - m_serializedPosition;
+ // avoid doing it more than once
+ // current this will happen dragging a prim to other region
+ m_serializedPosition = grppos;
+
+ m_basePosition += offset;
+ m_nextPosition += offset;
+
+ m_currentFrame.StartPosition += offset;
+ m_currentFrame.Position += offset;
+
+ for (int i = 0; i < m_frames.Count; i++)
+ {
+ Keyframe k = m_frames[i];
+ k.StartPosition += offset;
+ k.Position += offset;
+ m_frames[i]=k;
+ }
+
+ if (m_running)
+ Start();
+ }
+
+ public KeyframeMotion(SceneObjectGroup grp, PlayMode mode, DataFormat data)
+ {
+ m_mode = mode;
+ m_data = data;
+
+ m_group = grp;
+ if (grp != null)
+ {
+ m_basePosition = grp.AbsolutePosition;
+ m_baseRotation = grp.GroupRotation;
+ m_scene = grp.Scene;
+ }
+
+ m_timerStopped = true;
+ m_isCrossing = false;
+ m_waitingCrossing = false;
+ }
+
+ public void SetKeyframes(Keyframe[] frames)
+ {
+ m_keyframes = frames;
+ }
+
+ public KeyframeMotion Copy(SceneObjectGroup newgrp)
+ {
+ StopTimer();
+
+ KeyframeMotion newmotion = new KeyframeMotion(null, m_mode, m_data);
+
+ newmotion.m_group = newgrp;
+ newmotion.m_scene = newgrp.Scene;
+
+ if (m_keyframes != null)
+ {
+ newmotion.m_keyframes = new Keyframe[m_keyframes.Length];
+ m_keyframes.CopyTo(newmotion.m_keyframes, 0);
+ }
+
+ newmotion.m_frames = new List(m_frames);
+
+ newmotion.m_basePosition = m_basePosition;
+ newmotion.m_baseRotation = m_baseRotation;
+
+ if (m_selected)
+ newmotion.m_serializedPosition = m_serializedPosition;
+ else
+ {
+ if (m_group != null)
+ newmotion.m_serializedPosition = m_group.AbsolutePosition;
+ else
+ newmotion.m_serializedPosition = m_serializedPosition;
+ }
+
+ newmotion.m_currentFrame = m_currentFrame;
+
+ newmotion.m_iterations = m_iterations;
+ newmotion.m_running = m_running;
+
+ if (m_running && !m_waitingCrossing)
+ StartTimer();
+
+ return newmotion;
+ }
+
+ public void Delete()
+ {
+ m_running = false;
+ StopTimer();
+ m_isCrossing = false;
+ m_waitingCrossing = false;
+ m_frames.Clear();
+ m_keyframes = null;
+ }
+
+ public void Start()
+ {
+ m_isCrossing = false;
+ m_waitingCrossing = false;
+ if (m_keyframes != null && m_group != null && m_keyframes.Length > 0)
+ {
+ StartTimer();
+ m_running = true;
+ m_group.Scene.EventManager.TriggerMovingStartEvent(m_group.RootPart.LocalId);
+ }
+ else
+ {
+ m_running = false;
+ StopTimer();
+ }
+ }
+
+ public void Stop()
+ {
+ m_running = false;
+ m_isCrossing = false;
+ m_waitingCrossing = false;
+
+ StopTimer();
+
+ m_basePosition = m_group.AbsolutePosition;
+ m_baseRotation = m_group.GroupRotation;
+
+ m_group.RootPart.Velocity = Vector3.Zero;
+ m_group.RootPart.AngularVelocity = Vector3.Zero;
+ m_group.SendGroupRootTerseUpdate();
+// m_group.RootPart.ScheduleTerseUpdate();
+ m_frames.Clear();
+ }
+
+ public void Pause()
+ {
+ m_running = false;
+ StopTimer();
+
+ m_group.RootPart.Velocity = Vector3.Zero;
+ m_group.RootPart.AngularVelocity = Vector3.Zero;
+ m_group.SendGroupRootTerseUpdate();
+// m_group.RootPart.ScheduleTerseUpdate();
+
+ }
+
+ private void GetNextList()
+ {
+ m_frames.Clear();
+ Vector3 pos = m_basePosition;
+ Quaternion rot = m_baseRotation;
+
+ if (m_mode == PlayMode.Loop || m_mode == PlayMode.PingPong || m_iterations == 0)
+ {
+ int direction = 1;
+ if (m_mode == PlayMode.Reverse || ((m_mode == PlayMode.PingPong) && ((m_iterations & 1) != 0)))
+ direction = -1;
+
+ int start = 0;
+ int end = m_keyframes.Length;
+
+ if (direction < 0)
+ {
+ start = m_keyframes.Length - 1;
+ end = -1;
+ }
+
+ for (int i = start; i != end ; i += direction)
+ {
+ Keyframe k = m_keyframes[i];
+
+ k.StartPosition = pos;
+ if (k.Position.HasValue)
+ {
+ k.Position = (k.Position * direction);
+// k.Velocity = (Vector3)k.Position / (k.TimeMS / 1000.0f);
+ k.Position += pos;
+ }
+ else
+ {
+ k.Position = pos;
+// k.Velocity = Vector3.Zero;
+ }
+
+ k.StartRotation = rot;
+ if (k.Rotation.HasValue)
+ {
+ if (direction == -1)
+ k.Rotation = Quaternion.Conjugate((Quaternion)k.Rotation);
+ k.Rotation = rot * k.Rotation;
+ }
+ else
+ {
+ k.Rotation = rot;
+ }
+
+/* ang vel not in use for now
+
+ float angle = 0;
+
+ float aa = k.StartRotation.X * k.StartRotation.X + k.StartRotation.Y * k.StartRotation.Y + k.StartRotation.Z * k.StartRotation.Z + k.StartRotation.W * k.StartRotation.W;
+ float bb = ((Quaternion)k.Rotation).X * ((Quaternion)k.Rotation).X + ((Quaternion)k.Rotation).Y * ((Quaternion)k.Rotation).Y + ((Quaternion)k.Rotation).Z * ((Quaternion)k.Rotation).Z + ((Quaternion)k.Rotation).W * ((Quaternion)k.Rotation).W;
+ float aa_bb = aa * bb;
+
+ if (aa_bb == 0)
+ {
+ angle = 0;
+ }
+ else
+ {
+ float ab = k.StartRotation.X * ((Quaternion)k.Rotation).X +
+ k.StartRotation.Y * ((Quaternion)k.Rotation).Y +
+ k.StartRotation.Z * ((Quaternion)k.Rotation).Z +
+ k.StartRotation.W * ((Quaternion)k.Rotation).W;
+ float q = (ab * ab) / aa_bb;
+
+ if (q > 1.0f)
+ {
+ angle = 0;
+ }
+ else
+ {
+ angle = (float)Math.Acos(2 * q - 1);
+ }
+ }
+
+ k.AngularVelocity = (new Vector3(0, 0, 1) * (Quaternion)k.Rotation) * (angle / (k.TimeMS / 1000));
+ */
+ k.TimeTotal = k.TimeMS;
+
+ m_frames.Add(k);
+
+ pos = (Vector3)k.Position;
+ rot = (Quaternion)k.Rotation;
+ }
+
+ m_basePosition = pos;
+ m_baseRotation = rot;
+
+ m_iterations++;
+ }
+ }
+
+ public void OnTimer(double tickDuration)
+ {
+ if (m_skipLoops > 0)
+ {
+ m_skipLoops--;
+ return;
+ }
+
+ if (m_timerStopped) // trap events still in air even after a timer.stop
+ return;
+
+ if (m_group == null)
+ return;
+
+ bool update = false;
+
+ if (m_selected)
+ {
+ if (m_group.RootPart.Velocity != Vector3.Zero)
+ {
+ m_group.RootPart.Velocity = Vector3.Zero;
+ m_group.SendGroupRootTerseUpdate();
+
+ }
+ return;
+ }
+
+ if (m_isCrossing)
+ {
+ // if crossing and timer running then cross failed
+ // wait some time then
+ // retry to set the position that evtually caused the outbound
+ // if still outside region this will call startCrossing below
+ m_isCrossing = false;
+ m_group.AbsolutePosition = m_nextPosition;
+ if (!m_isCrossing)
+ {
+ StopTimer();
+ StartTimer();
+ }
+ return;
+ }
+
+ if (m_frames.Count == 0)
+ {
+ if (!m_running) return;
+
+ GetNextList();
+
+ if (m_frames.Count == 0)
+ {
+ Stop();
+// Scene scene = m_group.Scene;
+//
+// IScriptModule[] scriptModules = scene.RequestModuleInterfaces();
+// foreach (IScriptModule m in scriptModules)
+// {
+// if (m == null)
+// continue;
+// m.PostObjectEvent(m_group.RootPart.UUID, "moving_end", new object[0]);
+// }
+
+ m_group.Scene.EventManager.TriggerMovingEndEvent(m_group.RootPart.LocalId);
+
+ return;
+ }
+
+ m_currentFrame = m_frames[0];
+ m_currentFrame.TimeMS += (int)tickDuration;
+
+ //force a update on a keyframe transition
+ update = true;
+ }
+
+ m_currentFrame.TimeMS -= (int)tickDuration;
+
+ // Do the frame processing
+ double remainingSteps = (double)m_currentFrame.TimeMS / tickDuration;
+
+ if (remainingSteps <= 0.0)
+ {
+ m_group.RootPart.Velocity = Vector3.Zero;
+ m_group.RootPart.AngularVelocity = Vector3.Zero;
+
+ m_nextPosition = (Vector3)m_currentFrame.Position;
+ m_group.AbsolutePosition = m_nextPosition;
+
+ // we are sending imediate updates, no doing force a extra terseUpdate
+ // m_group.UpdateGroupRotationR((Quaternion)m_currentFrame.Rotation);
+
+ m_group.RootPart.RotationOffset = (Quaternion)m_currentFrame.Rotation;
+ m_frames.RemoveAt(0);
+ if (m_frames.Count > 0)
+ m_currentFrame = m_frames[0];
+
+ update = true;
+ }
+ else
+ {
+ float completed = ((float)m_currentFrame.TimeTotal - (float)m_currentFrame.TimeMS) / (float)m_currentFrame.TimeTotal;
+ bool lastStep = m_currentFrame.TimeMS <= tickDuration;
+
+ Vector3 positionThisStep = m_currentFrame.StartPosition + (m_currentFrame.Position.Value - m_currentFrame.StartPosition) * completed;
+ Vector3 motionThisStep = positionThisStep - m_group.AbsolutePosition;
+
+ float mag = Vector3.Mag(motionThisStep);
+
+ if ((mag >= 0.02f) || lastStep)
+ {
+ m_nextPosition = m_group.AbsolutePosition + motionThisStep;
+ m_group.AbsolutePosition = m_nextPosition;
+ update = true;
+ }
+
+ //int totalSteps = m_currentFrame.TimeTotal / (int)tickDuration;
+ //m_log.DebugFormat("KeyframeMotion.OnTimer: step {0}/{1}, curPosition={2}, finalPosition={3}, motionThisStep={4} (scene {5})",
+ // totalSteps - remainingSteps + 1, totalSteps, m_group.AbsolutePosition, m_currentFrame.Position, motionThisStep, m_scene.RegionInfo.RegionName);
+
+ if ((Quaternion)m_currentFrame.Rotation != m_group.GroupRotation)
+ {
+ Quaternion current = m_group.GroupRotation;
+
+ Quaternion step = Quaternion.Slerp(m_currentFrame.StartRotation, (Quaternion)m_currentFrame.Rotation, completed);
+ step.Normalize();
+/* use simpler change detection
+* float angle = 0;
+
+ float aa = current.X * current.X + current.Y * current.Y + current.Z * current.Z + current.W * current.W;
+ float bb = step.X * step.X + step.Y * step.Y + step.Z * step.Z + step.W * step.W;
+ float aa_bb = aa * bb;
+
+ if (aa_bb == 0)
+ {
+ angle = 0;
+ }
+ else
+ {
+ float ab = current.X * step.X +
+ current.Y * step.Y +
+ current.Z * step.Z +
+ current.W * step.W;
+ float q = (ab * ab) / aa_bb;
+
+ if (q > 1.0f)
+ {
+ angle = 0;
+ }
+ else
+ {
+ angle = (float)Math.Acos(2 * q - 1);
+ }
+ }
+
+ if (angle > 0.01f)
+*/
+ if(Math.Abs(step.X - current.X) > 0.001f
+ || Math.Abs(step.Y - current.Y) > 0.001f
+ || Math.Abs(step.Z - current.Z) > 0.001f
+ || lastStep)
+ // assuming w is a dependente var
+
+ {
+// m_group.UpdateGroupRotationR(step);
+ m_group.RootPart.RotationOffset = step;
+
+ //m_group.RootPart.UpdateAngularVelocity(m_currentFrame.AngularVelocity / 2);
+ update = true;
+ }
+ }
+ }
+
+ if (update)
+ {
+ m_group.SendGroupRootTerseUpdate();
+ }
+ }
+
+ public Byte[] Serialize()
+ {
+ StopTimer();
+
+ SceneObjectGroup tmp = m_group;
+ m_group = null;
+ if (!m_selected && tmp != null)
+ m_serializedPosition = tmp.AbsolutePosition;
+
+ using (MemoryStream ms = new MemoryStream())
+ {
+ BinaryFormatter fmt = new BinaryFormatter();
+ fmt.Serialize(ms, this);
+ m_group = tmp;
+ if (m_running && !m_waitingCrossing)
+ StartTimer();
+
+ return ms.ToArray();
+ }
+ }
+
+ public void StartCrossingCheck()
+ {
+ // timer will be restart by crossingFailure
+ // or never since crossing worked and this
+ // should be deleted
+ StopTimer();
+
+ m_isCrossing = true;
+ m_waitingCrossing = true;
+
+ // to remove / retune to smoth crossings
+ if (m_group.RootPart.Velocity != Vector3.Zero)
+ {
+ m_group.RootPart.Velocity = Vector3.Zero;
+ m_group.SendGroupRootTerseUpdate();
+// m_group.RootPart.ScheduleTerseUpdate();
+ }
+ }
+
+ public void CrossingFailure()
+ {
+ m_waitingCrossing = false;
+
+ if (m_group != null)
+ {
+ m_group.RootPart.Velocity = Vector3.Zero;
+ m_group.SendGroupRootTerseUpdate();
+// m_group.RootPart.ScheduleTerseUpdate();
+
+ if (m_running)
+ {
+ StopTimer();
+ m_skipLoops = 1200; // 60 seconds
+ StartTimer();
+ }
+ }
+ }
+ }
+}
diff --git a/OpenSim/Region/Framework/Scenes/Prioritizer.cs b/OpenSim/Region/Framework/Scenes/Prioritizer.cs
index 1b10e3c..ae85560 100644
--- a/OpenSim/Region/Framework/Scenes/Prioritizer.cs
+++ b/OpenSim/Region/Framework/Scenes/Prioritizer.cs
@@ -31,7 +31,7 @@ using log4net;
using Nini.Config;
using OpenSim.Framework;
using OpenMetaverse;
-using OpenSim.Region.Physics.Manager;
+using OpenSim.Region.PhysicsModules.SharedBase;
/*
* Steps to add a new prioritization policy:
diff --git a/OpenSim/Region/Framework/Scenes/RegionStatsHandler.cs b/OpenSim/Region/Framework/Scenes/RegionStatsHandler.cs
index c11174d..3b31281 100644
--- a/OpenSim/Region/Framework/Scenes/RegionStatsHandler.cs
+++ b/OpenSim/Region/Framework/Scenes/RegionStatsHandler.cs
@@ -35,7 +35,6 @@ using Nini.Config;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
using OpenSim.Framework;
-using OpenSim.Framework.Communications;
using OpenSim.Framework.Console;
using OpenSim.Framework.Servers;
using OpenSim.Framework.Servers.HttpServer;
@@ -46,47 +45,33 @@ using OpenSim.Region.Framework.Scenes;
namespace OpenSim.Region.Framework.Scenes
{
- public class RegionStatsHandler : IStreamedRequestHandler
+ public class RegionStatsHandler : BaseStreamHandler
{
//private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
- private string osRXStatsURI = String.Empty;
private string osXStatsURI = String.Empty;
//private string osSecret = String.Empty;
private OpenSim.Framework.RegionInfo regionInfo;
public string localZone = TimeZone.CurrentTimeZone.StandardName;
public TimeSpan utcOffset = TimeZone.CurrentTimeZone.GetUtcOffset(DateTime.Now);
- public string Name { get { return "RegionStats"; } }
- public string Description { get { return "Region Statistics"; } }
-
- public RegionStatsHandler(RegionInfo region_info)
+ public RegionStatsHandler(RegionInfo region_info)
+ : base("GET", "/" + Util.SHA1Hash(region_info.regionSecret), "RegionStats", "Region Statistics")
{
regionInfo = region_info;
- osRXStatsURI = Util.SHA1Hash(regionInfo.regionSecret);
osXStatsURI = Util.SHA1Hash(regionInfo.osSecret);
}
- public byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
+ protected override byte[] ProcessRequest(
+ string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
{
return Util.UTF8.GetBytes(Report());
}
- public string ContentType
+ public override string ContentType
{
get { return "text/plain"; }
}
-
- public string HttpMethod
- {
- get { return "GET"; }
- }
-
- public string Path
- {
- // This is for the region and is the regionSecret hashed
- get { return "/" + osRXStatsURI; }
- }
private string Report()
{
diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
index a6db4de..b838177 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
@@ -30,22 +30,27 @@ using System.Collections.Generic;
using System.Collections;
using System.Reflection;
using System.Text;
+using System.Threading;
using System.Timers;
+using System.Xml;
using OpenMetaverse;
using OpenMetaverse.Packets;
using log4net;
using OpenSim.Framework;
+using OpenSim.Framework.Serialization.External;
using OpenSim.Region.Framework;
using OpenSim.Framework.Client;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes.Serialization;
+using OpenSim.Services.Interfaces;
+using PermissionMask = OpenSim.Framework.PermissionMask;
namespace OpenSim.Region.Framework.Scenes
{
public partial class Scene
{
- private static readonly ILog m_log
- = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+ private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+ //private static readonly string LogHeader = "[SCENE INVENTORY]";
///
/// Allows asynchronous derezzing of objects from the scene into a client's inventory.
@@ -125,11 +130,16 @@ namespace OpenSim.Region.Framework.Scenes
}
}
+ public bool AddInventoryItem(InventoryItemBase item)
+ {
+ return AddInventoryItem(item, true);
+ }
+
///
/// Add the given inventory item to a user's inventory.
///
///
- public bool AddInventoryItem(InventoryItemBase item)
+ public bool AddInventoryItem(InventoryItemBase item, bool trigger)
{
if (item.Folder != UUID.Zero && InventoryService.AddItem(item))
{
@@ -138,14 +148,17 @@ namespace OpenSim.Region.Framework.Scenes
{
userlevel = 1;
}
- EventManager.TriggerOnNewInventoryItemUploadComplete(item.Owner, item.AssetID, item.Name, userlevel);
+ if (trigger)
+ EventManager.TriggerOnNewInventoryItemUploadComplete(item.Owner, (AssetType)item.AssetType, item.AssetID, item.Name, userlevel);
return true;
}
// OK so either the viewer didn't send a folderID or AddItem failed
UUID originalFolder = item.Folder;
- InventoryFolderBase f = InventoryService.GetFolderForType(item.Owner, (AssetType)item.AssetType);
+ InventoryFolderBase f = null;
+ if (Enum.IsDefined(typeof(FolderType), (sbyte)item.AssetType))
+ f = InventoryService.GetFolderForType(item.Owner, (FolderType)item.AssetType);
if (f != null)
{
m_log.DebugFormat(
@@ -177,7 +190,8 @@ namespace OpenSim.Region.Framework.Scenes
{
userlevel = 1;
}
- EventManager.TriggerOnNewInventoryItemUploadComplete(item.Owner, item.AssetID, item.Name, userlevel);
+ if (trigger)
+ EventManager.TriggerOnNewInventoryItemUploadComplete(item.Owner, (AssetType)item.AssetType, item.AssetID, item.Name, userlevel);
if (originalFolder != UUID.Zero)
{
@@ -325,7 +339,7 @@ namespace OpenSim.Region.Framework.Scenes
// Update item with new asset
item.AssetID = asset.FullID;
if (group.UpdateInventoryItem(item))
- remoteClient.SendAgentAlertMessage("Script saved", false);
+ remoteClient.SendAlertMessage("Script saved");
part.SendPropertiesToClient(remoteClient);
@@ -341,7 +355,7 @@ namespace OpenSim.Region.Framework.Scenes
}
else
{
- remoteClient.SendAgentAlertMessage("Script saved", false);
+ remoteClient.SendAlertMessage("Script saved");
}
// Tell anyone managing scripts that a script has been reloaded/changed
@@ -415,20 +429,61 @@ namespace OpenSim.Region.Framework.Scenes
// itemUpd.NextPermissions, itemUpd.GroupPermissions, itemUpd.EveryOnePermissions, item.Flags,
// item.NextPermissions, item.GroupPermissions, item.EveryOnePermissions, item.CurrentPermissions);
+ bool sendUpdate = false;
+
if (itemUpd.NextPermissions != 0) // Use this to determine validity. Can never be 0 if valid
{
+ // Create a set of base permissions that will not include export if the user
+ // is not allowed to change the export flag.
+ bool denyExportChange = false;
+
+// m_log.DebugFormat("[XXX]: B: {0} O: {1} E: {2}", itemUpd.BasePermissions, itemUpd.CurrentPermissions, itemUpd.EveryOnePermissions);
+
+ // If the user is not the creator or doesn't have "E" in both "B" and "O", deny setting export
+ if ((item.BasePermissions & (uint)(PermissionMask.All | PermissionMask.Export)) != (uint)(PermissionMask.All | PermissionMask.Export) || (item.CurrentPermissions & (uint)PermissionMask.Export) == 0 || item.CreatorIdAsUuid != item.Owner)
+ denyExportChange = true;
+
+// m_log.DebugFormat("[XXX]: Deny Export Update {0}", denyExportChange);
+
+ // If it is already set, force it set and also force full perm
+ // else prevent setting it. It can and should never be set unless
+ // set in base, so the condition above is valid
+ if (denyExportChange)
+ {
+ // If we are not allowed to change it, then force it to the
+ // original item's setting and if it was on, also force full perm
+ if ((item.EveryOnePermissions & (uint)PermissionMask.Export) != 0)
+ {
+ itemUpd.NextPermissions = (uint)(PermissionMask.All);
+ itemUpd.EveryOnePermissions |= (uint)PermissionMask.Export;
+ }
+ else
+ {
+ itemUpd.EveryOnePermissions &= ~(uint)PermissionMask.Export;
+ }
+ }
+ else
+ {
+ // If the new state is exportable, force full perm
+ if ((itemUpd.EveryOnePermissions & (uint)PermissionMask.Export) != 0)
+ {
+// m_log.DebugFormat("[XXX]: Force full perm");
+ itemUpd.NextPermissions = (uint)(PermissionMask.All);
+ }
+ }
+
if (item.NextPermissions != (itemUpd.NextPermissions & item.BasePermissions))
item.Flags |= (uint)InventoryItemFlags.ObjectOverwriteNextOwner;
item.NextPermissions = itemUpd.NextPermissions & item.BasePermissions;
+
if (item.EveryOnePermissions != (itemUpd.EveryOnePermissions & item.BasePermissions))
item.Flags |= (uint)InventoryItemFlags.ObjectOverwriteEveryone;
item.EveryOnePermissions = itemUpd.EveryOnePermissions & item.BasePermissions;
+
if (item.GroupPermissions != (itemUpd.GroupPermissions & item.BasePermissions))
item.Flags |= (uint)InventoryItemFlags.ObjectOverwriteGroup;
-
-// m_log.DebugFormat("[USER INVENTORY]: item.Flags {0}", item.Flags);
-
item.GroupPermissions = itemUpd.GroupPermissions & item.BasePermissions;
+
item.GroupID = itemUpd.GroupID;
item.GroupOwned = itemUpd.GroupOwned;
item.CreationDate = itemUpd.CreationDate;
@@ -449,6 +504,12 @@ namespace OpenSim.Region.Framework.Scenes
item.SalePrice = itemUpd.SalePrice;
item.SaleType = itemUpd.SaleType;
+ if (item.InvType == (int)InventoryType.Wearable && (item.Flags & 0xf) == 0 && (itemUpd.Flags & 0xf) != 0)
+ {
+ item.Flags = (uint)(item.Flags & 0xfffffff0) | (itemUpd.Flags & 0xf);
+ sendUpdate = true;
+ }
+
InventoryService.UpdateItem(item);
}
@@ -459,6 +520,17 @@ namespace OpenSim.Region.Framework.Scenes
AgentTransactionsModule.HandleItemUpdateFromTransaction(remoteClient, transactionID, item);
}
}
+ else
+ {
+ // This MAY be problematic, if it is, another solution
+ // needs to be found. If inventory item flags are updated
+ // the viewer's notion of the item needs to be refreshed.
+ //
+ // In other situations we cannot send out a bulk update here, since this will cause editing of clothing to start
+ // failing frequently. Possibly this is a race with a separate transaction that uploads the asset.
+ if (sendUpdate)
+ remoteClient.SendBulkUpdateInventory(item);
+ }
}
else
{
@@ -474,9 +546,9 @@ namespace OpenSim.Region.Framework.Scenes
///
/// ID of the sender of the item
///
- public virtual void GiveInventoryItem(IClientAPI recipientClient, UUID senderId, UUID itemId)
+ public virtual void GiveInventoryItem(IClientAPI recipientClient, UUID senderId, UUID itemId, out string message)
{
- InventoryItemBase itemCopy = GiveInventoryItem(recipientClient.AgentId, senderId, itemId);
+ InventoryItemBase itemCopy = GiveInventoryItem(recipientClient.AgentId, senderId, itemId, out message);
if (itemCopy != null)
recipientClient.SendBulkUpdateInventory(itemCopy);
@@ -489,9 +561,9 @@ namespace OpenSim.Region.Framework.Scenes
/// ID of the sender of the item
///
/// The inventory item copy given, null if the give was unsuccessful
- public virtual InventoryItemBase GiveInventoryItem(UUID recipient, UUID senderId, UUID itemId)
+ public virtual InventoryItemBase GiveInventoryItem(UUID recipient, UUID senderId, UUID itemId, out string message)
{
- return GiveInventoryItem(recipient, senderId, itemId, UUID.Zero);
+ return GiveInventoryItem(recipient, senderId, itemId, UUID.Zero, out message);
}
///
@@ -508,10 +580,16 @@ namespace OpenSim.Region.Framework.Scenes
/// The inventory item copy given, null if the give was unsuccessful
///
public virtual InventoryItemBase GiveInventoryItem(
- UUID recipient, UUID senderId, UUID itemId, UUID recipientFolderId)
+ UUID recipient, UUID senderId, UUID itemId, UUID recipientFolderId, out string message)
{
//Console.WriteLine("Scene.Inventory.cs: GiveInventoryItem");
+ if (!Permissions.CanTransferUserInventory(itemId, senderId, recipient))
+ {
+ message = "Not allowed to transfer this item.";
+ return null;
+ }
+
InventoryItemBase item = new InventoryItemBase(itemId, senderId);
item = InventoryService.GetItem(item);
@@ -519,6 +597,7 @@ namespace OpenSim.Region.Framework.Scenes
{
m_log.WarnFormat(
"[AGENT INVENTORY]: Failed to find item {0} sent by {1} to {2}", itemId, senderId, recipient);
+ message = string.Format("Item not found: {0}.", itemId);
return null;
}
@@ -527,6 +606,7 @@ namespace OpenSim.Region.Framework.Scenes
m_log.WarnFormat(
"[AGENT INVENTORY]: Attempt to send item {0} {1} to {2} failed because sender {3} did not match item owner {4}",
item.Name, item.ID, recipient, senderId, item.Owner);
+ message = "Sender did not match item owner.";
return null;
}
@@ -537,7 +617,10 @@ namespace OpenSim.Region.Framework.Scenes
if (!Permissions.BypassPermissions())
{
if ((item.CurrentPermissions & (uint)PermissionMask.Transfer) == 0)
+ {
+ message = "Item doesn't have the Transfer permission.";
return null;
+ }
}
// Insert a copy of the item into the recipient
@@ -606,17 +689,13 @@ namespace OpenSim.Region.Framework.Scenes
// a mask
if (item.InvType == (int)InventoryType.Object)
{
- // Create a safe mask for the current perms
- uint foldedPerms = (item.CurrentPermissions & 7) << 13;
- foldedPerms |= permsMask;
-
bool isRootMod = (item.CurrentPermissions &
(uint)PermissionMask.Modify) != 0 ?
true : false;
// Mask the owner perms to the folded perms
- ownerPerms &= foldedPerms;
- basePerms &= foldedPerms;
+ PermissionsUtil.ApplyFoldedPermissions(item.CurrentPermissions, ref ownerPerms);
+ PermissionsUtil.ApplyFoldedPermissions(item.CurrentPermissions, ref basePerms);
// If the root was mod, let the mask reflect that
// We also need to adjust the base here, because
@@ -666,7 +745,9 @@ namespace OpenSim.Region.Framework.Scenes
if (itemCopy.Folder == UUID.Zero)
{
- InventoryFolderBase folder = InventoryService.GetFolderForType(recipient, (AssetType)itemCopy.AssetType);
+ InventoryFolderBase folder = null;
+ if (Enum.IsDefined(typeof(FolderType), (sbyte)item.AssetType))
+ folder = InventoryService.GetFolderForType(recipient, (FolderType)itemCopy.AssetType);
if (folder != null)
{
@@ -677,9 +758,14 @@ namespace OpenSim.Region.Framework.Scenes
InventoryFolderBase root = InventoryService.GetRootFolder(recipient);
if (root != null)
+ {
itemCopy.Folder = root.ID;
+ }
else
- return null; // No destination
+ {
+ message = "Can't find a folder to add the item to.";
+ return null;
+ }
}
}
@@ -692,7 +778,7 @@ namespace OpenSim.Region.Framework.Scenes
IInventoryAccessModule invAccess = RequestModuleInterface();
if (invAccess != null)
invAccess.TransferInventoryAssets(itemCopy, senderId, recipient);
- AddInventoryItem(itemCopy);
+ AddInventoryItem(itemCopy, false);
if (!Permissions.BypassPermissions())
{
@@ -704,6 +790,7 @@ namespace OpenSim.Region.Framework.Scenes
}
}
+ message = null;
return itemCopy;
}
@@ -721,11 +808,11 @@ namespace OpenSim.Region.Framework.Scenes
///
/// The inventory folder copy given, null if the copy was unsuccessful
///
- public virtual InventoryFolderBase GiveInventoryFolder(
+ public virtual InventoryFolderBase GiveInventoryFolder(IClientAPI client,
UUID recipientId, UUID senderId, UUID folderId, UUID recipientParentFolderId)
{
//// Retrieve the folder from the sender
- InventoryFolderBase folder = InventoryService.GetFolder(new InventoryFolderBase(folderId));
+ InventoryFolderBase folder = InventoryService.GetFolder(new InventoryFolderBase(folderId, senderId));
if (null == folder)
{
m_log.ErrorFormat(
@@ -756,13 +843,18 @@ namespace OpenSim.Region.Framework.Scenes
InventoryCollection contents = InventoryService.GetFolderContent(senderId, folderId);
foreach (InventoryFolderBase childFolder in contents.Folders)
{
- GiveInventoryFolder(recipientId, senderId, childFolder.ID, newFolder.ID);
+ GiveInventoryFolder(client, recipientId, senderId, childFolder.ID, newFolder.ID);
}
// Give all the items
foreach (InventoryItemBase item in contents.Items)
{
- GiveInventoryItem(recipientId, senderId, item.ID, newFolder.ID);
+ string message;
+ if (GiveInventoryItem(recipientId, senderId, item.ID, newFolder.ID, out message) == null)
+ {
+ if (client != null)
+ client.SendAgentAlertMessage(message, false);
+ }
}
return newFolder;
@@ -794,51 +886,34 @@ namespace OpenSim.Region.Framework.Scenes
return;
}
- AssetBase asset = AssetService.Get(item.AssetID.ToString());
+ if (newName == String.Empty)
+ newName = item.Name;
- if (asset != null)
+ if (remoteClient.AgentId == oldAgentID
+ || (LibraryService != null
+ && LibraryService.LibraryRootFolder != null
+ && oldAgentID == LibraryService.LibraryRootFolder.Owner))
{
- if (newName != String.Empty)
- {
- asset.Name = newName;
- }
- else
- {
- newName = item.Name;
- }
-
- if (remoteClient.AgentId == oldAgentID
- || (LibraryService != null
- && LibraryService.LibraryRootFolder != null
- && oldAgentID == LibraryService.LibraryRootFolder.Owner))
+ CreateNewInventoryItem(
+ remoteClient, item.CreatorId, item.CreatorData, newFolderID,
+ newName, item.Description, item.Flags, callbackID, item.AssetID, (sbyte)item.AssetType, (sbyte)item.InvType,
+ item.BasePermissions, item.CurrentPermissions, item.EveryOnePermissions,
+ item.NextPermissions, item.GroupPermissions, Util.UnixTimeSinceEpoch(), false);
+ }
+ else
+ {
+ // If item is transfer or permissions are off or calling agent is allowed to copy item owner's inventory item.
+ if (((item.CurrentPermissions & (uint)PermissionMask.Transfer) != 0)
+ && (m_permissions.BypassPermissions()
+ || m_permissions.CanCopyUserInventory(remoteClient.AgentId, oldItemID)))
{
CreateNewInventoryItem(
- remoteClient, item.CreatorId, item.CreatorData, newFolderID,
- newName, item.Description, item.Flags, callbackID, asset, (sbyte)item.InvType,
- item.BasePermissions, item.CurrentPermissions, item.EveryOnePermissions,
- item.NextPermissions, item.GroupPermissions, Util.UnixTimeSinceEpoch());
- }
- else
- {
- // If item is transfer or permissions are off or calling agent is allowed to copy item owner's inventory item.
- if (((item.CurrentPermissions & (uint)PermissionMask.Transfer) != 0)
- && (m_permissions.BypassPermissions()
- || m_permissions.CanCopyUserInventory(remoteClient.AgentId, oldItemID)))
- {
- CreateNewInventoryItem(
- remoteClient, item.CreatorId, item.CreatorData, newFolderID, newName, item.Description, item.Flags, callbackID,
- asset, (sbyte) item.InvType,
- item.NextPermissions, item.NextPermissions, item.EveryOnePermissions & item.NextPermissions,
- item.NextPermissions, item.GroupPermissions, Util.UnixTimeSinceEpoch());
- }
+ remoteClient, item.CreatorId, item.CreatorData, newFolderID, newName, item.Description, item.Flags, callbackID,
+ item.AssetID, (sbyte)item.AssetType, (sbyte) item.InvType,
+ item.NextPermissions, item.NextPermissions, item.EveryOnePermissions & item.NextPermissions,
+ item.NextPermissions, item.GroupPermissions, Util.UnixTimeSinceEpoch(), false);
}
}
- else
- {
- m_log.ErrorFormat(
- "[AGENT INVENTORY]: Could not copy item {0} since asset {1} could not be found",
- item.Name, item.AssetID);
- }
}
///
@@ -888,11 +963,12 @@ namespace OpenSim.Region.Framework.Scenes
public void CreateNewInventoryItem(
IClientAPI remoteClient, string creatorID, string creatorData, UUID folderID,
string name, string description, uint flags, uint callbackID,
- AssetBase asset, sbyte invType, uint nextOwnerMask, int creationDate)
+ UUID assetID, sbyte assetType, sbyte invType, uint nextOwnerMask, int creationDate)
{
CreateNewInventoryItem(
- remoteClient, creatorID, creatorData, folderID, name, description, flags, callbackID, asset, invType,
- (uint)PermissionMask.All, (uint)PermissionMask.All, 0, nextOwnerMask, 0, creationDate);
+ remoteClient, creatorID, creatorData, folderID, name, description, flags, callbackID, assetID, assetType, invType,
+ (uint)PermissionMask.All | (uint)PermissionMask.Export, (uint)PermissionMask.All | (uint)PermissionMask.Export, 0, nextOwnerMask, 0,
+ creationDate, true);
}
///
@@ -916,19 +992,20 @@ namespace OpenSim.Region.Framework.Scenes
/// Unix timestamp at which this item was created.
private void CreateNewInventoryItem(
IClientAPI remoteClient, string creatorID, string creatorData, UUID folderID,
- string name, string description, uint flags, uint callbackID, AssetBase asset, sbyte invType,
- uint baseMask, uint currentMask, uint everyoneMask, uint nextOwnerMask, uint groupMask, int creationDate)
+ string name, string description, uint flags, uint callbackID, UUID assetID, sbyte assetType, sbyte invType,
+ uint baseMask, uint currentMask, uint everyoneMask, uint nextOwnerMask, uint groupMask, int creationDate,
+ bool assetUpload)
{
InventoryItemBase item = new InventoryItemBase();
item.Owner = remoteClient.AgentId;
item.CreatorId = creatorID;
item.CreatorData = creatorData;
item.ID = UUID.Random();
- item.AssetID = asset.FullID;
+ item.AssetID = assetID;
item.Name = name;
item.Description = description;
item.Flags = flags;
- item.AssetType = asset.Type;
+ item.AssetType = assetType;
item.InvType = invType;
item.Folder = folderID;
item.CurrentPermissions = currentMask;
@@ -938,7 +1015,7 @@ namespace OpenSim.Region.Framework.Scenes
item.BasePermissions = baseMask;
item.CreationDate = creationDate;
- if (AddInventoryItem(item))
+ if (AddInventoryItem(item, assetUpload))
{
remoteClient.SendInventoryItemCreateUpdate(item, callbackID);
}
@@ -1001,17 +1078,12 @@ namespace OpenSim.Region.Framework.Scenes
// return;
// }
- AssetBase asset = new AssetBase();
- asset.FullID = olditemID;
- asset.Type = type;
- asset.Name = name;
- asset.Description = description;
-
CreateNewInventoryItem(
remoteClient, remoteClient.AgentId.ToString(), string.Empty, folderID,
- name, description, 0, callbackID, asset, invType,
- (uint)PermissionMask.All, (uint)PermissionMask.All, (uint)PermissionMask.All,
- (uint)PermissionMask.All, (uint)PermissionMask.All, Util.UnixTimeSinceEpoch());
+ name, description, 0, callbackID, olditemID, type, invType,
+ (uint)PermissionMask.All | (uint)PermissionMask.Export, (uint)PermissionMask.All | (uint)PermissionMask.Export, (uint)PermissionMask.All,
+ (uint)PermissionMask.All | (uint)PermissionMask.Export, (uint)PermissionMask.All | (uint)PermissionMask.Export, Util.UnixTimeSinceEpoch(),
+ false);
}
else
{
@@ -1087,13 +1159,21 @@ namespace OpenSim.Region.Framework.Scenes
if (item == null)
return;
- InventoryFolderBase destFolder = InventoryService.GetFolderForType(remoteClient.AgentId, AssetType.TrashFolder);
+ InventoryFolderBase destFolder = InventoryService.GetFolderForType(remoteClient.AgentId, FolderType.Trash);
- // Move the item to trash. If this is a copiable item, only
+ // Move the item to trash. If this is a copyable item, only
// a copy will be moved and we will still need to delete
- // the item from the prim. If it was no copy, is will be
+ // the item from the prim. If it was no copy, it will be
// deleted by this method.
- MoveTaskInventoryItem(remoteClient, destFolder.ID, part, itemID);
+ string message;
+ InventoryItemBase item2 = MoveTaskInventoryItem(remoteClient, destFolder.ID, part, itemID, out message);
+
+ if (item2 == null)
+ {
+ m_log.WarnFormat("[SCENE INVENTORY]: RemoveTaskInventory of item {0} failed: {1}", itemID, message);
+ remoteClient.SendAgentAlertMessage(message, false);
+ return;
+ }
if (group.GetInventoryItem(localID, itemID) != null)
{
@@ -1105,11 +1185,16 @@ namespace OpenSim.Region.Framework.Scenes
group.RemoveInventoryItem(localID, itemID);
}
+
part.SendPropertiesToClient(remoteClient);
}
}
- private InventoryItemBase CreateAgentInventoryItemFromTask(UUID destAgent, SceneObjectPart part, UUID itemId)
+
+ ///
+ /// Creates (in memory only) a user inventory item that will contain a copy of a task inventory item.
+ ///
+ private InventoryItemBase CreateAgentInventoryItemFromTask(UUID destAgent, SceneObjectPart part, UUID itemId, out string message)
{
TaskInventoryItem taskItem = part.Inventory.GetInventoryItem(itemId);
@@ -1120,12 +1205,13 @@ namespace OpenSim.Region.Framework.Scenes
+ " inventory item from a prim's inventory item "
+ " but the required item does not exist in the prim's inventory",
itemId, part.Name, part.UUID);
-
+ message = "Item not found: " + itemId;
return null;
}
if ((destAgent != taskItem.OwnerID) && ((taskItem.CurrentPermissions & (uint)PermissionMask.Transfer) == 0))
{
+ message = "Item doesn't have the Transfer permission.";
return null;
}
@@ -1146,9 +1232,21 @@ namespace OpenSim.Region.Framework.Scenes
{
agentItem.BasePermissions = taskItem.BasePermissions & (taskItem.NextPermissions | (uint)PermissionMask.Move);
if (taskItem.InvType == (int)InventoryType.Object)
- agentItem.CurrentPermissions = agentItem.BasePermissions & (((taskItem.CurrentPermissions & 7) << 13) | (taskItem.CurrentPermissions & (uint)PermissionMask.Move));
- else
- agentItem.CurrentPermissions = agentItem.BasePermissions & taskItem.CurrentPermissions;
+ {
+ // Bake the new base permissions from folded permissions
+ // The folded perms are in the lowest 3 bits of the current perms
+ // We use base permissions here to avoid baking the "Locked" status
+ // into the item as it is passed.
+ uint perms = taskItem.BasePermissions & taskItem.NextPermissions;
+ PermissionsUtil.ApplyFoldedPermissions(taskItem.CurrentPermissions, ref perms);
+ // Avoid the "lock trap" - move must always be enabled but the above may remove it
+ // Add it back here.
+ agentItem.BasePermissions = perms | (uint)PermissionMask.Move;
+ // Newly given items cannot be "locked" on rez. Make sure by
+ // setting current equal to base.
+ }
+
+ agentItem.CurrentPermissions = agentItem.BasePermissions;
agentItem.Flags |= (uint)InventoryItemFlags.ObjectSlamPerm;
agentItem.NextPermissions = taskItem.NextPermissions;
@@ -1164,11 +1262,24 @@ namespace OpenSim.Region.Framework.Scenes
agentItem.GroupPermissions = taskItem.GroupPermissions;
}
+ message = null;
+ return agentItem;
+ }
+
+ ///
+ /// If the task item is not-copyable then remove it from the prim.
+ ///
+ private void RemoveNonCopyTaskItemFromPrim(SceneObjectPart part, UUID itemId)
+ {
+ TaskInventoryItem taskItem = part.Inventory.GetInventoryItem(itemId);
+ if (taskItem == null)
+ return;
+
if (!Permissions.BypassPermissions())
{
if ((taskItem.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
{
- if (taskItem.Type == 10)
+ if (taskItem.Type == (int)AssetType.LSLText)
{
part.RemoveScriptEvents(itemId);
EventManager.TriggerRemoveScript(part.LocalId, itemId);
@@ -1177,8 +1288,6 @@ namespace OpenSim.Region.Framework.Scenes
part.Inventory.RemoveInventoryItem(itemId);
}
}
-
- return agentItem;
}
///
@@ -1188,19 +1297,22 @@ namespace OpenSim.Region.Framework.Scenes
///
///
///
- public InventoryItemBase MoveTaskInventoryItem(IClientAPI remoteClient, UUID folderId, SceneObjectPart part, UUID itemId)
+ public InventoryItemBase MoveTaskInventoryItem(IClientAPI remoteClient, UUID folderId, SceneObjectPart part, UUID itemId, out string message)
{
m_log.DebugFormat(
"[PRIM INVENTORY]: Adding item {0} from {1} to folder {2} for {3}",
itemId, part.Name, folderId, remoteClient.Name);
- InventoryItemBase agentItem = CreateAgentInventoryItemFromTask(remoteClient.AgentId, part, itemId);
-
+ InventoryItemBase agentItem = CreateAgentInventoryItemFromTask(remoteClient.AgentId, part, itemId, out message);
if (agentItem == null)
return null;
agentItem.Folder = folderId;
AddInventoryItem(remoteClient, agentItem);
+
+ RemoveNonCopyTaskItemFromPrim(part, itemId);
+
+ message = null;
return agentItem;
}
@@ -1251,7 +1363,11 @@ namespace OpenSim.Region.Framework.Scenes
return;
}
- MoveTaskInventoryItem(remoteClient, folderId, part, itemId);
+ string message;
+ InventoryItemBase item = MoveTaskInventoryItem(remoteClient, folderId, part, itemId, out message);
+
+ if (item == null)
+ remoteClient.SendAgentAlertMessage(message, false);
}
///
@@ -1265,17 +1381,17 @@ namespace OpenSim.Region.Framework.Scenes
///
///
///
- public InventoryItemBase MoveTaskInventoryItem(UUID avatarId, UUID folderId, SceneObjectPart part, UUID itemId)
+ public InventoryItemBase MoveTaskInventoryItem(UUID avatarId, UUID folderId, SceneObjectPart part, UUID itemId, out string message)
{
ScenePresence avatar;
if (TryGetScenePresence(avatarId, out avatar))
{
- return MoveTaskInventoryItem(avatar.ControllingClient, folderId, part, itemId);
+ return MoveTaskInventoryItem(avatar.ControllingClient, folderId, part, itemId, out message);
}
else
{
- InventoryItemBase agentItem = CreateAgentInventoryItemFromTask(avatarId, part, itemId);
+ InventoryItemBase agentItem = CreateAgentInventoryItemFromTask(avatarId, part, itemId, out message);
if (agentItem == null)
return null;
@@ -1284,6 +1400,8 @@ namespace OpenSim.Region.Framework.Scenes
AddInventoryItem(agentItem);
+ RemoveNonCopyTaskItemFromPrim(part, itemId);
+
return agentItem;
}
}
@@ -1389,6 +1507,11 @@ namespace OpenSim.Region.Framework.Scenes
public UUID MoveTaskInventoryItems(UUID destID, string category, SceneObjectPart host, List items)
{
+ ScenePresence avatar;
+ IClientAPI remoteClient = null;
+ if (TryGetScenePresence(destID, out avatar))
+ remoteClient = avatar.ControllingClient;
+
InventoryFolderBase rootFolder = InventoryService.GetRootFolder(destID);
UUID newFolderID = UUID.Random();
@@ -1398,26 +1521,28 @@ namespace OpenSim.Region.Framework.Scenes
foreach (UUID itemID in items)
{
- InventoryItemBase agentItem = CreateAgentInventoryItemFromTask(destID, host, itemID);
+ string message;
+ InventoryItemBase agentItem = CreateAgentInventoryItemFromTask(destID, host, itemID, out message);
if (agentItem != null)
{
agentItem.Folder = newFolderID;
AddInventoryItem(agentItem);
+
+ RemoveNonCopyTaskItemFromPrim(host, itemID);
+ }
+ else
+ {
+ if (remoteClient != null)
+ remoteClient.SendAgentAlertMessage(message, false);
}
}
- ScenePresence avatar = null;
- if (TryGetScenePresence(destID, out avatar))
+ if (remoteClient != null)
{
- //profile.SendInventoryDecendents(avatar.ControllingClient,
- // profile.RootFolder.ID, true, false);
- //profile.SendInventoryDecendents(avatar.ControllingClient,
- // newFolderID, false, true);
-
- SendInventoryUpdate(avatar.ControllingClient, rootFolder, true, false);
- SendInventoryUpdate(avatar.ControllingClient, newFolder, false, true);
+ SendInventoryUpdate(remoteClient, rootFolder, true, false);
+ SendInventoryUpdate(remoteClient, newFolder, false, true);
}
return newFolderID;
@@ -1572,11 +1697,11 @@ namespace OpenSim.Region.Framework.Scenes
remoteClient, part, transactionID, currentItem);
if ((InventoryType)itemInfo.InvType == InventoryType.Notecard)
- remoteClient.SendAgentAlertMessage("Notecard saved", false);
+ remoteClient.SendAlertMessage("Notecard saved");
else if ((InventoryType)itemInfo.InvType == InventoryType.LSL)
- remoteClient.SendAgentAlertMessage("Script saved", false);
+ remoteClient.SendAlertMessage("Script saved");
else
- remoteClient.SendAgentAlertMessage("Item saved", false);
+ remoteClient.SendAlertMessage("Item saved");
}
// Base ALWAYS has move
@@ -1739,6 +1864,21 @@ namespace OpenSim.Region.Framework.Scenes
/// The part where the script was rezzed if successful. False otherwise.
public SceneObjectPart RezNewScript(UUID agentID, InventoryItemBase itemBase)
{
+ return RezNewScript(
+ agentID,
+ itemBase,
+ "default\n{\n state_entry()\n {\n llSay(0, \"Script running\");\n }\n}");
+ }
+
+ ///
+ /// Rez a new script from nothing with given script text.
+ ///
+ ///
+ /// Template item.
+ ///
+ /// The part where the script was rezzed if successful. False otherwise.
+ public SceneObjectPart RezNewScript(UUID agentID, InventoryItemBase itemBase, string scriptText)
+ {
// The part ID is the folder ID!
SceneObjectPart part = GetSceneObjectPart(itemBase.Folder);
if (part == null)
@@ -1758,9 +1898,14 @@ namespace OpenSim.Region.Framework.Scenes
return null;
}
- AssetBase asset = CreateAsset(itemBase.Name, itemBase.Description, (sbyte)itemBase.AssetType,
- Encoding.ASCII.GetBytes("default\n{\n state_entry()\n {\n llSay(0, \"Script running\");\n }\n}"),
- agentID);
+ AssetBase asset
+ = CreateAsset(
+ itemBase.Name,
+ itemBase.Description,
+ (sbyte)itemBase.AssetType,
+ Encoding.ASCII.GetBytes(scriptText),
+ agentID);
+
AssetService.Store(asset);
TaskInventoryItem taskItem = new TaskInventoryItem();
@@ -1801,8 +1946,11 @@ namespace OpenSim.Region.Framework.Scenes
/// Rez a script into a prim's inventory from another prim
///
///
- ///
- ///
+ ///
+ ///
+ ///
+ ///
+ ///
public void RezScriptFromPrim(UUID srcId, SceneObjectPart srcPart, UUID destId, int pin, int running, int start_param)
{
TaskInventoryItem srcTaskItem = srcPart.Inventory.GetInventoryItem(srcId);
@@ -1822,12 +1970,11 @@ namespace OpenSim.Region.Framework.Scenes
if (destPart == null)
{
m_log.ErrorFormat(
- "[PRIM INVENTORY]: " +
- "Could not find script for ID {0}",
- destId);
+ "[PRIM INVENTORY]: Could not find part {0} to insert script item {1} from {2} {3} in {4}",
+ destId, srcId, srcPart.Name, srcPart.UUID, Name);
return;
}
-
+
// Must own the object, and have modify rights
if (srcPart.OwnerID != destPart.OwnerID)
{
@@ -1835,12 +1982,14 @@ namespace OpenSim.Region.Framework.Scenes
if ((destPart.GroupID == UUID.Zero) || (destPart.GroupID != srcPart.GroupID) ||
((destPart.GroupMask & (uint)PermissionMask.Modify) == 0))
return;
- } else {
+ }
+ else
+ {
if ((destPart.OwnerMask & (uint)PermissionMask.Modify) == 0)
return;
}
- if (destPart.ScriptAccessPin != pin)
+ if (destPart.ScriptAccessPin == 0 || destPart.ScriptAccessPin != pin)
{
m_log.WarnFormat(
"[PRIM INVENTORY]: " +
@@ -1954,7 +2103,7 @@ namespace OpenSim.Region.Framework.Scenes
deleteGroups.Add(grp);
// If child prims have invalid perms, fix them
- grp.AdjustChildPrimPermissions();
+ grp.AdjustChildPrimPermissions(false);
if (remoteClient == null)
{
@@ -2004,7 +2153,10 @@ namespace OpenSim.Region.Framework.Scenes
{
// If we don't have permission, stop right here
if (!permissionToTakeCopy)
+ {
+ remoteClient.SendAlertMessage("You don't have permission to take the object");
return;
+ }
permissionToTake = true;
// Don't delete
@@ -2036,13 +2188,16 @@ namespace OpenSim.Region.Framework.Scenes
}
}
+ // OK, we're done with permissions. Let's check if any part of the code prevents the objects from being deleted
+ bool canDelete = EventManager.TriggerDeRezRequested(remoteClient, deleteGroups, action);
+
if (permissionToTake && (action != DeRezAction.Delete || this.m_useTrashOnDelete))
{
m_asyncSceneObjectDeleter.DeleteToInventory(
action, destinationID, deleteGroups, remoteClient,
- permissionToDelete);
+ permissionToDelete && canDelete);
}
- else if (permissionToDelete)
+ else if (permissionToDelete && canDelete)
{
foreach (SceneObjectGroup g in deleteGroups)
DeleteSceneObject(g, false);
@@ -2050,6 +2205,112 @@ namespace OpenSim.Region.Framework.Scenes
}
///
+ /// Returns the list of Scene Objects in an asset.
+ ///
+ ///
+ /// Returns one object if the asset is a regular object, and multiple objects for a coalesced object.
+ ///
+ /// Asset data
+ /// True if the object is an attachment.
+ /// The objects included in the asset
+ /// Relative positions of the objects
+ /// Bounding box of all the objects
+ /// Offset in the Z axis from the centre of the bounding box
+ /// to the centre of the root prim (relevant only when returning a single object)
+ ///
+ /// true if returning a single object or deserialization fails, false if returning the coalesced
+ /// list of objects
+ ///
+ public bool GetObjectsToRez(
+ byte[] assetData, bool isAttachment, out List objlist, out List veclist,
+ out Vector3 bbox, out float offsetHeight)
+ {
+ objlist = new List();
+ veclist = new List();
+ bbox = Vector3.Zero;
+ offsetHeight = 0;
+
+ string xmlData = ExternalRepresentationUtils.SanitizeXml(Utils.BytesToString(assetData));
+
+ try
+ {
+ using (XmlTextReader wrappedReader = new XmlTextReader(xmlData, XmlNodeType.Element, null))
+ {
+ using (XmlReader reader = XmlReader.Create(wrappedReader, new XmlReaderSettings() { IgnoreWhitespace = true, ConformanceLevel = ConformanceLevel.Fragment }))
+ {
+ reader.Read();
+ bool isSingleObject = reader.Name != "CoalescedObject";
+
+ if (isSingleObject || isAttachment)
+ {
+ SceneObjectGroup g;
+ try
+ {
+ g = SceneObjectSerializer.FromOriginalXmlFormat(reader);
+ }
+ catch (Exception e)
+ {
+ m_log.Error("[AGENT INVENTORY]: Deserialization of xml failed ", e);
+ Util.LogFailedXML("[AGENT INVENTORY]:", xmlData);
+ g = null;
+ }
+
+ if (g != null)
+ {
+ objlist.Add(g);
+ veclist.Add(Vector3.Zero);
+ bbox = g.GetAxisAlignedBoundingBox(out offsetHeight);
+ }
+
+ return true;
+ }
+ else
+ {
+ XmlDocument doc = new XmlDocument();
+ doc.LoadXml(xmlData);
+ XmlElement e = (XmlElement)doc.SelectSingleNode("/CoalescedObject");
+ XmlElement coll = (XmlElement)e;
+ float bx = Convert.ToSingle(coll.GetAttribute("x"));
+ float by = Convert.ToSingle(coll.GetAttribute("y"));
+ float bz = Convert.ToSingle(coll.GetAttribute("z"));
+ bbox = new Vector3(bx, by, bz);
+ offsetHeight = 0;
+
+ XmlNodeList groups = e.SelectNodes("SceneObjectGroup");
+ foreach (XmlNode n in groups)
+ {
+ SceneObjectGroup g = SceneObjectSerializer.FromOriginalXmlFormat(n.OuterXml);
+ if (g != null)
+ {
+ objlist.Add(g);
+
+ XmlElement el = (XmlElement)n;
+ string rawX = el.GetAttribute("offsetx");
+ string rawY = el.GetAttribute("offsety");
+ string rawZ = el.GetAttribute("offsetz");
+
+ float x = Convert.ToSingle(rawX);
+ float y = Convert.ToSingle(rawY);
+ float z = Convert.ToSingle(rawZ);
+ veclist.Add(new Vector3(x, y, z));
+ }
+ }
+
+ return false;
+ }
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ m_log.Error("[AGENT INVENTORY]: Deserialization of xml failed when looking for CoalescedObject tag ", e);
+ Util.LogFailedXML("[AGENT INVENTORY]:", xmlData);
+ }
+
+ return true;
+ }
+
+ ///
/// Event Handler Rez an object into a scene
/// Calls the non-void event handler
///
@@ -2124,19 +2385,25 @@ namespace OpenSim.Region.Framework.Scenes
/// will be used if it exists.
/// The velocity of the rezzed object.
///
- /// The SceneObjectGroup rezzed or null if rez was unsuccessful
- public virtual SceneObjectGroup RezObject(
+ /// The SceneObjectGroup(s) rezzed, or null if rez was unsuccessful
+ public virtual List RezObject(
SceneObjectPart sourcePart, TaskInventoryItem item, Vector3 pos, Quaternion? rot, Vector3 vel, int param)
{
if (null == item)
return null;
+
+ List objlist;
+ List veclist;
- SceneObjectGroup group = sourcePart.Inventory.GetRezReadySceneObject(item);
-
- if (null == group)
+ bool success = sourcePart.Inventory.GetRezReadySceneObjects(item, out objlist, out veclist);
+ if (!success)
return null;
-
- if (!Permissions.CanRezObject(group.PrimCount, item.OwnerID, pos))
+
+ int totalPrims = 0;
+ foreach (SceneObjectGroup group in objlist)
+ totalPrims += group.PrimCount;
+
+ if (!Permissions.CanRezObject(totalPrims, item.OwnerID, pos))
return null;
if (!Permissions.BypassPermissions())
@@ -2145,16 +2412,28 @@ namespace OpenSim.Region.Framework.Scenes
sourcePart.Inventory.RemoveInventoryItem(item.ItemID);
}
- group.FromPartID = sourcePart.UUID;
- AddNewSceneObject(group, true, pos, rot, vel);
-
- // We can only call this after adding the scene object, since the scene object references the scene
- // to find out if scripts should be activated at all.
- group.CreateScriptInstances(param, true, DefaultScriptEngine, 3);
-
- group.ScheduleGroupForFullUpdate();
-
- return group;
+ for (int i = 0; i < objlist.Count; i++)
+ {
+ SceneObjectGroup group = objlist[i];
+ Vector3 curpos = pos + veclist[i];
+
+ if (group.IsAttachment == false && group.RootPart.Shape.State != 0)
+ {
+ group.RootPart.AttachedPos = group.AbsolutePosition;
+ group.RootPart.Shape.LastAttachPoint = (byte)group.AttachmentPoint;
+ }
+
+ group.FromPartID = sourcePart.UUID;
+ AddNewSceneObject(group, true, curpos, rot, vel);
+
+ // We can only call this after adding the scene object, since the scene object references the scene
+ // to find out if scripts should be activated at all.
+ group.CreateScriptInstances(param, true, DefaultScriptEngine, 3);
+
+ group.ScheduleGroupForFullUpdate();
+ }
+
+ return objlist;
}
public virtual bool returnObjects(SceneObjectGroup[] returnobjects,
diff --git a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs
index df43271..8ebcd92 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs
@@ -31,7 +31,6 @@ using System.Threading;
using OpenMetaverse;
using OpenMetaverse.Packets;
using OpenSim.Framework;
-using OpenSim.Framework.Communications;
using OpenSim.Services.Interfaces;
namespace OpenSim.Region.Framework.Scenes
@@ -145,6 +144,21 @@ namespace OpenSim.Region.Framework.Scenes
}
///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public void SimChatToAgent(UUID targetID, byte[] message, int channel, Vector3 fromPos, string fromName, UUID fromID, bool fromAgent)
+ {
+ SimChat(message, ChatTypeEnum.Region, channel, fromPos, fromName, fromID, targetID, fromAgent, false);
+ }
+
+ ///
/// Invoked when the client requests a prim.
///
///
@@ -244,25 +258,20 @@ namespace OpenSim.Region.Framework.Scenes
if (part.ParentGroup.RootPart.LocalId != part.LocalId)
return;
- bool isAttachment = false;
-
// This is wrong, wrong, wrong. Selection should not be
// handled by group, but by prim. Legacy cruft.
// TODO: Make selection flagging per prim!
//
part.ParentGroup.IsSelected = false;
- if (part.ParentGroup.IsAttachment)
- isAttachment = true;
- else
- part.ParentGroup.ScheduleGroupForFullUpdate();
+ part.ParentGroup.ScheduleGroupForFullUpdate();
// If it's not an attachment, and we are allowed to move it,
// then we might have done so. If we moved across a parcel
// boundary, we will need to recount prims on the parcels.
// For attachments, that makes no sense.
//
- if (!isAttachment)
+ if (!part.ParentGroup.IsAttachment)
{
if (Permissions.CanEditObject(
part.UUID, remoteClient.AgentId)
@@ -390,6 +399,7 @@ namespace OpenSim.Region.Framework.Scenes
void ProcessViewerEffect(IClientAPI remoteClient, List args)
{
// TODO: don't create new blocks if recycling an old packet
+ bool discardableEffects = true;
ViewerEffectPacket.EffectBlock[] effectBlockArray = new ViewerEffectPacket.EffectBlock[args.Count];
for (int i = 0; i < args.Count; i++)
{
@@ -401,17 +411,34 @@ namespace OpenSim.Region.Framework.Scenes
effect.Type = args[i].Type;
effect.TypeData = args[i].TypeData;
effectBlockArray[i] = effect;
+
+ if ((EffectType)effect.Type != EffectType.LookAt && (EffectType)effect.Type != EffectType.Beam)
+ discardableEffects = false;
+
+ //m_log.DebugFormat("[YYY]: VE {0} {1} {2}", effect.AgentID, effect.Duration, (EffectType)effect.Type);
}
- ForEachClient(
- delegate(IClientAPI client)
+ ForEachScenePresence(sp =>
{
- if (client.AgentId != remoteClient.AgentId)
- client.SendViewerEffect(effectBlockArray);
- }
- );
+ if (sp.ControllingClient.AgentId != remoteClient.AgentId)
+ {
+ if (!discardableEffects ||
+ (discardableEffects && ShouldSendDiscardableEffect(remoteClient, sp)))
+ {
+ //m_log.DebugFormat("[YYY]: Sending to {0}", sp.UUID);
+ sp.ControllingClient.SendViewerEffect(effectBlockArray);
+ }
+ //else
+ // m_log.DebugFormat("[YYY]: Not sending to {0}", sp.UUID);
+ }
+ });
}
-
+
+ private bool ShouldSendDiscardableEffect(IClientAPI thisClient, ScenePresence other)
+ {
+ return Vector3.Distance(other.CameraPosition, thisClient.SceneAgent.AbsolutePosition) < 10;
+ }
+
///
/// Tell the client about the various child items and folders contained in the requested folder.
///
@@ -459,7 +486,16 @@ namespace OpenSim.Region.Framework.Scenes
void SendInventoryAsync(IClientAPI remoteClient, UUID folderID, UUID ownerID, bool fetchFolders, bool fetchItems, int sortOrder)
{
- SendInventoryUpdate(remoteClient, new InventoryFolderBase(folderID), fetchFolders, fetchItems);
+ try
+ {
+ SendInventoryUpdate(remoteClient, new InventoryFolderBase(folderID), fetchFolders, fetchItems);
+ }
+ catch (Exception e)
+ {
+ m_log.Error(
+ string.Format(
+ "[AGENT INVENTORY]: Error in SendInventoryAsync() for {0} with folder ID {1}. Exception ", e));
+ }
}
void SendInventoryComplete(IAsyncResult iar)
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
old mode 100644
new mode 100755
index f87d469..2fe6e22
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -6,7 +6,7 @@
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyrightD
+ * * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
@@ -39,18 +39,19 @@ using Nini.Config;
using OpenMetaverse;
using OpenMetaverse.Packets;
using OpenMetaverse.Imaging;
+using OpenMetaverse.StructuredData;
using OpenSim.Framework;
using OpenSim.Framework.Monitoring;
using OpenSim.Services.Interfaces;
-using OpenSim.Framework.Communications;
using OpenSim.Framework.Console;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes.Scripting;
using OpenSim.Region.Framework.Scenes.Serialization;
-using OpenSim.Region.Physics.Manager;
-using Timer=System.Timers.Timer;
+using OpenSim.Region.PhysicsModules.SharedBase;
+using Timer = System.Timers.Timer;
using TPFlags = OpenSim.Framework.Constants.TeleportFlags;
using GridRegion = OpenSim.Services.Interfaces.GridRegion;
+using PermissionMask = OpenSim.Framework.PermissionMask;
namespace OpenSim.Region.Framework.Scenes
{
@@ -60,6 +61,8 @@ namespace OpenSim.Region.Framework.Scenes
{
private const long DEFAULT_MIN_TIME_FOR_PERSISTENCE = 60L;
private const long DEFAULT_MAX_TIME_FOR_PERSISTENCE = 600L;
+
+ public const int m_defaultNumberFramesStored = 10;
public delegate void SynchronizeSceneHandler(Scene scene);
@@ -102,15 +105,37 @@ namespace OpenSim.Region.Framework.Scenes
///
/// If false then physical objects are disabled, though collisions will continue as normal.
///
- public bool PhysicsEnabled { get; set; }
+ public bool PhysicsEnabled
+ {
+ get
+ {
+ return m_physicsEnabled;
+ }
+
+ set
+ {
+ m_physicsEnabled = value;
+
+ if (PhysicsScene != null)
+ {
+ IPhysicsParameters physScene = PhysicsScene as IPhysicsParameters;
+
+ if (physScene != null)
+ physScene.SetPhysicsParameter(
+ "Active", m_physicsEnabled.ToString(), PhysParameterEntry.APPLY_TO_NONE);
+ }
+ }
+ }
+
+ private bool m_physicsEnabled;
///
/// If false then scripts are not enabled on the smiulator
///
- public bool ScriptsEnabled
- {
+ public bool ScriptsEnabled
+ {
get { return m_scripts_enabled; }
- set
+ set
{
if (m_scripts_enabled != value)
{
@@ -128,7 +153,7 @@ namespace OpenSim.Region.Framework.Scenes
else
{
m_log.Info("Starting all Scripts in Scene");
-
+
EntityBase[] entities = Entities.GetEntities();
foreach (EntityBase ent in entities)
{
@@ -150,7 +175,7 @@ namespace OpenSim.Region.Framework.Scenes
public SynchronizeSceneHandler SynchronizeScene;
///
- /// Used to prevent simultaneous calls to RemoveClient() for the same agent from interfering with each other.
+ /// Used to prevent simultaneous calls to code that adds and removes agents.
///
private object m_removeClientLock = new object();
@@ -159,11 +184,6 @@ namespace OpenSim.Region.Framework.Scenes
///
public SimStatsReporter StatsReporter { get; private set; }
- public List NorthBorders = new List();
- public List EastBorders = new List();
- public List SouthBorders = new List();
- public List WestBorders = new List();
-
///
/// Controls whether physics can be applied to prims. Even if false, prims still have entries in a
/// PhysicsScene in order to perform collision detection
@@ -196,7 +216,7 @@ namespace OpenSim.Region.Framework.Scenes
///
/// Maximum value of the size of a physical prim in each axis
///
- public float m_maxPhys = 10;
+ public float m_maxPhys = 64;
///
/// Max prims an object will hold
@@ -205,7 +225,13 @@ namespace OpenSim.Region.Framework.Scenes
public bool m_clampPrimSize;
public bool m_trustBinaries;
- public bool m_allowScriptCrossings;
+ public bool m_allowScriptCrossings = true;
+
+ ///
+ /// Can avatars cross from and to this region?
+ ///
+ public bool AllowAvatarCrossing { get; set; }
+
public bool m_useFlySlow;
public bool m_useTrashOnDelete = true;
@@ -214,21 +240,58 @@ namespace OpenSim.Region.Framework.Scenes
///
public bool SendPeriodicAppearanceUpdates { get; set; }
+ ///
+ /// How much a root agent has to change position before updates are sent to viewers.
+ ///
+ public float RootPositionUpdateTolerance { get; set; }
+
+ ///
+ /// How much a root agent has to rotate before updates are sent to viewers.
+ ///
+ public float RootRotationUpdateTolerance { get; set; }
+
+ ///
+ /// How much a root agent has to change velocity before updates are sent to viewers.
+ ///
+ public float RootVelocityUpdateTolerance { get; set; }
+
+ ///
+ /// If greater than 1, we only send terse updates to other root agents on every n updates.
+ ///
+ public int RootTerseUpdatePeriod { get; set; }
+
+ ///
+ /// If greater than 1, we only send terse updates to child agents on every n updates.
+ ///
+ public int ChildTerseUpdatePeriod { get; set; }
+
protected float m_defaultDrawDistance = 255.0f;
- public float DefaultDrawDistance
+ public float DefaultDrawDistance
{
- get { return m_defaultDrawDistance; }
+ // get { return m_defaultDrawDistance; }
+ get
+ {
+ if (RegionInfo != null)
+ {
+ float largestDimension = Math.Max(RegionInfo.RegionSizeX, RegionInfo.RegionSizeY);
+ m_defaultDrawDistance = Math.Max(m_defaultDrawDistance, largestDimension);
+
+ }
+ return m_defaultDrawDistance;
+ }
}
private List m_AllowedViewers = new List();
private List m_BannedViewers = new List();
-
+
// TODO: need to figure out how allow client agents but deny
// root agents when ACL denies access to root agent
public bool m_strictAccessControl = true;
public int MaxUndoCount { get; set; }
+ public bool SeeIntoRegion { get; set; }
+
// Using this for RegionReady module to prevent LoginsDisabled from changing under our feet;
public bool LoginLock = false;
@@ -262,6 +325,7 @@ namespace OpenSim.Region.Framework.Scenes
protected IUserAccountService m_UserAccountService;
protected IAvatarService m_AvatarService;
protected IGridUserService m_GridUserService;
+ protected IAgentPreferencesService m_AgentPreferencesService;
protected IXMLRPC m_xmlrpcModule;
protected IWorldComm m_worldCommModule;
@@ -275,6 +339,17 @@ namespace OpenSim.Region.Framework.Scenes
private Dictionary m_extraSettings;
///
+ /// If true then the next time the scene loop is activated, updates will be performed by firing of a timer
+ /// rather than on a single thread that sleeps.
+ ///
+ public bool UpdateOnTimer { get; set; }
+
+ ///
+ /// Only used if we are updating scene on a timer rather than sleeping a thread.
+ ///
+ private Timer m_sceneUpdateTimer;
+
+ ///
/// Current scene frame number
///
public uint Frame
@@ -289,30 +364,59 @@ namespace OpenSim.Region.Framework.Scenes
public uint MaintenanceRun { get; private set; }
///
- /// The minimum length of time in seconds that will be taken for a scene frame. If the frame takes less time then we
+ /// The minimum length of time in milliseconds that will be taken for a scene frame. If the frame takes less time then we
/// will sleep for the remaining period.
///
///
/// One can tweak this number to experiment. One current effect of reducing it is to make avatar animations
/// occur too quickly (viewer 1) or with even more slide (viewer 2).
///
- public float MinFrameTime { get; private set; }
+ public int MinFrameTicks
+ {
+ get { return m_minFrameTicks; }
+ private set
+ {
+ m_minFrameTicks = value;
+ MinFrameSeconds = (float)m_minFrameTicks / 1000;
+ }
+ }
+ private int m_minFrameTicks;
+
+ public int FrameTimeWarnPercent { get; private set; }
+ public int FrameTimeCritPercent { get; private set; }
+
+ // Normalize the frame related stats to nominal 55fps for viewer and scripts option
+ // see SimStatsReporter.cs
+ public bool Normalized55FPS { get; private set; }
+
+ ///
+ /// The minimum length of time in seconds that will be taken for a scene frame.
+ ///
+ ///
+ /// Always derived from MinFrameTicks.
+ ///
+ public float MinFrameSeconds { get; private set; }
///
- /// The minimum length of time in seconds that will be taken for a maintenance run.
+ /// The minimum length of time in milliseconds that will be taken for a scene frame. If the frame takes less time then we
+ /// will sleep for the remaining period.
///
- public float MinMaintenanceTime { get; private set; }
+ ///
+ /// One can tweak this number to experiment. One current effect of reducing it is to make avatar animations
+ /// occur too quickly (viewer 1) or with even more slide (viewer 2).
+ ///
+ public int MinMaintenanceTicks { get; set; }
private int m_update_physics = 1;
private int m_update_entitymovement = 1;
private int m_update_objects = 1;
- private int m_update_temp_cleaning = 1000;
private int m_update_presences = 1; // Update scene presence movements
private int m_update_events = 1;
private int m_update_backup = 200;
private int m_update_terrain = 50;
-// private int m_update_land = 1;
+ // private int m_update_land = 1;
private int m_update_coarse_locations = 50;
+ private int m_update_temp_cleaning = 180;
private int agentMS;
private int frameMS;
@@ -326,6 +430,17 @@ namespace OpenSim.Region.Framework.Scenes
private int landMS;
private int spareMS;
+ // A temporary configuration flag to enable using FireAndForget to process
+ // collisions from the physics engine. There is a problem with collisions
+ // stopping sometimes and MB's suspicion is some race condition passing
+ // collisions from the physics engine callback to the script engine.
+ // This causes the collision events to be passed with a FireAndForget
+ // call which should eliminate that linkage. Testers can turn this on
+ // and see if collisions stop. If they don't, the problem is somewhere else.
+ // This feature defaults to 'off' so, by default, the simulator operation
+ // is not changed.
+ public bool ShouldUseFireAndForgetForCollisions = false;
+
///
/// Tick at which the last frame was processed.
///
@@ -337,16 +452,28 @@ namespace OpenSim.Region.Framework.Scenes
private int m_lastMaintenanceTick;
///
+ /// Total script execution time (in Stopwatch Ticks) since the last frame
+ ///
+ private long m_scriptExecutionTime = 0;
+
+ ///
/// Signals whether temporary objects are currently being cleaned up. Needed because this is launched
/// asynchronously from the update loop.
///
private bool m_cleaningTemps = false;
-// private Object m_heartbeatLock = new Object();
+ ///
+ /// Used to control main scene thread looping time when not updating via timer.
+ ///
+ private ManualResetEvent m_updateWaitEvent = new ManualResetEvent(false);
+
+ ///
+ /// Used to control maintenance thread runs.
+ ///
+ private ManualResetEvent m_maintenanceWaitEvent = new ManualResetEvent(false);
// TODO: Possibly stop other classes being able to manipulate this directly.
private SceneGraph m_sceneGraph;
- private volatile int m_bordersLocked;
private readonly Timer m_restartTimer = new Timer(15000); // Wait before firing
private volatile bool m_backingup;
private Dictionary m_returns = new Dictionary();
@@ -354,6 +481,12 @@ namespace OpenSim.Region.Framework.Scenes
private string m_defaultScriptEngine;
+ private int m_unixStartTime;
+ public int UnixStartTime
+ {
+ get { return m_unixStartTime; }
+ }
+
///
/// Tick at which the last login occurred.
///
@@ -377,7 +510,8 @@ namespace OpenSim.Region.Framework.Scenes
/// Is the scene active?
///
///
- /// If false, maintenance and update loops are not being run. Updates can still be triggered manually if
+ /// If false, maintenance and update loops are not being run, though after setting to false update may still
+ /// be active for a period (and IsRunning will still be true). Updates can still be triggered manually if
/// the scene is not active.
///
public bool Active
@@ -388,24 +522,23 @@ namespace OpenSim.Region.Framework.Scenes
if (value)
{
if (!m_active)
- Start();
+ Start(false);
}
else
{
+ // This appears assymetric with Start() above but is not - setting m_active = false stops the loops
+ // XXX: Possibly this should be in an explicit Stop() method for symmetry.
m_active = false;
}
}
}
private volatile bool m_active;
-// private int m_lastUpdate;
-// private bool m_firstHeartbeat = true;
-
- private UpdatePrioritizationSchemes m_priorityScheme = UpdatePrioritizationSchemes.Time;
- private bool m_reprioritizationEnabled = true;
- private double m_reprioritizationInterval = 5000.0;
- private double m_rootReprioritizationDistance = 10.0;
- private double m_childReprioritizationDistance = 20.0;
+ ///
+ /// If true then updates are running. This may be true for a short period after a scene is de-activated.
+ ///
+ public bool IsRunning { get { return m_isRunning; } }
+ private volatile bool m_isRunning;
private Timer m_mapGenerationTimer = new Timer();
private bool m_generateMaptiles;
@@ -421,23 +554,18 @@ namespace OpenSim.Region.Framework.Scenes
set { m_splitRegionID = value; }
}
- public bool BordersLocked
- {
- get { return m_bordersLocked == 1; }
- set
- {
- if (value == true)
- m_bordersLocked = 1;
- else
- m_bordersLocked = 0;
- }
- }
-
public new float TimeDilation
{
get { return m_sceneGraph.PhysicsScene.TimeDilation; }
}
+ public void setThreadCount(int inUseThreads)
+ {
+ // Just pass the thread count information on its way as the Scene
+ // does not require the value for anything at this time
+ StatsReporter.SetThreadCount(inUseThreads);
+ }
+
public SceneCommunicationService SceneGridService
{
get { return m_sceneGridService; }
@@ -496,7 +624,7 @@ namespace OpenSim.Region.Framework.Scenes
return m_AssetService;
}
}
-
+
public IAuthorizationService AuthorizationService
{
get
@@ -624,6 +752,16 @@ namespace OpenSim.Region.Framework.Scenes
}
}
+ public IAgentPreferencesService AgentPreferencesService
+ {
+ get
+ {
+ if (m_AgentPreferencesService == null)
+ m_AgentPreferencesService = RequestModuleInterface();
+ return m_AgentPreferencesService;
+ }
+ }
+
public IAttachmentsModule AttachmentsModule { get; set; }
public IEntityTransferModule EntityTransferModule { get; private set; }
public IAgentAssetTransactions AgentTransactionsModule { get; private set; }
@@ -633,7 +771,7 @@ namespace OpenSim.Region.Framework.Scenes
{
get { return m_AvatarFactory; }
}
-
+
public ICapabilitiesModule CapsModule
{
get { return m_capsModule; }
@@ -650,11 +788,11 @@ namespace OpenSim.Region.Framework.Scenes
public int MonitorLandTime { get { return landMS; } }
public int MonitorLastFrameTick { get { return m_lastFrameTick; } }
- public UpdatePrioritizationSchemes UpdatePrioritizationScheme { get { return m_priorityScheme; } }
- public bool IsReprioritizationEnabled { get { return m_reprioritizationEnabled; } }
- public double ReprioritizationInterval { get { return m_reprioritizationInterval; } }
- public double RootReprioritizationDistance { get { return m_rootReprioritizationDistance; } }
- public double ChildReprioritizationDistance { get { return m_childReprioritizationDistance; } }
+ public UpdatePrioritizationSchemes UpdatePrioritizationScheme { get; set; }
+ public bool IsReprioritizationEnabled { get; set; }
+ public double ReprioritizationInterval { get; set; }
+ public double RootReprioritizationDistance { get; set; }
+ public double ChildReprioritizationDistance { get; set; }
public AgentCircuitManager AuthenticateHandler
{
@@ -699,43 +837,46 @@ namespace OpenSim.Region.Framework.Scenes
get { return m_sceneGraph.Entities; }
}
-
+
// used in sequence see: SpawnPoint()
private int m_SpawnPoint;
// can be closest/random/sequence
public string SpawnPointRouting
{
- get; private set;
+ get;
+ private set;
}
// allow landmarks to pass
public bool TelehubAllowLandmarks
{
- get; private set;
+ get;
+ private set;
}
#endregion Properties
#region Constructors
- public Scene(RegionInfo regInfo, AgentCircuitManager authen,
- SceneCommunicationService sceneGridService,
+ public Scene(RegionInfo regInfo, AgentCircuitManager authen,
ISimulationDataService simDataService, IEstateDataService estateDataService,
- bool dumpAssetsToFile,
IConfigSource config, string simulatorVersion)
: this(regInfo)
{
m_config = config;
- MinFrameTime = 0.089f;
- MinMaintenanceTime = 1;
+ MinFrameTicks = 89;
+ FrameTimeWarnPercent = 60;
+ FrameTimeCritPercent = 40;
+ Normalized55FPS = true;
+ MinMaintenanceTicks = 1000;
+ SeeIntoRegion = true;
Random random = new Random();
m_lastAllocatedLocalId = (uint)(random.NextDouble() * (double)(uint.MaxValue / 2)) + (uint)(uint.MaxValue / 4);
m_authenticateHandler = authen;
- m_sceneGridService = sceneGridService;
+ m_sceneGridService = new SceneCommunicationService();
m_SimulationDataService = simDataService;
m_EstateDataService = estateDataService;
- m_regionHandle = RegionInfo.RegionHandle;
m_asyncSceneObjectDeleter = new AsyncSceneObjectGroupDeleter(this);
m_asyncSceneObjectDeleter.Enabled = true;
@@ -794,25 +935,8 @@ namespace OpenSim.Region.Framework.Scenes
EventManager.OnLandObjectRemoved +=
new EventManager.LandObjectRemoved(simDataService.RemoveLandObject);
- m_sceneGraph = new SceneGraph(this);
-
- // If the scene graph has an Unrecoverable error, restart this sim.
- // Currently the only thing that causes it to happen is two kinds of specific
- // Physics based crashes.
- //
- // Out of memory
- // Operating system has killed the plugin
- m_sceneGraph.UnRecoverableError
- += () =>
- {
- m_log.ErrorFormat("[SCENE]: Restarting region {0} due to unrecoverable physics crash", Name);
- RestartNow();
- };
-
RegisterDefaultSceneEvents();
- DumpAssetsToFile = dumpAssetsToFile;
-
// XXX: Don't set the public property since we don't want to activate here. This needs to be handled
// better in the future.
m_scripts_enabled = !RegionInfo.RegionSettings.DisableScripts;
@@ -835,10 +959,12 @@ namespace OpenSim.Region.Framework.Scenes
UseBackup = startupConfig.GetBoolean("UseSceneBackup", UseBackup);
if (!UseBackup)
m_log.InfoFormat("[SCENE]: Backup has been disabled for {0}", RegionInfo.RegionName);
-
+
//Animation states
m_useFlySlow = startupConfig.GetBoolean("enableflyslow", false);
+ SeeIntoRegion = startupConfig.GetBoolean("see_into_region", SeeIntoRegion);
+
MaxUndoCount = startupConfig.GetInt("MaxPrimUndos", 20);
PhysicalPrims = startupConfig.GetBoolean("physical_prim", PhysicalPrims);
@@ -887,10 +1013,10 @@ namespace OpenSim.Region.Framework.Scenes
m_trustBinaries = startupConfig.GetBoolean("TrustBinaries", m_trustBinaries);
m_allowScriptCrossings = startupConfig.GetBoolean("AllowScriptCrossing", m_allowScriptCrossings);
m_dontPersistBefore =
- startupConfig.GetLong("MinimumTimeBeforePersistenceConsidered", DEFAULT_MIN_TIME_FOR_PERSISTENCE);
+ startupConfig.GetLong("MinimumTimeBeforePersistenceConsidered", DEFAULT_MIN_TIME_FOR_PERSISTENCE);
m_dontPersistBefore *= 10000000;
m_persistAfter =
- startupConfig.GetLong("MaximumTimeBeforePersistenceConsidered", DEFAULT_MAX_TIME_FOR_PERSISTENCE);
+ startupConfig.GetLong("MaximumTimeBeforePersistenceConsidered", DEFAULT_MAX_TIME_FOR_PERSISTENCE);
m_persistAfter *= 10000000;
m_defaultScriptEngine = startupConfig.GetString("DefaultScriptEngine", "XEngine");
@@ -900,10 +1026,15 @@ namespace OpenSim.Region.Framework.Scenes
m_strictAccessControl = startupConfig.GetBoolean("StrictAccessControl", m_strictAccessControl);
- m_generateMaptiles = startupConfig.GetBoolean("GenerateMaptiles", true);
+ string[] possibleMapConfigSections = new string[] { "Map", "Startup" };
+
+ m_generateMaptiles
+ = Util.GetConfigVarFromSections(config, "GenerateMaptiles", possibleMapConfigSections, true);
+
if (m_generateMaptiles)
{
- int maptileRefresh = startupConfig.GetInt("MaptileRefresh", 0);
+ int maptileRefresh = Util.GetConfigVarFromSections(config, "MaptileRefresh", possibleMapConfigSections, 0);
+ m_log.InfoFormat("[SCENE]: Region {0}, WORLD MAP refresh time set to {1} seconds", RegionInfo.RegionName, maptileRefresh);
if (maptileRefresh != 0)
{
m_mapGenerationTimer.Interval = maptileRefresh * 1000;
@@ -914,16 +1045,29 @@ namespace OpenSim.Region.Framework.Scenes
}
else
{
- string tile = startupConfig.GetString("MaptileStaticUUID", UUID.Zero.ToString());
+ string tile
+ = Util.GetConfigVarFromSections(
+ config, "MaptileStaticUUID", possibleMapConfigSections, UUID.Zero.ToString());
+
UUID tileID;
- if (UUID.TryParse(tile, out tileID))
+ if (tile != UUID.Zero.ToString() && UUID.TryParse(tile, out tileID))
{
RegionInfo.RegionSettings.TerrainImageID = tileID;
}
+ else
+ {
+ RegionInfo.RegionSettings.TerrainImageID = RegionInfo.MaptileStaticUUID;
+ m_log.InfoFormat("[SCENE]: Region {0}, maptile set to {1}", RegionInfo.RegionName, RegionInfo.MaptileStaticUUID.ToString());
+ }
}
- string grant = startupConfig.GetString("AllowedClients", String.Empty);
+ string[] possibleAccessControlConfigSections = new string[] { "Startup", "AccessControl"};
+
+ string grant
+ = Util.GetConfigVarFromSections(
+ config, "AllowedClients", possibleAccessControlConfigSections, string.Empty);
+
if (grant.Length > 0)
{
foreach (string viewer in grant.Split('|'))
@@ -932,7 +1076,14 @@ namespace OpenSim.Region.Framework.Scenes
}
}
- grant = startupConfig.GetString("BannedClients", String.Empty);
+ grant
+ = Util.GetConfigVarFromSections(
+ config, "DeniedClients", possibleAccessControlConfigSections, String.Empty);
+ // Deal with the mess of someone having used a different word at some point
+ if (grant == String.Empty)
+ grant = Util.GetConfigVarFromSections(
+ config, "BannedClients", possibleAccessControlConfigSections, String.Empty);
+
if (grant.Length > 0)
{
foreach (string viewer in grant.Split('|'))
@@ -941,21 +1092,32 @@ namespace OpenSim.Region.Framework.Scenes
}
}
- MinFrameTime = startupConfig.GetFloat( "MinFrameTime", MinFrameTime);
- m_update_backup = startupConfig.GetInt( "UpdateStorageEveryNFrames", m_update_backup);
- m_update_coarse_locations = startupConfig.GetInt( "UpdateCoarseLocationsEveryNFrames", m_update_coarse_locations);
- m_update_entitymovement = startupConfig.GetInt( "UpdateEntityMovementEveryNFrames", m_update_entitymovement);
- m_update_events = startupConfig.GetInt( "UpdateEventsEveryNFrames", m_update_events);
- m_update_objects = startupConfig.GetInt( "UpdateObjectsEveryNFrames", m_update_objects);
- m_update_physics = startupConfig.GetInt( "UpdatePhysicsEveryNFrames", m_update_physics);
- m_update_presences = startupConfig.GetInt( "UpdateAgentsEveryNFrames", m_update_presences);
- m_update_terrain = startupConfig.GetInt( "UpdateTerrainEveryNFrames", m_update_terrain);
- m_update_temp_cleaning = startupConfig.GetInt( "UpdateTempCleaningEveryNFrames", m_update_temp_cleaning);
+ if (startupConfig.Contains("MinFrameTime"))
+ MinFrameTicks = (int)(startupConfig.GetFloat("MinFrameTime") * 1000);
+ FrameTimeWarnPercent = startupConfig.GetInt( "FrameTimeWarnPercent", FrameTimeWarnPercent);
+ FrameTimeCritPercent = startupConfig.GetInt( "FrameTimeCritPercent", FrameTimeCritPercent);
+ Normalized55FPS = startupConfig.GetBoolean( "Normalized55FPS", Normalized55FPS);
+
+ m_update_backup = startupConfig.GetInt("UpdateStorageEveryNFrames", m_update_backup);
+ m_update_coarse_locations = startupConfig.GetInt("UpdateCoarseLocationsEveryNFrames", m_update_coarse_locations);
+ m_update_entitymovement = startupConfig.GetInt("UpdateEntityMovementEveryNFrames", m_update_entitymovement);
+ m_update_events = startupConfig.GetInt("UpdateEventsEveryNFrames", m_update_events);
+ m_update_objects = startupConfig.GetInt("UpdateObjectsEveryNFrames", m_update_objects);
+ m_update_physics = startupConfig.GetInt("UpdatePhysicsEveryNFrames", m_update_physics);
+ m_update_presences = startupConfig.GetInt("UpdateAgentsEveryNFrames", m_update_presences);
+ m_update_terrain = startupConfig.GetInt("UpdateTerrainEveryNFrames", m_update_terrain);
+ m_update_temp_cleaning = startupConfig.GetInt("UpdateTempCleaningEveryNSeconds", m_update_temp_cleaning);
+
+ if (startupConfig.Contains("ShouldUseFireAndForgetForCollisions"))
+ {
+ ShouldUseFireAndForgetForCollisions = startupConfig.GetBoolean("ShouldUseFireAndForgetForCollisions", false);
+ }
}
+
// FIXME: Ultimately this should be in a module.
- SendPeriodicAppearanceUpdates = true;
-
+ SendPeriodicAppearanceUpdates = false;
+
IConfig appearanceConfig = m_config.Configs["Appearance"];
if (appearanceConfig != null)
{
@@ -965,6 +1127,12 @@ namespace OpenSim.Region.Framework.Scenes
#endregion Region Config
+ IConfig entityTransferConfig = m_config.Configs["EntityTransfer"];
+ if (entityTransferConfig != null)
+ {
+ AllowAvatarCrossing = entityTransferConfig.GetBoolean("AllowAvatarCrossing", AllowAvatarCrossing);
+ }
+
#region Interest Management
IConfig interestConfig = m_config.Configs["InterestManagement"];
@@ -974,59 +1142,109 @@ namespace OpenSim.Region.Framework.Scenes
try
{
- m_priorityScheme = (UpdatePrioritizationSchemes)Enum.Parse(typeof(UpdatePrioritizationSchemes), update_prioritization_scheme, true);
+ UpdatePrioritizationScheme = (UpdatePrioritizationSchemes)Enum.Parse(typeof(UpdatePrioritizationSchemes), update_prioritization_scheme, true);
}
catch (Exception)
{
m_log.Warn("[PRIORITIZER]: UpdatePrioritizationScheme was not recognized, setting to default prioritizer Time");
- m_priorityScheme = UpdatePrioritizationSchemes.Time;
+ UpdatePrioritizationScheme = UpdatePrioritizationSchemes.Time;
}
- m_reprioritizationEnabled = interestConfig.GetBoolean("ReprioritizationEnabled", true);
- m_reprioritizationInterval = interestConfig.GetDouble("ReprioritizationInterval", 5000.0);
- m_rootReprioritizationDistance = interestConfig.GetDouble("RootReprioritizationDistance", 10.0);
- m_childReprioritizationDistance = interestConfig.GetDouble("ChildReprioritizationDistance", 20.0);
+ IsReprioritizationEnabled
+ = interestConfig.GetBoolean("ReprioritizationEnabled", IsReprioritizationEnabled);
+ ReprioritizationInterval
+ = interestConfig.GetDouble("ReprioritizationInterval", ReprioritizationInterval);
+ RootReprioritizationDistance
+ = interestConfig.GetDouble("RootReprioritizationDistance", RootReprioritizationDistance);
+ ChildReprioritizationDistance
+ = interestConfig.GetDouble("ChildReprioritizationDistance", ChildReprioritizationDistance);
+
+ RootTerseUpdatePeriod = interestConfig.GetInt("RootTerseUpdatePeriod", RootTerseUpdatePeriod);
+ ChildTerseUpdatePeriod = interestConfig.GetInt("ChildTerseUpdatePeriod", ChildTerseUpdatePeriod);
+
+ RootPositionUpdateTolerance
+ = interestConfig.GetFloat("RootPositionUpdateTolerance", RootPositionUpdateTolerance);
+ RootRotationUpdateTolerance
+ = interestConfig.GetFloat("RootRotationUpdateTolerance", RootRotationUpdateTolerance);
+ RootVelocityUpdateTolerance
+ = interestConfig.GetFloat("RootVelocityUpdateTolerance", RootVelocityUpdateTolerance);
}
- m_log.DebugFormat("[SCENE]: Using the {0} prioritization scheme", m_priorityScheme);
+ m_log.DebugFormat("[SCENE]: Using the {0} prioritization scheme", UpdatePrioritizationScheme);
#endregion Interest Management
- StatsReporter = new SimStatsReporter(this);
+ // The timer used by the Stopwatch class depends on the system hardware and operating system; inform
+ // if the timer is based on a high-resolution performance counter or based on the system timer;
+ // the performance counter will provide a more precise time than the system timer
+ if (Stopwatch.IsHighResolution)
+ m_log.InfoFormat("[SCENE]: Using high-resolution performance counter for statistics.");
+ else
+ m_log.InfoFormat("[SCENE]: Using system timer for statistics.");
+
+ // Acquire the statistics section of the OpenSim.ini file located
+ // in the bin directory
+ IConfig statisticsConfig = m_config.Configs["Statistics"];
+
+ // Confirm that the statistics section existed in the configuration
+ // file
+ if (statisticsConfig != null)
+ {
+ // Create the StatsReporter using the number of frames to store
+ // for the frame time statistics, or 10 frames if the config
+ // file doesn't contain a value
+ StatsReporter = new SimStatsReporter(this,
+ statisticsConfig.GetInt("NumberOfFrames",
+ m_defaultNumberFramesStored));
+ }
+ else
+ {
+ // Create a StatsReporter with the current scene and a default
+ // 10 frames stored for the frame time statistics
+ StatsReporter = new SimStatsReporter(this);
+ }
+
StatsReporter.OnSendStatsResult += SendSimStatsPackets;
StatsReporter.OnStatsIncorrect += m_sceneGraph.RecalculateStats;
+
}
- public Scene(RegionInfo regInfo) : base(regInfo)
+ public Scene(RegionInfo regInfo)
+ : base(regInfo)
{
+ m_sceneGraph = new SceneGraph(this);
+
+ // If the scene graph has an Unrecoverable error, restart this sim.
+ // Currently the only thing that causes it to happen is two kinds of specific
+ // Physics based crashes.
+ //
+ // Out of memory
+ // Operating system has killed the plugin
+ m_sceneGraph.UnRecoverableError
+ += () =>
+ {
+ m_log.ErrorFormat("[SCENE]: Restarting region {0} due to unrecoverable physics crash", Name);
+ RestartNow();
+ };
+
PhysicalPrims = true;
CollidablePrims = true;
PhysicsEnabled = true;
+ AllowAvatarCrossing = true;
+
PeriodicBackup = true;
UseBackup = true;
- BordersLocked = true;
- Border northBorder = new Border();
- northBorder.BorderLine = new Vector3(float.MinValue, float.MaxValue, (int)Constants.RegionSize); //<---
- northBorder.CrossDirection = Cardinals.N;
- NorthBorders.Add(northBorder);
-
- Border southBorder = new Border();
- southBorder.BorderLine = new Vector3(float.MinValue, float.MaxValue,0); //--->
- southBorder.CrossDirection = Cardinals.S;
- SouthBorders.Add(southBorder);
+ IsReprioritizationEnabled = true;
+ UpdatePrioritizationScheme = UpdatePrioritizationSchemes.Time;
+ ReprioritizationInterval = 5000;
- Border eastBorder = new Border();
- eastBorder.BorderLine = new Vector3(float.MinValue, float.MaxValue, (int)Constants.RegionSize); //<---
- eastBorder.CrossDirection = Cardinals.E;
- EastBorders.Add(eastBorder);
-
- Border westBorder = new Border();
- westBorder.BorderLine = new Vector3(float.MinValue, float.MaxValue,0); //--->
- westBorder.CrossDirection = Cardinals.W;
- WestBorders.Add(westBorder);
- BordersLocked = false;
+ RootRotationUpdateTolerance = 0.1f;
+ RootVelocityUpdateTolerance = 0.001f;
+ RootPositionUpdateTolerance = 0.05f;
+ RootReprioritizationDistance = 10.0;
+ ChildReprioritizationDistance = 20.0;
m_eventManager = new EventManager();
@@ -1046,13 +1264,44 @@ namespace OpenSim.Region.Framework.Scenes
get { return m_sceneGraph; }
}
- protected virtual void RegisterDefaultSceneEvents()
+ ///
+ /// Called by the module loader when all modules are loaded, after each module's
+ /// RegionLoaded hook is called. This is the earliest time where RequestModuleInterface
+ /// may be used.
+ ///
+ public void AllModulesLoaded()
{
IDialogModule dm = RequestModuleInterface();
if (dm != null)
m_eventManager.OnPermissionError += dm.SendAlertToUser;
+ ISimulatorFeaturesModule fm = RequestModuleInterface();
+ if (fm != null)
+ {
+ OSD openSimExtras;
+ OSDMap openSimExtrasMap;
+
+ if (!fm.TryGetFeature("OpenSimExtras", out openSimExtras))
+ openSimExtras = new OSDMap();
+
+ float FrameTime = MinFrameTicks / 1000.0f;
+ float statisticsFPSfactor = 1.0f;
+ if(Normalized55FPS)
+ statisticsFPSfactor = 55.0f * FrameTime;
+
+ openSimExtrasMap = (OSDMap)openSimExtras;
+ openSimExtrasMap["SimulatorFPS"] = OSD.FromReal(1.0f / FrameTime);
+ openSimExtrasMap["SimulatorFPSFactor"] = OSD.FromReal(statisticsFPSfactor);
+ openSimExtrasMap["SimulatorFPSWarnPercent"] = OSD.FromInteger(FrameTimeWarnPercent);
+ openSimExtrasMap["SimulatorFPSCritPercent"] = OSD.FromInteger(FrameTimeCritPercent);
+
+ fm.AddFeature("OpenSimExtras", openSimExtrasMap);
+ }
+ }
+
+ protected virtual void RegisterDefaultSceneEvents()
+ {
m_eventManager.OnSignificantClientMovement += HandleOnSignificantClientMovement;
}
@@ -1074,17 +1323,22 @@ namespace OpenSim.Region.Framework.Scenes
/// True after all operations complete, throws exceptions otherwise.
public override void OtherRegionUp(GridRegion otherRegion)
{
- uint xcell = (uint)((int)otherRegion.RegionLocX / (int)Constants.RegionSize);
- uint ycell = (uint)((int)otherRegion.RegionLocY / (int)Constants.RegionSize);
- //m_log.InfoFormat("[SCENE]: (on region {0}): Region {1} up in coords {2}-{3}",
- // RegionInfo.RegionName, otherRegion.RegionName, xcell, ycell);
-
if (RegionInfo.RegionHandle != otherRegion.RegionHandle)
{
- // If these are cast to INT because long + negative values + abs returns invalid data
- int resultX = Math.Abs((int)xcell - (int)RegionInfo.RegionLocX);
- int resultY = Math.Abs((int)ycell - (int)RegionInfo.RegionLocY);
- if (resultX <= 1 && resultY <= 1)
+ //// If these are cast to INT because long + negative values + abs returns invalid data
+ //int resultX = Math.Abs((int)xcell - (int)RegionInfo.RegionLocX);
+ //int resultY = Math.Abs((int)ycell - (int)RegionInfo.RegionLocY);
+ //if (resultX <= 1 && resultY <= 1)
+ float dist = (float)Math.Max(DefaultDrawDistance,
+ (float)Math.Max(RegionInfo.RegionSizeX, RegionInfo.RegionSizeY));
+ uint newRegionX, newRegionY, thisRegionX, thisRegionY;
+ Util.RegionHandleToRegionLoc(otherRegion.RegionHandle, out newRegionX, out newRegionY);
+ Util.RegionHandleToRegionLoc(RegionInfo.RegionHandle, out thisRegionX, out thisRegionY);
+
+ //m_log.InfoFormat("[SCENE]: (on region {0}): Region {1} up in coords {2}-{3}",
+ // RegionInfo.RegionName, otherRegion.RegionName, newRegionX, newRegionY);
+
+ if (!Util.IsOutsideView(dist, thisRegionX, newRegionX, thisRegionY, newRegionY))
{
// Let the grid service module know, so this can be cached
m_eventManager.TriggerOnRegionUp(otherRegion);
@@ -1147,46 +1401,6 @@ namespace OpenSim.Region.Framework.Scenes
return found;
}
- ///
- /// Checks whether this region has a neighbour in the given direction.
- ///
- ///
- ///
- ///
- /// An integer which represents a compass point. N == 1, going clockwise until we reach NW == 8.
- /// Returns a positive integer if there is a region in that direction, a negative integer if not.
- ///
- public int HaveNeighbor(Cardinals car, ref int[] fix)
- {
- uint neighbourx = RegionInfo.RegionLocX;
- uint neighboury = RegionInfo.RegionLocY;
-
- int dir = (int)car;
-
- if (dir > 1 && dir < 5) //Heading East
- neighbourx++;
- else if (dir > 5) // Heading West
- neighbourx--;
-
- if (dir < 3 || dir == 8) // Heading North
- neighboury++;
- else if (dir > 3 && dir < 7) // Heading Sout
- neighboury--;
-
- int x = (int)(neighbourx * Constants.RegionSize);
- int y = (int)(neighboury * Constants.RegionSize);
- GridRegion neighbourRegion = GridService.GetRegionByPosition(RegionInfo.ScopeID, x, y);
-
- if (neighbourRegion == null)
- {
- fix[0] = (int)(RegionInfo.RegionLocX - neighbourx);
- fix[1] = (int)(RegionInfo.RegionLocY - neighboury);
- return dir * (-1);
- }
- else
- return dir;
- }
-
// Alias IncomingHelloNeighbour OtherRegionUp, for now
public GridRegion IncomingHelloNeighbour(RegionInfo neighbour)
{
@@ -1270,14 +1484,14 @@ namespace OpenSim.Region.Framework.Scenes
// Kick all ROOT agents with the message, 'The simulator is going down'
ForEachScenePresence(delegate(ScenePresence avatar)
- {
- avatar.RemoveNeighbourRegion(RegionInfo.RegionHandle);
+ {
+ avatar.RemoveNeighbourRegion(RegionInfo.RegionHandle);
- if (!avatar.IsChildAgent)
- avatar.ControllingClient.Kick("The simulator is going down.");
+ if (!avatar.IsChildAgent)
+ avatar.ControllingClient.Kick("The simulator is going down.");
- avatar.ControllingClient.SendShutdownConnectionNotice();
- });
+ avatar.ControllingClient.SendShutdownConnectionNotice();
+ });
// Stop updating the scene objects and agents.
m_shuttingDown = true;
@@ -1288,20 +1502,11 @@ namespace OpenSim.Region.Framework.Scenes
Thread.Sleep(500);
// Stop all client threads.
- ForEachScenePresence(delegate(ScenePresence avatar) { avatar.ControllingClient.Close(); });
+ ForEachScenePresence(delegate(ScenePresence avatar) { CloseAgent(avatar.UUID, false); });
m_log.Debug("[SCENE]: Persisting changed objects");
EventManager.TriggerSceneShuttingDown(this);
-
- EntityBase[] entities = GetEntities();
- foreach (EntityBase entity in entities)
- {
- if (!entity.IsDeleted && entity is SceneObjectGroup && ((SceneObjectGroup)entity).HasGroupChanged)
- {
- ((SceneObjectGroup)entity).ProcessBackup(SimulationDataService, false);
- }
- }
-
+ Backup(false);
m_sceneGraph.Close();
if (!GridService.DeregisterRegion(RegionInfo.RegionID))
@@ -1322,28 +1527,38 @@ namespace OpenSim.Region.Framework.Scenes
}
}
+ public override void Start()
+ {
+ Start(true);
+ }
+
///
/// Start the scene
///
- public void Start()
+ ///
+ /// Start the scripts within the scene.
+ ///
+ public void Start(bool startScripts)
{
+ if (IsRunning)
+ return;
+
+ m_isRunning = true;
m_active = true;
+ m_unixStartTime = Util.UnixTimeSinceEpoch();
// m_log.DebugFormat("[SCENE]: Starting Heartbeat timer for {0}", RegionInfo.RegionName);
-
- //m_heartbeatTimer.Enabled = true;
- //m_heartbeatTimer.Interval = (int)(m_timespan * 1000);
- //m_heartbeatTimer.Elapsed += new ElapsedEventHandler(Heartbeat);
if (m_heartbeatThread != null)
{
m_heartbeatThread.Abort();
m_heartbeatThread = null;
}
-// m_lastUpdate = Util.EnvironmentTickCount();
m_heartbeatThread
- = Watchdog.StartThread(
- Heartbeat, string.Format("Heartbeat ({0})", RegionInfo.RegionName), ThreadPriority.Normal, false, false);
+ = WorkManager.StartThread(
+ Heartbeat, string.Format("Heartbeat-({0})", RegionInfo.RegionName.Replace(" ", "_")), ThreadPriority.Normal, false, false);
+
+ StartScripts();
}
///
@@ -1374,15 +1589,6 @@ namespace OpenSim.Region.Framework.Scenes
///
private void Heartbeat()
{
-// if (!Monitor.TryEnter(m_heartbeatLock))
-// {
-// Watchdog.RemoveThread();
-// return;
-// }
-
-// try
-// {
-
m_eventManager.TriggerOnRegionStarted(this);
// The first frame can take a very long time due to physics actors being added on startup. Therefore,
@@ -1390,22 +1596,49 @@ namespace OpenSim.Region.Framework.Scenes
// alarms for scenes with many objects.
Update(1);
- Watchdog.StartThread(
- Maintenance, string.Format("Maintenance ({0})", RegionInfo.RegionName), ThreadPriority.Normal, false, true);
+ WorkManager.StartThread(
+ Maintenance, string.Format("Maintenance ({0})", RegionInfo.RegionName), ThreadPriority.Normal, false, true);
Watchdog.GetCurrentThreadInfo().AlarmIfTimeout = true;
- Update(-1);
+ m_lastFrameTick = Util.EnvironmentTickCount();
-// m_lastUpdate = Util.EnvironmentTickCount();
-// m_firstHeartbeat = false;
-// }
-// finally
-// {
-// Monitor.Pulse(m_heartbeatLock);
-// Monitor.Exit(m_heartbeatLock);
-// }
+ if (UpdateOnTimer)
+ {
+ m_sceneUpdateTimer = new Timer(MinFrameTicks);
+ m_sceneUpdateTimer.AutoReset = true;
+ m_sceneUpdateTimer.Elapsed += Update;
+ m_sceneUpdateTimer.Start();
+ }
+ else
+ {
+ Thread.CurrentThread.Priority = ThreadPriority.Highest;
+ Update(-1);
+ Watchdog.RemoveThread();
+ m_isRunning = false;
+ }
+ }
- Watchdog.RemoveThread();
+ private volatile bool m_isTimerUpdateRunning;
+
+ private void Update(object sender, ElapsedEventArgs e)
+ {
+ if (m_isTimerUpdateRunning)
+ return;
+
+ m_isTimerUpdateRunning = true;
+
+ // If the last frame did not complete on time, then immediately start the next update on the same thread
+ // and ignore further timed updates until we have a frame that had spare time.
+ while (!Update(1) && Active) { }
+
+ if (!Active || m_shuttingDown)
+ {
+ m_sceneUpdateTimer.Stop();
+ m_sceneUpdateTimer = null;
+ m_isRunning = false;
+ }
+
+ m_isTimerUpdateRunning = false;
}
private void Maintenance()
@@ -1418,7 +1651,7 @@ namespace OpenSim.Region.Framework.Scenes
public void DoMaintenance(int runs)
{
long? endRun = null;
- int runtc;
+ int runtc, tmpMS;
int previousMaintenanceTick;
if (runs >= 0)
@@ -1432,6 +1665,8 @@ namespace OpenSim.Region.Framework.Scenes
runtc = Util.EnvironmentTickCount();
++MaintenanceRun;
+ // m_log.DebugFormat("[SCENE]: Maintenance run {0} in {1}", MaintenanceRun, Name);
+
// Coarse locations relate to positions of green dots on the mini-map (on a SecondLife client)
if (MaintenanceRun % (m_update_coarse_locations / 10) == 0)
{
@@ -1445,7 +1680,7 @@ namespace OpenSim.Region.Framework.Scenes
if (SendPeriodicAppearanceUpdates && MaintenanceRun % 60 == 0)
{
-// m_log.DebugFormat("[SCENE]: Sending periodic appearance updates");
+ // m_log.DebugFormat("[SCENE]: Sending periodic appearance updates");
if (AvatarFactory != null)
{
@@ -1453,29 +1688,44 @@ namespace OpenSim.Region.Framework.Scenes
}
}
+ // Delete temp-on-rez stuff
+ if (MaintenanceRun % m_update_temp_cleaning == 0 && !m_cleaningTemps)
+ {
+ // m_log.DebugFormat("[SCENE]: Running temp-on-rez cleaning in {0}", Name);
+ tmpMS = Util.EnvironmentTickCount();
+ m_cleaningTemps = true;
+
+ WorkManager.RunInThread(
+ delegate { CleanTempObjects(); m_cleaningTemps = false; },
+ null,
+ string.Format("CleanTempObjects ({0})", Name));
+
+ tempOnRezMS = Util.EnvironmentTickCountSubtract(tmpMS);
+ }
+
Watchdog.UpdateThread();
previousMaintenanceTick = m_lastMaintenanceTick;
m_lastMaintenanceTick = Util.EnvironmentTickCount();
runtc = Util.EnvironmentTickCountSubtract(m_lastMaintenanceTick, runtc);
- runtc = (int)(MinMaintenanceTime * 1000) - runtc;
-
+ runtc = MinMaintenanceTicks - runtc;
+
if (runtc > 0)
- Thread.Sleep(runtc);
-
+ m_maintenanceWaitEvent.WaitOne(runtc);
+
// Optionally warn if a frame takes double the amount of time that it should.
if (DebugUpdates
&& Util.EnvironmentTickCountSubtract(
- m_lastMaintenanceTick, previousMaintenanceTick) > (int)(MinMaintenanceTime * 1000 * 2))
+ m_lastMaintenanceTick, previousMaintenanceTick) > MinMaintenanceTicks * 2)
m_log.WarnFormat(
"[SCENE]: Maintenance took {0} ms (desired max {1} ms) in {2}",
Util.EnvironmentTickCountSubtract(m_lastMaintenanceTick, previousMaintenanceTick),
- MinMaintenanceTime * 1000,
+ MinMaintenanceTicks,
RegionInfo.RegionName);
}
}
- public override void Update(int frames)
+ public override bool Update(int frames)
{
long? endFrame = null;
@@ -1484,101 +1734,159 @@ namespace OpenSim.Region.Framework.Scenes
float physicsFPS = 0f;
int previousFrameTick, tmpMS;
- int maintc = Util.EnvironmentTickCount();
+
+ // These variables will be used to save the precise frame time using the
+ // Stopwatch class of Microsoft SDK; the times are recorded at the start
+ // and end of a particular section of code, and then used to calculate
+ // the frame times, which are the sums of the sections for each given name
+ double preciseTotalFrameTime = 0.0;
+ double preciseSimFrameTime = 0.0;
+ double precisePhysicsFrameTime = 0.0;
+ Stopwatch totalFrameStopwatch = new Stopwatch();
+ Stopwatch simFrameStopwatch = new Stopwatch();
+ Stopwatch physicsFrameStopwatch = new Stopwatch();
+
+ // Begin the stopwatch to keep track of the time that the frame
+ // started running to determine how long the frame took to complete
+ totalFrameStopwatch.Start();
while (!m_shuttingDown && ((endFrame == null && Active) || Frame < endFrame))
{
++Frame;
-// m_log.DebugFormat("[SCENE]: Processing frame {0} in {1}", Frame, RegionInfo.RegionName);
+ // m_log.DebugFormat("[SCENE]: Processing frame {0} in {1}", Frame, RegionInfo.RegionName);
- agentMS = tempOnRezMS = eventMS = backupMS = terrainMS = landMS = spareMS = 0;
+ agentMS = eventMS = backupMS = terrainMS = landMS = spareMS = 0;
try
{
+ EventManager.TriggerRegionHeartbeatStart(this);
+
// Apply taints in terrain module to terrain in physics scene
if (Frame % m_update_terrain == 0)
{
+ // At several points inside the code there was a need to
+ // create a more precise measurement of time elapsed.
+ // This led to the addition of variables that have a
+ // similar function and thus remain tightly connected to
+ // their original counterparts. However, the original
+ // code is not receiving comments from our group because
+ // we don't feel right modifying the code to that degree
+ // at this point in time, the precise values all begin
+ // with the keyword precise
tmpMS = Util.EnvironmentTickCount();
+ simFrameStopwatch.Start();
UpdateTerrain();
+
+ // Get the simulation frame time that the avatar force
+ // input took
+ simFrameStopwatch.Stop();
+ preciseSimFrameTime =
+ simFrameStopwatch.Elapsed.TotalMilliseconds;
terrainMS = Util.EnvironmentTickCountSubtract(tmpMS);
}
+ // At several points inside the code there was a need to
+ // create a more precise measurement of time elapsed. This
+ // led to the addition of variables that have a similar
+ // function and thus remain tightly connected to their
+ // original counterparts. However, the original code is
+ // not receiving comments from our group because we don't
+ // feel right modifying the code to that degree at this
+ // point in time, the precise values all begin with the
+ // keyword precise
+
tmpMS = Util.EnvironmentTickCount();
+
+ // Begin the stopwatch to track the time to prepare physics
+ physicsFrameStopwatch.Start();
if (PhysicsEnabled && Frame % m_update_physics == 0)
m_sceneGraph.UpdatePreparePhysics();
+
+ // Get the time it took to prepare the physics, this
+ // would report the most precise time that physics was
+ // running on the machine and should the physics not be
+ // enabled will report the time it took to check if physics
+ // was enabled
+ physicsFrameStopwatch.Stop();
+ precisePhysicsFrameTime = physicsFrameStopwatch.Elapsed.TotalMilliseconds;
physicsMS2 = Util.EnvironmentTickCountSubtract(tmpMS);
-
+
// Apply any pending avatar force input to the avatar's velocity
tmpMS = Util.EnvironmentTickCount();
+ simFrameStopwatch.Restart();
if (Frame % m_update_entitymovement == 0)
m_sceneGraph.UpdateScenePresenceMovement();
+
+ // Get the simulation frame time that the avatar force input
+ // took
+ simFrameStopwatch.Stop();
+ preciseSimFrameTime +=
+ simFrameStopwatch.Elapsed.TotalMilliseconds;
agentMS = Util.EnvironmentTickCountSubtract(tmpMS);
-
+
// Perform the main physics update. This will do the actual work of moving objects and avatars according to their
// velocity
tmpMS = Util.EnvironmentTickCount();
+ physicsFrameStopwatch.Restart();
if (Frame % m_update_physics == 0)
{
if (PhysicsEnabled)
- physicsFPS = m_sceneGraph.UpdatePhysics(MinFrameTime);
-
+ physicsFPS = m_sceneGraph.UpdatePhysics(MinFrameSeconds);
+
if (SynchronizeScene != null)
SynchronizeScene(this);
}
+
+ // Add the main physics update time to the prepare physics time
+ physicsFrameStopwatch.Stop();
+ precisePhysicsFrameTime += physicsFrameStopwatch.Elapsed.TotalMilliseconds;
physicsMS = Util.EnvironmentTickCountSubtract(tmpMS);
+ // Start the stopwatch for the remainder of the simulation
+ simFrameStopwatch.Restart();
tmpMS = Util.EnvironmentTickCount();
-
+
// Check if any objects have reached their targets
CheckAtTargets();
-
+
// Update SceneObjectGroups that have scheduled themselves for updates
// Objects queue their updates onto all scene presences
if (Frame % m_update_objects == 0)
m_sceneGraph.UpdateObjectGroups();
-
+
// Run through all ScenePresences looking for updates
// Presence updates and queued object updates for each presence are sent to clients
if (Frame % m_update_presences == 0)
m_sceneGraph.UpdatePresences();
-
+
agentMS += Util.EnvironmentTickCountSubtract(tmpMS);
-
- // Delete temp-on-rez stuff
- if (Frame % m_update_temp_cleaning == 0 && !m_cleaningTemps)
- {
- tmpMS = Util.EnvironmentTickCount();
- m_cleaningTemps = true;
- Util.FireAndForget(delegate { CleanTempObjects(); m_cleaningTemps = false; });
- tempOnRezMS = Util.EnvironmentTickCountSubtract(tmpMS);
- }
-
+
if (Frame % m_update_events == 0)
{
tmpMS = Util.EnvironmentTickCount();
UpdateEvents();
eventMS = Util.EnvironmentTickCountSubtract(tmpMS);
}
-
+
if (PeriodicBackup && Frame % m_update_backup == 0)
{
tmpMS = Util.EnvironmentTickCount();
UpdateStorageBackup();
backupMS = Util.EnvironmentTickCountSubtract(tmpMS);
}
-
+
//if (Frame % m_update_land == 0)
//{
// int ldMS = Util.EnvironmentTickCount();
// UpdateLand();
// landMS = Util.EnvironmentTickCountSubtract(ldMS);
//}
-
+
if (!LoginsEnabled && Frame == 20)
{
- // m_log.DebugFormat("{0} {1} {2}", LoginsDisabled, m_sceneGraph.GetActiveScriptsCount(), LoginLock);
-
+ // m_log.DebugFormat("{0} {1} {2}", LoginsDisabled, m_sceneGraph.GetActiveScriptsCount(), LoginLock);
+
// In 99.9% of cases it is a bad idea to manually force garbage collection. However,
// this is a rare case where we know we have just went through a long cycle of heap
// allocations, and there is no more work to be done until someone logs in
@@ -1593,7 +1901,7 @@ namespace OpenSim.Region.Framework.Scenes
}
m_sceneGridService.InformNeighborsThatRegionisUp(
- RequestModuleInterface(), RegionInfo);
+ RequestModuleInterface(), RegionInfo);
// Region ready should always be set
Ready = true;
@@ -1604,7 +1912,7 @@ namespace OpenSim.Region.Framework.Scenes
if (m_sceneGraph.GetActiveScriptsCount() == 0)
{
// In this case, we leave it to the IRegionReadyModule to enable logins
-
+
// LoginLock can currently only be set by a region module implementation.
// If somehow this hasn't been done then the quickest way to bugfix is to see the
// NullReferenceException
@@ -1620,26 +1928,42 @@ namespace OpenSim.Region.Framework.Scenes
"[SCENE]: Failed on region {0} with exception {1}{2}",
RegionInfo.RegionName, e.Message, e.StackTrace);
}
-
+
EventManager.TriggerRegionHeartbeatEnd(this);
+ otherMS = eventMS + backupMS + terrainMS + landMS;
- Watchdog.UpdateThread();
+ // Get the elapsed time for the simulation frame
+ simFrameStopwatch.Stop();
+ preciseSimFrameTime +=
+ simFrameStopwatch.Elapsed.TotalMilliseconds;
- previousFrameTick = m_lastFrameTick;
- m_lastFrameTick = Util.EnvironmentTickCount();
- tmpMS = Util.EnvironmentTickCountSubtract(m_lastFrameTick, maintc);
- tmpMS = (int)(MinFrameTime * 1000) - tmpMS;
+ if (!UpdateOnTimer)
+ {
+ Watchdog.UpdateThread();
- if (tmpMS > 0)
+ spareMS = MinFrameTicks - Util.EnvironmentTickCountSubtract(m_lastFrameTick);
+
+ if (spareMS > 0)
+ m_updateWaitEvent.WaitOne(spareMS);
+ else
+ spareMS = 0;
+ }
+ else
{
- Thread.Sleep(tmpMS);
- spareMS += tmpMS;
+ spareMS = Math.Max(0, MinFrameTicks - physicsMS2 - agentMS - physicsMS - otherMS);
}
- frameMS = Util.EnvironmentTickCountSubtract(maintc);
- maintc = Util.EnvironmentTickCount();
+ // Get the total frame time
+ totalFrameStopwatch.Stop();
+ preciseTotalFrameTime =
+ totalFrameStopwatch.Elapsed.TotalMilliseconds;
- otherMS = tempOnRezMS + eventMS + backupMS + terrainMS + landMS;
+ // Restart the stopwatch for the total time of the next frame
+ totalFrameStopwatch.Restart();
+
+ previousFrameTick = m_lastFrameTick;
+ frameMS = Util.EnvironmentTickCountSubtract(m_lastFrameTick);
+ m_lastFrameTick = Util.EnvironmentTickCount();
// if (Frame%m_update_avatars == 0)
// UpdateInWorldTime();
@@ -1653,18 +1977,53 @@ namespace OpenSim.Region.Framework.Scenes
StatsReporter.addOtherMS(otherMS);
StatsReporter.AddSpareMS(spareMS);
StatsReporter.addScriptLines(m_sceneGraph.GetScriptLPS());
+ StatsReporter.AddScriptMS((int) GetAndResetScriptExecutionTime());
+
+ // Send the correct time values to the stats reporter for the
+ // frame times
+ StatsReporter.addFrameTimeMilliseconds(preciseTotalFrameTime,
+ preciseSimFrameTime, precisePhysicsFrameTime, 0.0);
- // Optionally warn if a frame takes double the amount of time that it should.
+ // Send the correct number of frames that the physics library
+ // has processed to the stats reporter
+ StatsReporter.addPhysicsFrame(1);
+
+ // Optionally warn if a frame takes double the amount of time that it should.
if (DebugUpdates
&& Util.EnvironmentTickCountSubtract(
- m_lastFrameTick, previousFrameTick) > (int)(MinFrameTime * 1000 * 2))
+ m_lastFrameTick, previousFrameTick) > MinFrameTicks * 2)
m_log.WarnFormat(
"[SCENE]: Frame took {0} ms (desired max {1} ms) in {2}",
Util.EnvironmentTickCountSubtract(m_lastFrameTick, previousFrameTick),
- MinFrameTime * 1000,
+ MinFrameTicks,
RegionInfo.RegionName);
}
- }
+
+ // Finished updating scene frame, so stop the total frame's Stopwatch
+ totalFrameStopwatch.Stop();
+
+ return spareMS >= 0;
+ }
+
+ ///
+ /// Adds the execution time of one script to the total scripts execution time for this region.
+ ///
+ /// Elapsed Stopwatch ticks
+ public void AddScriptExecutionTime(long ticks)
+ {
+ Interlocked.Add(ref m_scriptExecutionTime, ticks);
+ }
+
+ ///
+ /// Returns the total execution time of all the scripts in the region since the last frame
+ /// (in milliseconds), and clears the value in preparation for the next frame.
+ ///
+ /// Time in milliseconds
+ private long GetAndResetScriptExecutionTime()
+ {
+ long ticks = Interlocked.Exchange(ref m_scriptExecutionTime, 0);
+ return (ticks * 1000) / Stopwatch.Frequency;
+ }
public void AddGroupTarget(SceneObjectGroup grp)
{
@@ -1723,7 +2082,7 @@ namespace OpenSim.Region.Framework.Scenes
if (!m_backingup)
{
m_backingup = true;
- Util.FireAndForget(BackupWaitCallback);
+ WorkManager.RunInThread(o => Backup(false), null, string.Format("BackupWaitCallback ({0})", Name));
}
}
@@ -1736,16 +2095,12 @@ namespace OpenSim.Region.Framework.Scenes
}
///
- /// Wrapper for Backup() that can be called with Util.FireAndForget()
- ///
- private void BackupWaitCallback(object o)
- {
- Backup(false);
- }
-
- ///
- /// Backup the scene. This acts as the main method of the backup thread.
+ /// Backup the scene.
///
+ ///
+ /// This acts as the main method of the backup thread. In a regression test whether the backup thread is not
+ /// running independently this can be invoked directly.
+ ///
///
/// If true, then any changes that have not yet been persisted are persisted. If false,
/// then the persistence decision is left to the backup code (in some situations, such as object persistence,
@@ -1784,7 +2139,7 @@ namespace OpenSim.Region.Framework.Scenes
IMessageTransferModule tr = RequestModuleInterface();
if (tr != null)
- tr.SendInstantMessage(msg, delegate(bool success) {});
+ tr.SendInstantMessage(msg, delegate(bool success) { });
}
m_returns.Clear();
}
@@ -1798,6 +2153,7 @@ namespace OpenSim.Region.Framework.Scenes
{
if (group != null)
{
+ group.HasGroupChanged = true;
group.ProcessBackup(SimulationDataService, true);
}
}
@@ -1866,7 +2222,7 @@ namespace OpenSim.Region.Framework.Scenes
{
try
{
- double[,] map = SimulationDataService.LoadTerrain(RegionInfo.RegionID);
+ TerrainData map = SimulationDataService.LoadTerrain(RegionInfo.RegionID, (int)RegionInfo.RegionSizeX, (int)RegionInfo.RegionSizeY, (int)RegionInfo.RegionSizeZ);
if (map == null)
{
// This should be in the Terrain module, but it isn't because
@@ -1877,7 +2233,7 @@ namespace OpenSim.Region.Framework.Scenes
m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain);
m_log.InfoFormat("[TERRAIN]: No default terrain. Generating a new terrain {0}.", m_InitialTerrain);
- Heightmap = new TerrainChannel(m_InitialTerrain);
+ Heightmap = new TerrainChannel(m_InitialTerrain, (int)RegionInfo.RegionSizeX, (int)RegionInfo.RegionSizeY, (int)RegionInfo.RegionSizeZ);
SimulationDataService.StoreTerrain(Heightmap.GetDoubles(), RegionInfo.RegionID);
}
@@ -1891,9 +2247,9 @@ namespace OpenSim.Region.Framework.Scenes
m_log.WarnFormat(
"[TERRAIN]: Scene.cs: LoadWorldMap() - Regenerating as failed with exception {0}{1}",
e.Message, e.StackTrace);
-
+
// Non standard region size. If there's an old terrain in the database, it might read past the buffer
- #pragma warning disable 0162
+#pragma warning disable 0162
if ((int)Constants.RegionSize != 256)
{
Heightmap = new TerrainChannel();
@@ -1921,10 +2277,16 @@ namespace OpenSim.Region.Framework.Scenes
//// stored in the GridService, because that's what the world map module uses
//// to send the map image UUIDs (of other regions) to the viewer...
if (m_generateMaptiles)
- RegenerateMaptile();
+ RegenerateMaptile();
GridRegion region = new GridRegion(RegionInfo);
string error = GridService.RegisterRegion(RegionInfo.ScopeID, region);
+ // m_log.DebugFormat("[SCENE]: RegisterRegionWithGrid. name={0},id={1},loc=<{2},{3}>,size=<{4},{5}>",
+ // m_regionName,
+ // RegionInfo.RegionID,
+ // RegionInfo.RegionLocX, RegionInfo.RegionLocY,
+ // RegionInfo.RegionSizeX, RegionInfo.RegionSizeY);
+
if (error != String.Empty)
throw new Exception(error);
}
@@ -1985,13 +2347,26 @@ namespace OpenSim.Region.Framework.Scenes
rootPart.TrimPermissions();
// Don't do this here - it will get done later on when sculpt data is loaded.
-// group.CheckSculptAndLoad();
+ // group.CheckSculptAndLoad();
}
LoadingPrims = false;
EventManager.TriggerPrimsLoaded(this);
}
+ public bool SupportsRayCastFiltered()
+ {
+ if (PhysicsScene == null)
+ return false;
+ return PhysicsScene.SupportsRaycastWorldFiltered();
+ }
+
+ public object RayCastFiltered(Vector3 position, Vector3 direction, float length, int Count, RayFilterFlags filter)
+ {
+ if (PhysicsScene == null)
+ return null;
+ return PhysicsScene.RaycastWorld(position, direction, length, Count, filter);
+ }
///
/// Gets a new rez location based on the raycast and the size of the object that is being rezzed.
@@ -2020,8 +2395,8 @@ namespace OpenSim.Region.Framework.Scenes
SceneObjectPart target = GetSceneObjectPart(RayTargetID);
Vector3 direction = Vector3.Normalize(RayEnd - RayStart);
- Vector3 AXOrigin = new Vector3(RayStart.X, RayStart.Y, RayStart.Z);
- Vector3 AXdirection = new Vector3(direction.X, direction.Y, direction.Z);
+ Vector3 AXOrigin = RayStart;
+ Vector3 AXdirection = direction;
if (target != null)
{
@@ -2037,19 +2412,19 @@ namespace OpenSim.Region.Framework.Scenes
EntityIntersection ei = target.TestIntersectionOBB(NewRay, Quaternion.Identity, frontFacesOnly, FaceCenter);
// Un-comment out the following line to Get Raytrace results printed to the console.
- // m_log.Info("[RAYTRACERESULTS]: Hit:" + ei.HitTF.ToString() + " Point: " + ei.ipoint.ToString() + " Normal: " + ei.normal.ToString());
+ // m_log.Info("[RAYTRACERESULTS]: Hit:" + ei.HitTF.ToString() + " Point: " + ei.ipoint.ToString() + " Normal: " + ei.normal.ToString());
float ScaleOffset = 0.5f;
// If we hit something
if (ei.HitTF)
{
- Vector3 scaleComponent = new Vector3(ei.AAfaceNormal.X, ei.AAfaceNormal.Y, ei.AAfaceNormal.Z);
+ Vector3 scaleComponent = ei.AAfaceNormal;
if (scaleComponent.X != 0) ScaleOffset = scale.X;
if (scaleComponent.Y != 0) ScaleOffset = scale.Y;
if (scaleComponent.Z != 0) ScaleOffset = scale.Z;
ScaleOffset = Math.Abs(ScaleOffset);
- Vector3 intersectionpoint = new Vector3(ei.ipoint.X, ei.ipoint.Y, ei.ipoint.Z);
- Vector3 normal = new Vector3(ei.normal.X, ei.normal.Y, ei.normal.Z);
+ Vector3 intersectionpoint = ei.ipoint;
+ Vector3 normal = ei.normal;
// Set the position to the intersection point
Vector3 offset = (normal * (ScaleOffset / 2f));
pos = (intersectionpoint + offset);
@@ -2058,7 +2433,7 @@ namespace OpenSim.Region.Framework.Scenes
//And in cases when we weren't rezzing from inventory we were re-adding the 0.25 straight after calling this method
// Un-offset the prim (it gets offset later by the consumer method)
//pos.Z -= 0.25F;
-
+
}
return pos;
@@ -2074,8 +2449,9 @@ namespace OpenSim.Region.Framework.Scenes
if (ei.HitTF)
{
- pos = new Vector3(ei.ipoint.X, ei.ipoint.Y, ei.ipoint.Z);
- } else
+ pos = ei.ipoint;
+ }
+ else
{
// fall back to our stupid functionality
pos = RayEnd;
@@ -2137,7 +2513,7 @@ namespace OpenSim.Region.Framework.Scenes
// "[SCENE]: Scene.AddNewPrim() pcode {0} called for {1} in {2}", shape.PCode, ownerID, RegionInfo.RegionName);
SceneObjectGroup sceneObject = null;
-
+
// If an entity creator has been registered for this prim type then use that
if (m_entityCreators.ContainsKey((PCode)shape.PCode))
{
@@ -2158,7 +2534,7 @@ namespace OpenSim.Region.Framework.Scenes
return sceneObject;
}
-
+
///
/// Add an object into the scene that has come from storage
///
@@ -2191,7 +2567,7 @@ namespace OpenSim.Region.Framework.Scenes
return false;
}
-
+
///
/// Add an object into the scene that has come from storage
///
@@ -2227,7 +2603,7 @@ namespace OpenSim.Region.Framework.Scenes
{
return AddNewSceneObject(sceneObject, attachToBackup, true);
}
-
+
///
/// Add a newly created object to the scene
///
@@ -2242,16 +2618,16 @@ namespace OpenSim.Region.Framework.Scenes
///
/// true if the object was added. false if not
public bool AddNewSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates)
- {
+ {
if (m_sceneGraph.AddNewSceneObject(sceneObject, attachToBackup, sendClientUpdates))
{
EventManager.TriggerObjectAddedToScene(sceneObject);
- return true;
+ return true;
}
-
+
return false;
}
-
+
///
/// Add a newly created object to the scene.
///
@@ -2268,7 +2644,7 @@ namespace OpenSim.Region.Framework.Scenes
SceneObjectGroup sceneObject, bool attachToBackup, Vector3? pos, Quaternion? rot, Vector3 vel)
{
if (m_sceneGraph.AddNewSceneObject(sceneObject, attachToBackup, pos, rot, vel))
- {
+ {
EventManager.TriggerObjectAddedToScene(sceneObject);
return true;
}
@@ -2316,8 +2692,8 @@ namespace OpenSim.Region.Framework.Scenes
/// Suppress broadcasting changes to other clients.
/// If true, then scripts are removed. If false, then they are only stopped.
public void DeleteSceneObject(SceneObjectGroup group, bool silent, bool removeScripts)
- {
-// m_log.DebugFormat("[SCENE]: Deleting scene object {0} {1}", group.Name, group.UUID);
+ {
+ // m_log.DebugFormat("[SCENE]: Deleting scene object {0} {1}", group.Name, group.UUID);
if (removeScripts)
group.RemoveScriptInstances(true);
@@ -2328,6 +2704,12 @@ namespace OpenSim.Region.Framework.Scenes
foreach (SceneObjectPart part in partList)
{
+ if (part.KeyframeMotion != null)
+ {
+ part.KeyframeMotion.Delete();
+ part.KeyframeMotion = null;
+ }
+
if (part.IsJoint() && ((part.Flags & PrimFlags.Physics) != 0))
{
PhysicsScene.RequestJointDeletion(part.Name); // FIXME: what if the name changed?
@@ -2346,7 +2728,7 @@ namespace OpenSim.Region.Framework.Scenes
group.DeleteGroupFromScene(silent);
-// m_log.DebugFormat("[SCENE]: Exit DeleteSceneObject() for {0} {1}", group.Name, group.UUID);
+ // m_log.DebugFormat("[SCENE]: Exit DeleteSceneObject() for {0} {1}", group.Name, group.UUID);
}
///
@@ -2362,17 +2744,16 @@ namespace OpenSim.Region.Framework.Scenes
{
if (!softDelete)
{
- // Force a database update so that the scene object group ID is accurate. It's possible that the
- // group has recently been delinked from another group but that this change has not been persisted
- // to the DB.
+ // If the group contains prims whose SceneGroupID is incorrect then force a
+ // database update, because RemoveObject() works by searching on the SceneGroupID.
// This is an expensive thing to do so only do it if absolutely necessary.
- if (so.HasGroupChangedDueToDelink)
- ForceSceneObjectBackup(so);
-
+ if (so.GroupContainsForeignPrims)
+ ForceSceneObjectBackup(so);
+
so.DetachFromBackup();
SimulationDataService.RemoveObject(so.UUID, RegionInfo.RegionID);
}
-
+
// We need to keep track of this state in case this group is still queued for further backup.
so.IsDeleted = true;
@@ -2431,186 +2812,35 @@ namespace OpenSim.Region.Framework.Scenes
EntityTransferModule.Cross(grp, attemptedPosition, silent);
}
- public Border GetCrossedBorder(Vector3 position, Cardinals gridline)
+ // Simple test to see if a position is in the current region.
+ // This test is mostly used to see if a region crossing is necessary.
+ // Assuming the position is relative to the region so anything outside its bounds.
+ // Return 'true' if position inside region.
+ public bool PositionIsInCurrentRegion(Vector3 pos)
{
- if (BordersLocked)
- {
- switch (gridline)
- {
- case Cardinals.N:
- lock (NorthBorders)
- {
- foreach (Border b in NorthBorders)
- {
- if (b.TestCross(position))
- return b;
- }
- }
- break;
- case Cardinals.S:
- lock (SouthBorders)
- {
- foreach (Border b in SouthBorders)
- {
- if (b.TestCross(position))
- return b;
- }
- }
-
- break;
- case Cardinals.E:
- lock (EastBorders)
- {
- foreach (Border b in EastBorders)
- {
- if (b.TestCross(position))
- return b;
- }
- }
-
- break;
- case Cardinals.W:
-
- lock (WestBorders)
- {
- foreach (Border b in WestBorders)
- {
- if (b.TestCross(position))
- return b;
- }
- }
- break;
+ bool ret = false;
+ int xx = (int)Math.Floor(pos.X);
+ int yy = (int)Math.Floor(pos.Y);
+ if (xx < 0 || yy < 0)
+ return false;
- }
+ IRegionCombinerModule regionCombinerModule = RequestModuleInterface();
+ if (regionCombinerModule == null)
+ {
+ // Regular region. Just check for region size
+ if (xx < RegionInfo.RegionSizeX && yy < RegionInfo.RegionSizeY)
+ ret = true;
}
else
{
- switch (gridline)
- {
- case Cardinals.N:
- foreach (Border b in NorthBorders)
- {
- if (b.TestCross(position))
- return b;
- }
-
- break;
- case Cardinals.S:
- foreach (Border b in SouthBorders)
- {
- if (b.TestCross(position))
- return b;
- }
- break;
- case Cardinals.E:
- foreach (Border b in EastBorders)
- {
- if (b.TestCross(position))
- return b;
- }
-
- break;
- case Cardinals.W:
- foreach (Border b in WestBorders)
- {
- if (b.TestCross(position))
- return b;
- }
- break;
-
- }
+ // We're in a mega-region so see if we are still in that larger region
+ ret = regionCombinerModule.PositionIsInMegaregion(this.RegionInfo.RegionID, xx, yy);
}
-
- return null;
- }
+ return ret;
- public bool TestBorderCross(Vector3 position, Cardinals border)
- {
- if (BordersLocked)
- {
- switch (border)
- {
- case Cardinals.N:
- lock (NorthBorders)
- {
- foreach (Border b in NorthBorders)
- {
- if (b.TestCross(position))
- return true;
- }
- }
- break;
- case Cardinals.E:
- lock (EastBorders)
- {
- foreach (Border b in EastBorders)
- {
- if (b.TestCross(position))
- return true;
- }
- }
- break;
- case Cardinals.S:
- lock (SouthBorders)
- {
- foreach (Border b in SouthBorders)
- {
- if (b.TestCross(position))
- return true;
- }
- }
- break;
- case Cardinals.W:
- lock (WestBorders)
- {
- foreach (Border b in WestBorders)
- {
- if (b.TestCross(position))
- return true;
- }
- }
- break;
- }
- }
- else
- {
- switch (border)
- {
- case Cardinals.N:
- foreach (Border b in NorthBorders)
- {
- if (b.TestCross(position))
- return true;
- }
- break;
- case Cardinals.E:
- foreach (Border b in EastBorders)
- {
- if (b.TestCross(position))
- return true;
- }
- break;
- case Cardinals.S:
- foreach (Border b in SouthBorders)
- {
- if (b.TestCross(position))
- return true;
- }
- break;
- case Cardinals.W:
- foreach (Border b in WestBorders)
- {
- if (b.TestCross(position))
- return true;
- }
- break;
- }
- }
- return false;
}
-
///
/// Called when objects or attachments cross the border, or teleport, between regions.
///
@@ -2632,45 +2862,8 @@ namespace OpenSim.Region.Framework.Scenes
return false;
}
- // If the user is banned, we won't let any of their objects
- // enter. Period.
- //
- if (RegionInfo.EstateSettings.IsBanned(newObject.OwnerID))
- {
- m_log.InfoFormat("[INTERREGION]: Denied prim crossing for banned avatar {0}", newObject.OwnerID);
+ if (!EntityTransferModule.HandleIncomingSceneObject(newObject, newPosition))
return false;
- }
-
- if (newPosition != Vector3.Zero)
- newObject.RootPart.GroupPosition = newPosition;
-
- if (!AddSceneObject(newObject))
- {
- m_log.DebugFormat(
- "[INTERREGION]: Problem adding scene object {0} in {1} ", newObject.UUID, RegionInfo.RegionName);
- return false;
- }
-
- if (!newObject.IsAttachment)
- {
- // FIXME: It would be better to never add the scene object at all rather than add it and then delete
- // it
- if (!Permissions.CanObjectEntry(newObject.UUID, true, newObject.AbsolutePosition))
- {
- // Deny non attachments based on parcel settings
- //
- m_log.Info("[INTERREGION]: Denied prim crossing because of parcel settings");
-
- DeleteSceneObject(newObject, false);
-
- return false;
- }
-
- // For attachments, we need to wait until the agent is root
- // before we restart the scripts, or else some functions won't work.
- newObject.RootPart.ParentGroup.CreateScriptInstances(0, false, DefaultScriptEngine, GetStateSource(newObject));
- newObject.ResumeScripts();
- }
// Do this as late as possible so that listeners have full access to the incoming object
EventManager.TriggerOnIncomingSceneObject(newObject);
@@ -2697,7 +2890,7 @@ namespace OpenSim.Region.Framework.Scenes
{
sceneObject.RootPart.AddFlag(PrimFlags.TemporaryOnRez);
sceneObject.RootPart.AddFlag(PrimFlags.Phantom);
-
+
// Don't sent a full update here because this will cause full updates to be sent twice for
// attachments on region crossings, resulting in viewer glitches.
AddRestoredSceneObject(sceneObject, false, false, false);
@@ -2712,15 +2905,18 @@ namespace OpenSim.Region.Framework.Scenes
{
SceneObjectGroup grp = sceneObject;
-// m_log.DebugFormat(
-// "[ATTACHMENT]: Received attachment {0}, inworld asset id {1}", grp.FromItemID, grp.UUID);
-// m_log.DebugFormat(
-// "[ATTACHMENT]: Attach to avatar {0} at position {1}", sp.UUID, grp.AbsolutePosition);
+ // m_log.DebugFormat(
+ // "[ATTACHMENT]: Received attachment {0}, inworld asset id {1}", grp.FromItemID, grp.UUID);
+ // m_log.DebugFormat(
+ // "[ATTACHMENT]: Attach to avatar {0} at position {1}", sp.UUID, grp.AbsolutePosition);
RootPrim.RemFlag(PrimFlags.TemporaryOnRez);
-
+
+ // We must currently not resume scripts at this stage since AttachmentsModule does not have the
+ // information that this is due to a teleport/border cross rather than an ordinary attachment.
+ // We currently do this in Scene.MakeRootAgent() instead.
if (AttachmentsModule != null)
- AttachmentsModule.AttachObject(sp, grp, 0, false, false);
+ AttachmentsModule.AttachObject(sp, grp, 0, false, false, true);
}
else
{
@@ -2736,28 +2932,22 @@ namespace OpenSim.Region.Framework.Scenes
return true;
}
- private int GetStateSource(SceneObjectGroup sog)
- {
- ScenePresence sp = GetScenePresence(sog.OwnerID);
-
- if (sp != null)
- return sp.GetStateSource();
-
- return 2; // StateSource.PrimCrossing
- }
-
#endregion
#region Add/Remove Avatar Methods
- public override ISceneAgent AddNewClient(IClientAPI client, PresenceType type)
+ public override ISceneAgent AddNewAgent(IClientAPI client, PresenceType type)
{
ScenePresence sp;
bool vialogin;
+ bool reallyNew = true;
+
+ // Update the number of users attempting to login
+ StatsReporter.UpdateUsersLoggingIn(true);
// Validation occurs in LLUDPServer
//
- // XXX: A race condition exists here where two simultaneous calls to AddNewClient can interfere with
+ // XXX: A race condition exists here where two simultaneous calls to AddNewAgent can interfere with
// each other. In practice, this does not currently occur in the code.
AgentCircuitData aCircuit = m_authenticateHandler.GetAgentCircuitData(client.CircuitCode);
@@ -2765,9 +2955,9 @@ namespace OpenSim.Region.Framework.Scenes
// and a simultaneous one that removes it (as can happen if the client is closed at a particular point
// whilst connecting).
//
- // It would be easier to lock across all NewUserConnection(), AddNewClient() and
+ // It would be easier to lock across all NewUserConnection(), AddNewAgent() and
// RemoveClient() calls for all agents, but this would allow a slow call (e.g. because of slow service
- // response in some module listening to AddNewClient()) from holding up unrelated agent calls.
+ // response in some module listening to AddNewAgent()) from holding up unrelated agent calls.
//
// In practice, the lock (this) in LLUDPServer.AddNewClient() currently lock across all
// AddNewClient() operations (though not other ops).
@@ -2777,68 +2967,90 @@ namespace OpenSim.Region.Framework.Scenes
vialogin
= (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0
|| (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaLogin) != 0;
-
- // CheckHeartbeat();
-
+
+ // CheckHeartbeat();
+
sp = GetScenePresence(client.AgentId);
// XXX: Not sure how good it is to add a new client if a scene presence already exists. Possibly this
// could occur if a viewer crashes and relogs before the old client is kicked out. But this could cause
- // other problems, and possible the code calling AddNewClient() should ensure that no client is already
+ // other problems, and possibly the code calling AddNewAgent() should ensure that no client is already
// connected.
if (sp == null)
{
m_log.DebugFormat(
"[SCENE]: Adding new child scene presence {0} {1} to scene {2} at pos {3}",
client.Name, client.AgentId, RegionInfo.RegionName, client.StartPos);
-
+
+ sp = m_sceneGraph.CreateAndAddChildScenePresence(client, aCircuit.Appearance, type);
+
+ // We must set this here so that TriggerOnNewClient and TriggerOnClientLogin can determine whether the
+ // client is for a root or child agent.
+ // We must also set this before adding the client to the client manager so that an exception later on
+ // does not leave a client manager entry without the scene agent set, which will cause other code
+ // to fail since any entry in the client manager should have a ScenePresence
+ //
+ // XXX: This may be better set for a new client before that client is added to the client manager.
+ // But need to know what happens in the case where a ScenePresence is already present (and if this
+ // actually occurs).
+ client.SceneAgent = sp;
+
m_clientManager.Add(client);
SubscribeToClientEvents(client);
-
- sp = m_sceneGraph.CreateAndAddChildScenePresence(client, aCircuit.Appearance, type);
m_eventManager.TriggerOnNewPresence(sp);
-
+
sp.TeleportFlags = (TPFlags)aCircuit.teleportFlags;
-
- // The first agent upon login is a root agent by design.
- // For this agent we will have to rez the attachments.
- // All other AddNewClient calls find aCircuit.child to be true.
- if (aCircuit.child == false)
- {
- // We have to set SP to be a root agent here so that SP.MakeRootAgent() will later not try to
- // start the scripts again (since this is done in RezAttachments()).
- // XXX: This is convoluted.
- sp.IsChildAgent = false;
-
- if (AttachmentsModule != null)
- Util.FireAndForget(delegate(object o) { AttachmentsModule.RezAttachments(sp); });
- }
}
else
{
+ // We must set this here so that TriggerOnNewClient and TriggerOnClientLogin can determine whether the
+ // client is for a root or child agent.
+ // XXX: This may be better set for a new client before that client is added to the client manager.
+ // But need to know what happens in the case where a ScenePresence is already present (and if this
+ // actually occurs).
+ client.SceneAgent = sp;
+
m_log.WarnFormat(
"[SCENE]: Already found {0} scene presence for {1} in {2} when asked to add new scene presence",
sp.IsChildAgent ? "child" : "root", sp.Name, RegionInfo.RegionName);
+
+ reallyNew = false;
}
-
- // We must set this here so that TriggerOnNewClient and TriggerOnClientLogin can determine whether the
- // client is for a root or child agent.
- client.SceneAgent = sp;
- // Cache the user's name
+ // This is currently also being done earlier in NewUserConnection for real users to see if this
+ // resolves problems where HG agents are occasionally seen by others as "Unknown user" in chat and other
+ // places. However, we still need to do it here for NPCs.
CacheUserName(sp, aCircuit);
-
- EventManager.TriggerOnNewClient(client);
+
+ if (reallyNew)
+ EventManager.TriggerOnNewClient(client);
+
if (vialogin)
EventManager.TriggerOnClientLogin(client);
}
+ // User has logged into the scene so update the list of users logging
+ // in
+ StatsReporter.UpdateUsersLoggingIn(false);
+
m_LastLogin = Util.EnvironmentTickCount();
return sp;
}
///
+ /// Returns the Home URI of the agent, or null if unknown.
+ ///
+ public string GetAgentHomeURI(UUID agentID)
+ {
+ AgentCircuitData circuit = AuthenticateHandler.GetAgentCircuitData(agentID);
+ if (circuit != null && circuit.ServiceURLs != null && circuit.ServiceURLs.ContainsKey("HomeURI"))
+ return circuit.ServiceURLs["HomeURI"].ToString();
+ else
+ return null;
+ }
+
+ ///
/// Cache the user name for later use.
///
///
@@ -2849,7 +3061,7 @@ namespace OpenSim.Region.Framework.Scenes
{
string first = aCircuit.firstname, last = aCircuit.lastname;
- if (sp.PresenceType == PresenceType.Npc)
+ if (sp != null && sp.PresenceType == PresenceType.Npc)
{
UserManagementModule.AddUser(aCircuit.AgentID, first, last);
}
@@ -2878,7 +3090,7 @@ namespace OpenSim.Region.Framework.Scenes
private bool VerifyClient(AgentCircuitData aCircuit, System.Net.IPEndPoint ep, out bool vialogin)
{
vialogin = false;
-
+
// Do the verification here
if ((aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0)
{
@@ -2929,7 +3141,7 @@ namespace OpenSim.Region.Framework.Scenes
{
PresenceService.LogoutAgent(sp.ControllingClient.SessionId);
- sp.ControllingClient.Close();
+ CloseAgent(sp.UUID, false);
}
else
{
@@ -2973,7 +3185,7 @@ namespace OpenSim.Region.Framework.Scenes
{
client.OnRegionHandShakeReply += SendLayerData;
}
-
+
public virtual void SubscribeToClientPrimEvents(IClientAPI client)
{
client.OnUpdatePrimGroupPosition += m_sceneGraph.UpdatePrimGroupPosition;
@@ -2983,7 +3195,7 @@ namespace OpenSim.Region.Framework.Scenes
client.OnUpdatePrimGroupMouseRotation += m_sceneGraph.UpdatePrimGroupRotation;
client.OnUpdatePrimSingleRotation += m_sceneGraph.UpdatePrimSingleRotation;
client.OnUpdatePrimSingleRotationPosition += m_sceneGraph.UpdatePrimSingleRotationPosition;
-
+
client.OnUpdatePrimScale += m_sceneGraph.UpdatePrimScale;
client.OnUpdatePrimGroupScale += m_sceneGraph.UpdatePrimGroupScale;
client.OnUpdateExtraParams += m_sceneGraph.UpdateExtraParam;
@@ -2996,7 +3208,7 @@ namespace OpenSim.Region.Framework.Scenes
client.OnSpinStart += m_sceneGraph.SpinStart;
client.OnSpinUpdate += m_sceneGraph.SpinObject;
client.OnDeRezObject += DeRezObjects;
-
+
client.OnObjectName += m_sceneGraph.PrimName;
client.OnObjectClickAction += m_sceneGraph.PrimClickAction;
client.OnObjectMaterial += m_sceneGraph.PrimMaterial;
@@ -3008,7 +3220,7 @@ namespace OpenSim.Region.Framework.Scenes
client.OnRequestObjectPropertiesFamily += m_sceneGraph.RequestObjectPropertiesFamily;
client.OnObjectPermissions += HandleObjectPermissionsUpdate;
client.OnGrabObject += ProcessObjectGrab;
- client.OnGrabUpdate += ProcessObjectGrabUpdate;
+ client.OnGrabUpdate += ProcessObjectGrabUpdate;
client.OnDeGrabObject += ProcessObjectDeGrab;
client.OnUndo += m_sceneGraph.HandleUndo;
client.OnRedo += m_sceneGraph.HandleRedo;
@@ -3068,10 +3280,8 @@ namespace OpenSim.Region.Framework.Scenes
{
//client.OnNameFromUUIDRequest += HandleUUIDNameRequest;
client.OnMoneyTransferRequest += ProcessMoneyTransferRequest;
- client.OnSetStartLocationRequest += SetHomeRezPoint;
- client.OnRegionHandleRequest += RegionHandleRequest;
}
-
+
public virtual void SubscribeToClientNetworkEvents(IClientAPI client)
{
client.OnNetworkStatsUpdate += StatsReporter.AddPacketsStats;
@@ -3193,8 +3403,6 @@ namespace OpenSim.Region.Framework.Scenes
{
//client.OnNameFromUUIDRequest -= HandleUUIDNameRequest;
client.OnMoneyTransferRequest -= ProcessMoneyTransferRequest;
- client.OnSetStartLocationRequest -= SetHomeRezPoint;
- client.OnRegionHandleRequest -= RegionHandleRequest;
}
public virtual void UnSubscribeToClientNetworkEvents(IClientAPI client)
@@ -3208,17 +3416,18 @@ namespace OpenSim.Region.Framework.Scenes
///
/// The avatar's Unique ID
/// The IClientAPI for the client
- public virtual void TeleportClientHome(UUID agentId, IClientAPI client)
+ public virtual bool TeleportClientHome(UUID agentId, IClientAPI client)
{
if (EntityTransferModule != null)
{
- EntityTransferModule.TeleportHome(agentId, client);
+ return EntityTransferModule.TeleportHome(agentId, client);
}
else
{
m_log.DebugFormat("[SCENE]: Unable to teleport user home: no AgentTransferModule is active");
client.SendTeleportFailed("Unable to perform teleports on this simulator.");
}
+ return false;
}
///
@@ -3264,8 +3473,8 @@ namespace OpenSim.Region.Framework.Scenes
if (target != null && target2 != null)
{
Vector3 direction = Vector3.Normalize(RayEnd - RayStart);
- Vector3 AXOrigin = new Vector3(RayStart.X, RayStart.Y, RayStart.Z);
- Vector3 AXdirection = new Vector3(direction.X, direction.Y, direction.Z);
+ Vector3 AXOrigin = RayStart;
+ Vector3 AXdirection = direction;
pos = target2.AbsolutePosition;
//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());
@@ -3286,13 +3495,13 @@ namespace OpenSim.Region.Framework.Scenes
if (ei.HitTF)
{
Vector3 scale = target.Scale;
- Vector3 scaleComponent = new Vector3(ei.AAfaceNormal.X, ei.AAfaceNormal.Y, ei.AAfaceNormal.Z);
+ Vector3 scaleComponent = ei.AAfaceNormal;
if (scaleComponent.X != 0) ScaleOffset = scale.X;
if (scaleComponent.Y != 0) ScaleOffset = scale.Y;
if (scaleComponent.Z != 0) ScaleOffset = scale.Z;
ScaleOffset = Math.Abs(ScaleOffset);
- Vector3 intersectionpoint = new Vector3(ei.ipoint.X, ei.ipoint.Y, ei.ipoint.Z);
- Vector3 normal = new Vector3(ei.normal.X, ei.normal.Y, ei.normal.Z);
+ Vector3 intersectionpoint = ei.ipoint;
+ Vector3 normal = ei.normal;
Vector3 offset = normal * (ScaleOffset / 2f);
pos = intersectionpoint + offset;
@@ -3312,6 +3521,7 @@ namespace OpenSim.Region.Framework.Scenes
{
copy = m_sceneGraph.DuplicateObject(localID, pos, target.GetEffectiveObjectFlags(), AgentID, GroupID, Quaternion.Identity);
}
+
if (copy != null)
EventManager.TriggerObjectAddedToScene(copy);
}
@@ -3319,24 +3529,7 @@ namespace OpenSim.Region.Framework.Scenes
}
///
- /// Sets the Home Point. The LoginService uses this to know where to put a user when they log-in
- ///
- ///
- ///
- ///
- ///
- ///
- public virtual void SetHomeRezPoint(IClientAPI remoteClient, ulong regionHandle, Vector3 position, Vector3 lookAt, uint flags)
- {
- if (GridUserService != null && GridUserService.SetHome(remoteClient.AgentId.ToString(), RegionInfo.RegionID, position, lookAt))
- // FUBAR ALERT: this needs to be "Home position set." so the viewer saves a home-screenshot.
- m_dialogModule.SendAlertToUser(remoteClient, "Home position set.");
- else
- m_dialogModule.SendAlertToUser(remoteClient, "Set Home request Failed.");
- }
-
- ///
- /// Get the avatar apperance for the given client.
+ /// Get the avatar appearance for the given client.
///
///
///
@@ -3359,93 +3552,93 @@ namespace OpenSim.Region.Framework.Scenes
}
}
- public override void RemoveClient(UUID agentID, bool closeChildAgents)
+ ///
+ /// Remove the given client from the scene.
+ ///
+ ///
+ /// Only clientstack code should call this directly. All other code should call IncomingCloseAgent() instead
+ /// to properly operate the state machine and avoid race conditions with other close requests (such as directly
+ /// from viewers).
+ ///
+ /// ID of agent to close
+ ///
+ /// Close the neighbour child agents associated with this client.
+ ///
+ public void RemoveClient(UUID agentID, bool closeChildAgents)
{
-// CheckHeartbeat();
- bool isChildAgent = false;
- AgentCircuitData acd;
+ AgentCircuitData acd = m_authenticateHandler.GetAgentCircuitData(agentID);
- lock (m_removeClientLock)
+ // Shouldn't be necessary since RemoveClient() is currently only called by IClientAPI.Close() which
+ // in turn is only called by Scene.IncomingCloseAgent() which checks whether the presence exists or not
+ // However, will keep for now just in case.
+ if (acd == null)
{
- acd = m_authenticateHandler.GetAgentCircuitData(agentID);
+ m_log.ErrorFormat(
+ "[SCENE]: No agent circuit found for {0} in {1}, aborting Scene.RemoveClient", agentID, Name);
- if (acd == null)
- {
- m_log.ErrorFormat("[SCENE]: No agent circuit found for {0}, aborting Scene.RemoveClient", agentID);
- return;
- }
- else
- {
- // We remove the acd up here to avoid later race conditions if two RemoveClient() calls occurred
- // simultaneously.
- // We also need to remove by agent ID since NPCs will have no circuit code.
- m_authenticateHandler.RemoveCircuit(agentID);
- }
+ return;
}
+ // TODO: Can we now remove this lock?
lock (acd)
{
+ bool isChildAgent = false;
+
ScenePresence avatar = GetScenePresence(agentID);
-
+
+ // Shouldn't be necessary since RemoveClient() is currently only called by IClientAPI.Close() which
+ // in turn is only called by Scene.IncomingCloseAgent() which checks whether the presence exists or not
+ // However, will keep for now just in case.
if (avatar == null)
{
- m_log.WarnFormat(
+ m_log.ErrorFormat(
"[SCENE]: Called RemoveClient() with agent ID {0} but no such presence is in the scene.", agentID);
-
+ m_authenticateHandler.RemoveCircuit(agentID);
+
return;
}
-
+
try
{
isChildAgent = avatar.IsChildAgent;
m_log.DebugFormat(
"[SCENE]: Removing {0} agent {1} {2} from {3}",
- (isChildAgent ? "child" : "root"), avatar.Name, agentID, RegionInfo.RegionName);
-
+ isChildAgent ? "child" : "root", avatar.Name, agentID, Name);
+
// Don't do this to root agents, it's not nice for the viewer
if (closeChildAgents && isChildAgent)
{
// Tell a single agent to disconnect from the region.
- IEventQueue eq = RequestModuleInterface();
- if (eq != null)
- {
- eq.DisableSimulator(RegionInfo.RegionHandle, avatar.UUID);
- }
- else
- {
- avatar.ControllingClient.SendShutdownConnectionNotice();
- }
+ // Let's do this via UDP
+ avatar.ControllingClient.SendShutdownConnectionNotice();
}
-
+
// Only applies to root agents.
if (avatar.ParentID != 0)
{
avatar.StandUp();
}
-
+
m_sceneGraph.removeUserCount(!isChildAgent);
-
+
// TODO: We shouldn't use closeChildAgents here - it's being used by the NPC module to stop
// unnecessary operations. This should go away once NPCs have no accompanying IClientAPI
if (closeChildAgents && CapsModule != null)
CapsModule.RemoveCaps(agentID);
-
-// // REFACTORING PROBLEM -- well not really a problem, but just to point out that whatever
-// // this method is doing is HORRIBLE!!!
- // Commented pending deletion since this method no longer appears to do anything at all
-// avatar.Scene.NeedSceneCacheClear(avatar.UUID);
-
+
if (closeChildAgents && !isChildAgent)
{
List regions = avatar.KnownRegionHandles;
regions.Remove(RegionInfo.RegionHandle);
- m_sceneGridService.SendCloseChildAgentConnections(agentID, regions);
+
+ // This ends up being done asynchronously so that a logout isn't held up where there are many present but unresponsive neighbours.
+ m_sceneGridService.SendCloseChildAgentConnections(agentID, acd.SessionID.ToString(), regions);
}
-
+
m_eventManager.TriggerClientClosed(agentID, this);
m_eventManager.TriggerOnRemovePresence(agentID);
-
+
if (!isChildAgent)
{
if (AttachmentsModule != null)
@@ -3457,11 +3650,11 @@ namespace OpenSim.Region.Framework.Scenes
delegate(IClientAPI client)
{
//We can safely ignore null reference exceptions. It means the avatar is dead and cleaned up anyway
- try { client.SendKillObject(avatar.RegionHandle, new List { avatar.LocalId }); }
+ try { client.SendKillObject(new List { avatar.LocalId }); }
catch (NullReferenceException) { }
});
}
-
+
// It's possible for child agents to have transactions if changes are being made cross-border.
if (AgentTransactionsModule != null)
AgentTransactionsModule.RemoveAgentAssetTransactions(agentID);
@@ -3478,9 +3671,10 @@ namespace OpenSim.Region.Framework.Scenes
// Always clean these structures up so that any failure above doesn't cause them to remain in the
// scene with possibly bad effects (e.g. continually timing out on unacked packets and triggering
// the same cleanup exception continually.
+ m_authenticateHandler.RemoveCircuit(agentID);
m_sceneGraph.RemoveScenePresence(agentID);
m_clientManager.Remove(agentID);
-
+
avatar.Close();
}
catch (Exception e)
@@ -3537,7 +3731,8 @@ namespace OpenSim.Region.Framework.Scenes
}
deleteIDs.Add(localID);
}
- ForEachClient(delegate(IClientAPI client) { client.SendKillObject(m_regionHandle, deleteIDs); });
+
+ ForEachClient(c => c.SendKillObject(deleteIDs));
}
#endregion
@@ -3549,12 +3744,13 @@ namespace OpenSim.Region.Framework.Scenes
///
/// CircuitData of the agent who is connecting
///
+ /// Source region (may be null)
/// Outputs the reason for the false response on this string
/// True if the region accepts this agent. False if it does not. False will
/// also return a reason.
- public bool NewUserConnection(AgentCircuitData agent, uint teleportFlags, out string reason)
+ public bool NewUserConnection(AgentCircuitData agent, uint teleportFlags, GridRegion source, out string reason)
{
- return NewUserConnection(agent, teleportFlags, out reason, true);
+ return NewUserConnection(agent, teleportFlags, source, out reason, true);
}
///
@@ -3573,13 +3769,14 @@ namespace OpenSim.Region.Framework.Scenes
/// is activated later when the viewer sends the initial UseCircuitCodePacket UDP packet (in the case of
/// the LLUDP stack).
///
- /// CircuitData of the agent who is connecting
+ /// CircuitData of the agent who is connecting
+ /// Source region (may be null)
/// Outputs the reason for the false response on this string
/// True for normal presence. False for NPC
/// or other applications where a full grid/Hypergrid presence may not be required.
/// True if the region accepts this agent. False if it does not. False will
/// also return a reason.
- public bool NewUserConnection(AgentCircuitData agent, uint teleportFlags, out string reason, bool requirePresenceLookup)
+ public bool NewUserConnection(AgentCircuitData acd, uint teleportFlags, GridRegion source, out string reason, bool requirePresenceLookup)
{
bool vialogin = ((teleportFlags & (uint)TPFlags.ViaLogin) != 0 ||
(teleportFlags & (uint)TPFlags.ViaHGLogin) != 0);
@@ -3596,18 +3793,20 @@ namespace OpenSim.Region.Framework.Scenes
// TeleportFlags.ViaLandmark | TeleportFlags.ViaLocation | TeleportFlags.ViaLandmark | TeleportFlags.Default - Regular Teleport
// Don't disable this log message - it's too helpful
+ string curViewer = Util.GetViewerName(acd);
m_log.DebugFormat(
- "[SCENE]: Region {0} told of incoming {1} agent {2} {3} {4} (circuit code {5}, IP {6}, viewer {7}, teleportflags ({8}), position {9})",
+ "[SCENE]: Region {0} told of incoming {1} agent {2} {3} {4} (circuit code {5}, IP {6}, viewer {7}, teleportflags ({8}), position {9}. {10}",
RegionInfo.RegionName,
- (agent.child ? "child" : "root"),
- agent.firstname,
- agent.lastname,
- agent.AgentID,
- agent.circuitcode,
- agent.IPAddress,
- agent.Viewer,
+ (acd.child ? "child" : "root"),
+ acd.firstname,
+ acd.lastname,
+ acd.AgentID,
+ acd.circuitcode,
+ acd.IPAddress,
+ curViewer,
((TPFlags)teleportFlags).ToString(),
- agent.startpos
+ acd.startpos,
+ (source == null) ? "" : string.Format("From region {0} ({1}){2}", source.RegionName, source.RegionID, (source.RawServerURI == null) ? "" : " @ " + source.ServerURI)
);
if (!LoginsEnabled)
@@ -3625,7 +3824,7 @@ namespace OpenSim.Region.Framework.Scenes
{
foreach (string viewer in m_AllowedViewers)
{
- if (viewer == agent.Viewer.Substring(0, viewer.Length).Trim().ToLower())
+ if (viewer == curViewer.Substring(0, Math.Min(viewer.Length, curViewer.Length)).Trim().ToLower())
{
ViewerDenied = false;
break;
@@ -3642,7 +3841,7 @@ namespace OpenSim.Region.Framework.Scenes
{
foreach (string viewer in m_BannedViewers)
{
- if (viewer == agent.Viewer.Substring(0, viewer.Length).Trim().ToLower())
+ if (viewer == curViewer.Substring(0, Math.Min(viewer.Length, curViewer.Length)).Trim().ToLower())
{
ViewerDenied = true;
break;
@@ -3654,81 +3853,178 @@ namespace OpenSim.Region.Framework.Scenes
{
m_log.DebugFormat(
"[SCENE]: Access denied for {0} {1} using {2}",
- agent.firstname, agent.lastname, agent.Viewer);
+ acd.firstname, acd.lastname, curViewer);
reason = "Access denied, your viewer is banned by the region owner";
return false;
}
ILandObject land;
+ ScenePresence sp;
- lock (agent)
+ lock (m_removeClientLock)
{
- ScenePresence sp = GetScenePresence(agent.AgentID);
-
- if (sp != null && !sp.IsChildAgent)
+ sp = GetScenePresence(acd.AgentID);
+
+ // We need to ensure that we are not already removing the scene presence before we ask it not to be
+ // closed.
+ if (sp != null && sp.IsChildAgent
+ && (sp.LifecycleState == ScenePresenceState.Running
+ || sp.LifecycleState == ScenePresenceState.PreRemove))
+ {
+ m_log.DebugFormat(
+ "[SCENE]: Reusing existing child scene presence for {0}, state {1} in {2}",
+ sp.Name, sp.LifecycleState, Name);
+
+ // In the case where, for example, an A B C D region layout, an avatar may
+ // teleport from A -> D, but then -> C before A has asked B to close its old child agent. When C
+ // renews the lease on the child agent at B, we must make sure that the close from A does not succeed.
+ //
+ // XXX: In the end, this should not be necessary if child agents are closed without delay on
+ // teleport, since realistically, the close request should always be processed before any other
+ // region tried to re-establish a child agent. This is much simpler since the logic below is
+ // vulnerable to an issue when a viewer quits a region without sending a proper logout but then
+ // re-establishes the connection on a relogin. This could wrongly set the DoNotCloseAfterTeleport
+ // flag when no teleport had taken place (and hence no close was going to come).
+// if (!acd.ChildrenCapSeeds.ContainsKey(RegionInfo.RegionHandle))
+// {
+// m_log.DebugFormat(
+// "[SCENE]: Setting DoNotCloseAfterTeleport for child scene presence {0} in {1} because source will attempt close.",
+// sp.Name, Name);
+//
+// sp.DoNotCloseAfterTeleport = true;
+// }
+// else if (EntityTransferModule.IsInTransit(sp.UUID))
+
+ sp.LifecycleState = ScenePresenceState.Running;
+
+ if (EntityTransferModule.IsInTransit(sp.UUID))
+ {
+ sp.DoNotCloseAfterTeleport = true;
+
+ m_log.DebugFormat(
+ "[SCENE]: Set DoNotCloseAfterTeleport for child scene presence {0} in {1} because this region will attempt end-of-teleport close from a previous close.",
+ sp.Name, Name);
+ }
+ }
+ }
+
+ // Need to poll here in case we are currently deleting an sp. Letting threads run over each other will
+ // allow unpredictable things to happen.
+ if (sp != null)
+ {
+ const int polls = 10;
+ const int pollInterval = 1000;
+ int pollsLeft = polls;
+
+ while (sp.LifecycleState == ScenePresenceState.Removing && pollsLeft-- > 0)
+ Thread.Sleep(pollInterval);
+
+ if (sp.LifecycleState == ScenePresenceState.Removing)
{
- // We have a zombie from a crashed session.
- // Or the same user is trying to be root twice here, won't work.
- // Kill it.
m_log.WarnFormat(
- "[SCENE]: Existing root scene presence detected for {0} {1} in {2} when connecting. Removing existing presence.",
- sp.Name, sp.UUID, RegionInfo.RegionName);
-
- sp.ControllingClient.Close(true);
- sp = null;
- }
-
- land = LandChannel.GetLandObject(agent.startpos.X, agent.startpos.Y);
-
- //On login test land permisions
+ "[SCENE]: Agent {0} in {1} was still being removed after {2}s. Aborting NewUserConnection.",
+ sp.Name, Name, polls * pollInterval / 1000);
+
+ return false;
+ }
+ else if (polls != pollsLeft)
+ {
+ m_log.DebugFormat(
+ "[SCENE]: NewUserConnection for agent {0} in {1} had to wait {2}s for in-progress removal to complete on an old presence.",
+ sp.Name, Name, polls * pollInterval / 1000);
+ }
+ }
+
+ // TODO: can we remove this lock?
+ lock (acd)
+ {
+ if (sp != null && !sp.IsChildAgent)
+ {
+ // We have a root agent. Is it in transit?
+ if (!EntityTransferModule.IsInTransit(sp.UUID))
+ {
+ // We have a zombie from a crashed session.
+ // Or the same user is trying to be root twice here, won't work.
+ // Kill it.
+ m_log.WarnFormat(
+ "[SCENE]: Existing root scene presence detected for {0} {1} in {2} when connecting. Removing existing presence.",
+ sp.Name, sp.UUID, RegionInfo.RegionName);
+
+ if (sp.ControllingClient != null)
+ CloseAgent(sp.UUID, true);
+
+ sp = null;
+ }
+ //else
+ // m_log.WarnFormat("[SCENE]: Existing root scene presence for {0} {1} in {2}, but agent is in trasit", sp.Name, sp.UUID, RegionInfo.RegionName);
+ }
+
+ // Optimistic: add or update the circuit data with the new agent circuit data and teleport flags.
+ // We need the circuit data here for some of the subsequent checks. (groups, for example)
+ // If the checks fail, we remove the circuit.
+ acd.teleportFlags = teleportFlags;
+ m_authenticateHandler.AddNewCircuit(acd.circuitcode, acd);
+
+ land = LandChannel.GetLandObject(acd.startpos.X, acd.startpos.Y);
+
+ // On login test land permisions
if (vialogin)
{
- if (land != null && !TestLandRestrictions(agent, land, out reason))
+ if (land != null && !TestLandRestrictions(acd.AgentID, out reason, ref acd.startpos.X, ref acd.startpos.Y))
{
+ m_authenticateHandler.RemoveCircuit(acd.circuitcode);
return false;
}
}
-
+
if (sp == null) // We don't have an [child] agent here already
{
if (requirePresenceLookup)
{
try
{
- if (!VerifyUserPresence(agent, out reason))
+ if (!VerifyUserPresence(acd, out reason))
+ {
+ m_authenticateHandler.RemoveCircuit(acd.circuitcode);
return false;
+ }
}
catch (Exception e)
{
m_log.ErrorFormat(
"[SCENE]: Exception verifying presence {0}{1}", e.Message, e.StackTrace);
+ m_authenticateHandler.RemoveCircuit(acd.circuitcode);
return false;
}
}
-
+
try
{
- if (!AuthorizeUser(agent, out reason))
+ if (!AuthorizeUser(acd, (vialogin ? false : SeeIntoRegion), out reason))
+ {
+ m_authenticateHandler.RemoveCircuit(acd.circuitcode);
return false;
+ }
}
catch (Exception e)
{
m_log.ErrorFormat(
"[SCENE]: Exception authorizing user {0}{1}", e.Message, e.StackTrace);
+ m_authenticateHandler.RemoveCircuit(acd.circuitcode);
return false;
}
-
+
m_log.InfoFormat(
"[SCENE]: Region {0} authenticated and authorized incoming {1} agent {2} {3} {4} (circuit code {5})",
- RegionInfo.RegionName, (agent.child ? "child" : "root"), agent.firstname, agent.lastname,
- agent.AgentID, agent.circuitcode);
-
+ Name, (acd.child ? "child" : "root"), acd.firstname, acd.lastname,
+ acd.AgentID, acd.circuitcode);
+
if (CapsModule != null)
{
- CapsModule.SetAgentCapsSeeds(agent);
- CapsModule.CreateCaps(agent.AgentID);
+ CapsModule.SetAgentCapsSeeds(acd);
+ CapsModule.CreateCaps(acd.AgentID);
}
}
else
@@ -3736,83 +4032,42 @@ namespace OpenSim.Region.Framework.Scenes
// Let the SP know how we got here. This has a lot of interesting
// uses down the line.
sp.TeleportFlags = (TPFlags)teleportFlags;
-
+
if (sp.IsChildAgent)
{
m_log.DebugFormat(
"[SCENE]: Adjusting known seeds for existing agent {0} in {1}",
- agent.AgentID, RegionInfo.RegionName);
-
+ acd.AgentID, RegionInfo.RegionName);
+
sp.AdjustKnownSeeds();
-
+
if (CapsModule != null)
- CapsModule.SetAgentCapsSeeds(agent);
+ {
+ CapsModule.SetAgentCapsSeeds(acd);
+ CapsModule.CreateCaps(acd.AgentID);
+ }
}
}
- }
- // In all cases, add or update the circuit data with the new agent circuit data and teleport flags
- agent.teleportFlags = teleportFlags;
- m_authenticateHandler.AddNewCircuit(agent.circuitcode, agent);
+ // Try caching an incoming user name much earlier on to see if this helps with an issue
+ // where HG users are occasionally seen by others as "Unknown User" because their UUIDName
+ // request for the HG avatar appears to trigger before the user name is cached.
+ CacheUserName(null, acd);
+ }
if (vialogin)
{
// CleanDroppedAttachments();
- if (TestBorderCross(agent.startpos, Cardinals.E))
- {
- Border crossedBorder = GetCrossedBorder(agent.startpos, Cardinals.E);
- agent.startpos.X = crossedBorder.BorderLine.Z - 1;
- }
+ // Make sure avatar position is in the region (why it wouldn't be is a mystery but do sanity checking)
+ if (acd.startpos.X < 0) acd.startpos.X = 1f;
+ if (acd.startpos.X >= RegionInfo.RegionSizeX) acd.startpos.X = RegionInfo.RegionSizeX - 1f;
+ if (acd.startpos.Y < 0) acd.startpos.Y = 1f;
+ if (acd.startpos.Y >= RegionInfo.RegionSizeY) acd.startpos.Y = RegionInfo.RegionSizeY - 1f;
- if (TestBorderCross(agent.startpos, Cardinals.N))
- {
- Border crossedBorder = GetCrossedBorder(agent.startpos, Cardinals.N);
- agent.startpos.Y = crossedBorder.BorderLine.Z - 1;
- }
-
- //Mitigate http://opensimulator.org/mantis/view.php?id=3522
- // Check if start position is outside of region
- // If it is, check the Z start position also.. if not, leave it alone.
- if (BordersLocked)
- {
- lock (EastBorders)
- {
- if (agent.startpos.X > EastBorders[0].BorderLine.Z)
- {
- m_log.Warn("FIX AGENT POSITION");
- agent.startpos.X = EastBorders[0].BorderLine.Z * 0.5f;
- if (agent.startpos.Z > 720)
- agent.startpos.Z = 720;
- }
- }
- lock (NorthBorders)
- {
- if (agent.startpos.Y > NorthBorders[0].BorderLine.Z)
- {
- m_log.Warn("FIX Agent POSITION");
- agent.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f;
- if (agent.startpos.Z > 720)
- agent.startpos.Z = 720;
- }
- }
- } else
- {
- if (agent.startpos.X > EastBorders[0].BorderLine.Z)
- {
- m_log.Warn("FIX AGENT POSITION");
- agent.startpos.X = EastBorders[0].BorderLine.Z * 0.5f;
- if (agent.startpos.Z > 720)
- agent.startpos.Z = 720;
- }
- if (agent.startpos.Y > NorthBorders[0].BorderLine.Z)
- {
- m_log.Warn("FIX Agent POSITION");
- agent.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f;
- if (agent.startpos.Z > 720)
- agent.startpos.Z = 720;
- }
- }
+// m_log.DebugFormat(
+// "[SCENE]: Found telehub object {0} for new user connection {1} to {2}",
+// RegionInfo.RegionSettings.TelehubObject, acd.Name, Name);
// Honor Estate teleport routing via Telehubs excluding ViaHome and GodLike TeleportFlags
if (RegionInfo.RegionSettings.TelehubObject != UUID.Zero &&
@@ -3820,26 +4075,49 @@ namespace OpenSim.Region.Framework.Scenes
!viahome && !godlike)
{
SceneObjectGroup telehub = GetSceneObjectGroup(RegionInfo.RegionSettings.TelehubObject);
- // Can have multiple SpawnPoints
- List spawnpoints = RegionInfo.RegionSettings.SpawnPoints();
- if (spawnpoints.Count > 1)
+
+ if (telehub != null)
{
- // We have multiple SpawnPoints, Route the agent to a random or sequential one
- if (SpawnPointRouting == "random")
- agent.startpos = spawnpoints[Util.RandomClass.Next(spawnpoints.Count) - 1].GetLocation(
- telehub.AbsolutePosition,
- telehub.GroupRotation
- );
+ // Can have multiple SpawnPoints
+ List spawnpoints = RegionInfo.RegionSettings.SpawnPoints();
+ if (spawnpoints.Count > 1)
+ {
+ // We have multiple SpawnPoints, Route the agent to a random or sequential one
+ if (SpawnPointRouting == "random")
+ acd.startpos = spawnpoints[Util.RandomClass.Next(spawnpoints.Count) - 1].GetLocation(
+ telehub.AbsolutePosition,
+ telehub.GroupRotation
+ );
+ else
+ acd.startpos = spawnpoints[SpawnPoint()].GetLocation(
+ telehub.AbsolutePosition,
+ telehub.GroupRotation
+ );
+ }
+ else if (spawnpoints.Count == 1)
+ {
+ // We have a single SpawnPoint and will route the agent to it
+ acd.startpos = spawnpoints[0].GetLocation(telehub.AbsolutePosition, telehub.GroupRotation);
+ }
else
- agent.startpos = spawnpoints[SpawnPoint()].GetLocation(
- telehub.AbsolutePosition,
- telehub.GroupRotation
- );
+ {
+ m_log.DebugFormat(
+ "[SCENE]: No spawnpoints defined for telehub {0} for {1} in {2}. Continuing.",
+ RegionInfo.RegionSettings.TelehubObject, acd.Name, Name);
+ }
}
else
{
- // We have a single SpawnPoint and will route the agent to it
- agent.startpos = spawnpoints[0].GetLocation(telehub.AbsolutePosition, telehub.GroupRotation);
+ m_log.DebugFormat(
+ "[SCENE]: No telehub {0} found to direct {1} in {2}. Continuing.",
+ RegionInfo.RegionSettings.TelehubObject, acd.Name, Name);
+ }
+
+ // Final permissions check; this time we don't allow changing the position
+ if (!IsPositionAllowed(acd.AgentID, acd.startpos, ref reason))
+ {
+ m_authenticateHandler.RemoveCircuit(acd.circuitcode);
+ return false;
}
return true;
@@ -3850,7 +4128,14 @@ namespace OpenSim.Region.Framework.Scenes
{
if (land.LandData.LandingType == (byte)1 && land.LandData.UserLocation != Vector3.Zero)
{
- agent.startpos = land.LandData.UserLocation;
+ acd.startpos = land.LandData.UserLocation;
+
+ // Final permissions check; this time we don't allow changing the position
+ if (!IsPositionAllowed(acd.AgentID, acd.startpos, ref reason))
+ {
+ m_authenticateHandler.RemoveCircuit(acd.circuitcode);
+ return false;
+ }
}
}
}
@@ -3858,20 +4143,52 @@ namespace OpenSim.Region.Framework.Scenes
return true;
}
- private bool TestLandRestrictions(AgentCircuitData agent, ILandObject land, out string reason)
+ private bool IsPositionAllowed(UUID agentID, Vector3 pos, ref string reason)
{
- bool banned = land.IsBannedFromLand(agent.AgentID);
- bool restricted = land.IsRestrictedFromLand(agent.AgentID);
+ ILandObject land = LandChannel.GetLandObject(pos);
+ if (land == null)
+ return true;
+
+ if (land.IsBannedFromLand(agentID) || land.IsRestrictedFromLand(agentID))
+ {
+ reason = "You are banned from the region.";
+ return false;
+ }
+
+ return true;
+ }
+
+ public bool TestLandRestrictions(UUID agentID, out string reason, ref float posX, ref float posY)
+ {
+ if (posX < 0)
+ posX = 0;
+ else if (posX >= (float)RegionInfo.RegionSizeX)
+ posX = (float)RegionInfo.RegionSizeX - 0.001f;
+ if (posY < 0)
+ posY = 0;
+ else if (posY >= (float)RegionInfo.RegionSizeY)
+ posY = (float)RegionInfo.RegionSizeY - 0.001f;
+
+ reason = String.Empty;
+ if (Permissions.IsGod(agentID))
+ return true;
+
+ ILandObject land = LandChannel.GetLandObject(posX, posY);
+ if (land == null)
+ return false;
+
+ bool banned = land.IsBannedFromLand(agentID);
+ bool restricted = land.IsRestrictedFromLand(agentID);
if (banned || restricted)
{
- ILandObject nearestParcel = GetNearestAllowedParcel(agent.AgentID, agent.startpos.X, agent.startpos.Y);
+ ILandObject nearestParcel = GetNearestAllowedParcel(agentID, posX, posY);
if (nearestParcel != null)
{
//Move agent to nearest allowed
Vector3 newPosition = GetParcelCenterAtGround(nearestParcel);
- agent.startpos.X = newPosition.X;
- agent.startpos.Y = newPosition.Y;
+ posX = newPosition.X;
+ posY = newPosition.Y;
}
else
{
@@ -3882,7 +4199,7 @@ namespace OpenSim.Region.Framework.Scenes
else
{
reason = String.Format("Denied access to private region {0}: You are not on the access list for that region.",
- RegionInfo.RegionName);
+ RegionInfo.RegionName);
}
return false;
}
@@ -3927,86 +4244,93 @@ namespace OpenSim.Region.Framework.Scenes
/// outputs the reason to this string
/// True if the region accepts this agent. False if it does not. False will
/// also return a reason.
- protected virtual bool AuthorizeUser(AgentCircuitData agent, out string reason)
+ protected virtual bool AuthorizeUser(AgentCircuitData agent, bool bypassAccessControl, out string reason)
{
reason = String.Empty;
if (!m_strictAccessControl) return true;
if (Permissions.IsGod(agent.AgentID)) return true;
-
+
if (AuthorizationService != null)
{
if (!AuthorizationService.IsAuthorizedForRegion(
agent.AgentID.ToString(), agent.firstname, agent.lastname, RegionInfo.RegionID.ToString(), out reason))
{
- m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because {4}",
+ m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because: {4}",
agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName, reason);
-
- return false;
- }
- }
- if (RegionInfo.EstateSettings != null)
- {
- if (RegionInfo.EstateSettings.IsBanned(agent.AgentID))
- {
- m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user is on the banlist",
- agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName);
- reason = String.Format("Denied access to region {0}: You have been banned from that region.",
- RegionInfo.RegionName);
return false;
}
}
- else
- {
- m_log.ErrorFormat("[CONNECTION BEGIN]: Estate Settings is null!");
- }
- List agentGroups = new List();
-
- if (m_groupsModule != null)
+ // We only test the things below when we want to cut off
+ // child agents from being present in the scene for which their root
+ // agent isn't allowed. Otherwise, we allow child agents. The test for
+ // the root is done elsewhere (QueryAccess)
+ if (!bypassAccessControl)
{
- GroupMembershipData[] GroupMembership = m_groupsModule.GetMembershipData(agent.AgentID);
-
- if (GroupMembership != null)
+ if (RegionInfo.EstateSettings != null)
{
- for (int i = 0; i < GroupMembership.Length; i++)
- agentGroups.Add(GroupMembership[i].GroupID);
+ if (RegionInfo.EstateSettings.IsBanned(agent.AgentID))
+ {
+ m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user is on the banlist",
+ agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName);
+ reason = String.Format("Denied access to region {0}: You have been banned from that region.",
+ RegionInfo.RegionName);
+ return false;
+ }
}
else
{
- m_log.ErrorFormat("[CONNECTION BEGIN]: GroupMembership is null!");
+ m_log.ErrorFormat("[CONNECTION BEGIN]: Estate Settings is null!");
}
- }
- bool groupAccess = false;
- UUID[] estateGroups = RegionInfo.EstateSettings.EstateGroups;
+ List agentGroups = new List();
- if (estateGroups != null)
- {
- foreach (UUID group in estateGroups)
+ if (m_groupsModule != null)
{
- if (agentGroups.Contains(group))
+ GroupMembershipData[] GroupMembership = m_groupsModule.GetMembershipData(agent.AgentID);
+
+ if (GroupMembership != null)
{
- groupAccess = true;
- break;
+ for (int i = 0; i < GroupMembership.Length; i++)
+ agentGroups.Add(GroupMembership[i].GroupID);
+ }
+ else
+ {
+ m_log.ErrorFormat("[CONNECTION BEGIN]: GroupMembership is null!");
}
}
- }
- else
- {
- m_log.ErrorFormat("[CONNECTION BEGIN]: EstateGroups is null!");
- }
- if (!RegionInfo.EstateSettings.PublicAccess &&
- !RegionInfo.EstateSettings.HasAccess(agent.AgentID) &&
- !groupAccess)
- {
- m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user does not have access to the estate",
- agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName);
- reason = String.Format("Denied access to private region {0}: You are not on the access list for that region.",
- RegionInfo.RegionName);
- return false;
+ bool groupAccess = false;
+ UUID[] estateGroups = RegionInfo.EstateSettings.EstateGroups;
+
+ if (estateGroups != null)
+ {
+ foreach (UUID group in estateGroups)
+ {
+ if (agentGroups.Contains(group))
+ {
+ groupAccess = true;
+ break;
+ }
+ }
+ }
+ else
+ {
+ m_log.ErrorFormat("[CONNECTION BEGIN]: EstateGroups is null!");
+ }
+
+ if (!RegionInfo.EstateSettings.PublicAccess &&
+ !RegionInfo.EstateSettings.HasAccess(agent.AgentID) &&
+ !groupAccess)
+ {
+ m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user does not have access to the estate",
+ agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName);
+ reason = String.Format("Denied access to private region {0}: You are not on the access list for that region.",
+ RegionInfo.RegionName);
+ return false;
+ }
}
// TODO: estate/region settings are not properly hooked up
@@ -4096,33 +4420,33 @@ namespace OpenSim.Region.Framework.Scenes
// }
// }
- ///
- /// Triggered when an agent crosses into this sim. Also happens on initial login.
- ///
- ///
- ///
- ///
- public virtual void AgentCrossing(UUID agentID, Vector3 position, bool isFlying)
- {
- ScenePresence presence = GetScenePresence(agentID);
- if (presence != null)
- {
- try
- {
- presence.MakeRootAgent(position, isFlying);
- }
- catch (Exception e)
- {
- m_log.ErrorFormat("[SCENE]: Unable to do agent crossing, exception {0}{1}", e.Message, e.StackTrace);
- }
- }
- else
- {
- m_log.ErrorFormat(
- "[SCENE]: Could not find presence for agent {0} crossing into scene {1}",
- agentID, RegionInfo.RegionName);
- }
- }
+// ///
+// /// Triggered when an agent crosses into this sim. Also happens on initial login.
+// ///
+// ///
+// ///
+// ///
+// public virtual void AgentCrossing(UUID agentID, Vector3 position, bool isFlying)
+// {
+// ScenePresence presence = GetScenePresence(agentID);
+// if (presence != null)
+// {
+// try
+// {
+// presence.MakeRootAgent(position, isFlying);
+// }
+// catch (Exception e)
+// {
+// m_log.ErrorFormat("[SCENE]: Unable to do agent crossing, exception {0}{1}", e.Message, e.StackTrace);
+// }
+// }
+// else
+// {
+// m_log.ErrorFormat(
+// "[SCENE]: Could not find presence for agent {0} crossing into scene {1}",
+// agentID, RegionInfo.RegionName);
+// }
+// }
///
/// We've got an update about an agent that sees into this region,
@@ -4131,18 +4455,16 @@ namespace OpenSim.Region.Framework.Scenes
/// Agent that contains all of the relevant things about an agent.
/// Appearance, animations, position, etc.
/// true if we handled it.
- public virtual bool IncomingChildAgentDataUpdate(AgentData cAgentData)
+ public virtual bool IncomingUpdateChildAgent(AgentData cAgentData)
{
m_log.DebugFormat(
"[SCENE]: Incoming child agent update for {0} in {1}", cAgentData.AgentID, RegionInfo.RegionName);
- // XPTO: if this agent is not allowed here as root, always return false
-
// TODO: This check should probably be in QueryAccess().
- ILandObject nearestParcel = GetNearestAllowedParcel(cAgentData.AgentID, Constants.RegionSize / 2, Constants.RegionSize / 2);
+ ILandObject nearestParcel = GetNearestAllowedParcel(cAgentData.AgentID, RegionInfo.RegionSizeX / 2, RegionInfo.RegionSizeY / 2);
if (nearestParcel == null)
{
- m_log.DebugFormat(
+ m_log.InfoFormat(
"[SCENE]: Denying root agent entry to {0} in {1}: no allowed parcel",
cAgentData.AgentID, RegionInfo.RegionName);
@@ -4150,13 +4472,44 @@ namespace OpenSim.Region.Framework.Scenes
}
// We have to wait until the viewer contacts this region
- // after receiving the EnableSimulator HTTP Event Queue message. This triggers the viewer to send
- // a UseCircuitCode packet which in turn calls AddNewClient which finally creates the ScenePresence.
- ScenePresence childAgentUpdate = WaitGetScenePresence(cAgentData.AgentID);
+ // after receiving the EnableSimulator HTTP Event Queue message (for the v1 teleport protocol)
+ // or TeleportFinish (for the v2 teleport protocol). This triggers the viewer to send
+ // a UseCircuitCode packet which in turn calls AddNewAgent which finally creates the ScenePresence.
+ ScenePresence sp = WaitGetScenePresence(cAgentData.AgentID);
- if (childAgentUpdate != null)
+ if (sp != null)
{
- childAgentUpdate.ChildAgentDataUpdate(cAgentData);
+ if (cAgentData.SessionID != sp.ControllingClient.SessionId)
+ {
+ m_log.WarnFormat(
+ "[SCENE]: Attempt to update agent {0} with invalid session id {1} (possibly from simulator in older version; tell them to update).",
+ sp.UUID, cAgentData.SessionID);
+
+ Console.WriteLine(String.Format("[SCENE]: Attempt to update agent {0} ({1}) with invalid session id {2}",
+ sp.UUID, sp.ControllingClient.SessionId, cAgentData.SessionID));
+ }
+
+ sp.UpdateChildAgent(cAgentData);
+
+ int ntimes = 20;
+ if (cAgentData.SenderWantsToWaitForRoot)
+ {
+ while (sp.IsChildAgent && ntimes-- > 0)
+ Thread.Sleep(1000);
+
+ if (sp.IsChildAgent)
+ m_log.WarnFormat(
+ "[SCENE]: Found presence {0} {1} unexpectedly still child in {2}",
+ sp.Name, sp.UUID, Name);
+ else
+ m_log.InfoFormat(
+ "[SCENE]: Found presence {0} {1} as root in {2} after {3} waits",
+ sp.Name, sp.UUID, Name, 20 - ntimes);
+
+ if (sp.IsChildAgent)
+ return false;
+ }
+
return true;
}
@@ -4169,12 +4522,20 @@ namespace OpenSim.Region.Framework.Scenes
///
/// AgentPosition that contains agent positional data so we can know what to send
/// true if we handled it.
- public virtual bool IncomingChildAgentDataUpdate(AgentPosition cAgentData)
+ public virtual bool IncomingUpdateChildAgent(AgentPosition cAgentData)
{
- //m_log.Debug(" XXX Scene IncomingChildAgentDataUpdate POSITION in " + RegionInfo.RegionName);
+// m_log.DebugFormat(
+// "[SCENE PRESENCE]: IncomingChildAgentDataUpdate POSITION for {0} in {1}, position {2}",
+// cAgentData.AgentID, Name, cAgentData.Position);
+
ScenePresence childAgentUpdate = GetScenePresence(cAgentData.AgentID);
if (childAgentUpdate != null)
{
+// if (childAgentUpdate.ControllingClient.SessionId != cAgentData.SessionID)
+// // Only warn for now
+// m_log.WarnFormat("[SCENE]: Attempt at updating position of agent {0} with invalid session id {1}. Neighbor running older version?",
+// childAgentUpdate.UUID, cAgentData.SessionID);
+
// I can't imagine *yet* why we would get an update if the agent is a root agent..
// however to avoid a race condition crossing borders..
if (childAgentUpdate.IsChildAgent)
@@ -4184,7 +4545,7 @@ namespace OpenSim.Region.Framework.Scenes
uint tRegionX = RegionInfo.RegionLocX;
uint tRegionY = RegionInfo.RegionLocY;
//Send Data to ScenePresence
- childAgentUpdate.ChildAgentDataUpdate(cAgentData, tRegionX, tRegionY, rRegionX, rRegionY);
+ childAgentUpdate.UpdateChildAgent(cAgentData, tRegionX, tRegionY, rRegionX, rRegionY);
// Not Implemented:
//TODO: Do we need to pass the message on to one of our neighbors?
}
@@ -4202,7 +4563,7 @@ namespace OpenSim.Region.Framework.Scenes
///
protected virtual ScenePresence WaitGetScenePresence(UUID agentID)
{
- int ntimes = 10;
+ int ntimes = 20;
ScenePresence sp = null;
while ((sp = GetScenePresence(agentID)) == null && (ntimes-- > 0))
Thread.Sleep(1000);
@@ -4211,28 +4572,92 @@ namespace OpenSim.Region.Framework.Scenes
m_log.WarnFormat(
"[SCENE PRESENCE]: Did not find presence with id {0} in {1} before timeout",
agentID, RegionInfo.RegionName);
-// else
-// m_log.DebugFormat(
-// "[SCENE PRESENCE]: Found presence {0} {1} {2} in {3} after {4} waits",
-// sp.Name, sp.UUID, sp.IsChildAgent ? "child" : "root", RegionInfo.RegionName, 10 - ntimes);
return sp;
}
- public virtual bool IncomingRetrieveRootAgent(UUID id, out IAgentData agent)
+ ///
+ /// Authenticated close (via network)
+ ///
+ ///
+ ///
+ ///
+ ///
+ public bool CloseAgent(UUID agentID, bool force, string auth_token)
{
- agent = null;
- ScenePresence sp = GetScenePresence(id);
- if ((sp != null) && (!sp.IsChildAgent))
+ //m_log.DebugFormat("[SCENE]: Processing incoming close agent {0} in region {1} with auth_token {2}", agentID, RegionInfo.RegionName, auth_token);
+
+ // Check that the auth_token is valid
+ AgentCircuitData acd = AuthenticateHandler.GetAgentCircuitData(agentID);
+
+ if (acd == null)
+ {
+ m_log.DebugFormat(
+ "[SCENE]: Request to close agent {0} but no such agent in scene {1}. May have been closed previously.",
+ agentID, Name);
+
+ return false;
+ }
+
+ if (acd.SessionID.ToString() == auth_token)
+ {
+ return CloseAgent(agentID, force);
+ }
+ else
{
- sp.IsChildAgent = true;
- return sp.CopyAgent(out agent);
+ m_log.WarnFormat(
+ "[SCENE]: Request to close agent {0} with invalid authorization token {1} in {2}",
+ agentID, auth_token, Name);
}
return false;
}
///
+ /// Tell a single client to prepare to close.
+ ///
+ ///
+ /// This should only be called if we may close the client but there will be some delay in so doing. Meant for
+ /// internal use - other callers should almost certainly called CloseClient().
+ ///
+ ///
+ /// true if pre-close state notification was successful. false if the agent
+ /// was not in a state where it could transition to pre-close.
+ public bool IncomingPreCloseClient(ScenePresence sp)
+ {
+ lock (m_removeClientLock)
+ {
+ // We need to avoid a race condition where in, for example, an A B C D region layout, an avatar may
+ // teleport from A -> D, but then -> C before A has asked B to close its old child agent. We do not
+ // want to obey this close since C may have renewed the child agent lease on B.
+ if (sp.DoNotCloseAfterTeleport)
+ {
+ m_log.DebugFormat(
+ "[SCENE]: Not pre-closing {0} agent {1} in {2} since another simulator has re-established the child connection",
+ sp.IsChildAgent ? "child" : "root", sp.Name, Name);
+
+ // Need to reset the flag so that a subsequent close after another teleport can succeed.
+ sp.DoNotCloseAfterTeleport = false;
+
+ return false;
+ }
+
+ if (sp.LifecycleState != ScenePresenceState.Running)
+ {
+ m_log.DebugFormat(
+ "[SCENE]: Called IncomingPreCloseAgent() for {0} in {1} but presence is already in state {2}",
+ sp.Name, Name, sp.LifecycleState);
+
+ return false;
+ }
+
+ sp.LifecycleState = ScenePresenceState.PreRemove;
+
+ return true;
+ }
+ }
+
+ ///
/// Tell a single agent to disconnect from the region.
///
///
@@ -4240,19 +4665,53 @@ namespace OpenSim.Region.Framework.Scenes
/// Force the agent to close even if it might be in the middle of some other operation. You do not want to
/// force unless you are absolutely sure that the agent is dead and a normal close is not working.
///
- public bool IncomingCloseAgent(UUID agentID, bool force)
+ public override bool CloseAgent(UUID agentID, bool force)
{
- //m_log.DebugFormat("[SCENE]: Processing incoming close agent for {0}", agentID);
+ ScenePresence sp;
- ScenePresence presence = m_sceneGraph.GetScenePresence(agentID);
- if (presence != null)
+ lock (m_removeClientLock)
{
- presence.ControllingClient.Close(force);
- return true;
+ sp = GetScenePresence(agentID);
+
+ if (sp == null)
+ {
+ m_log.DebugFormat(
+ "[SCENE]: Called CloseClient() with agent ID {0} but no such presence is in {1}",
+ agentID, Name);
+
+ return false;
+ }
+
+ if (sp.LifecycleState != ScenePresenceState.Running && sp.LifecycleState != ScenePresenceState.PreRemove)
+ {
+ m_log.DebugFormat(
+ "[SCENE]: Called CloseClient() for {0} in {1} but presence is already in state {2}",
+ sp.Name, Name, sp.LifecycleState);
+
+ return false;
+ }
+
+ // We need to avoid a race condition where in, for example, an A B C D region layout, an avatar may
+ // teleport from A -> D, but then -> C before A has asked B to close its old child agent. We do not
+ // want to obey this close since C may have renewed the child agent lease on B.
+ if (sp.DoNotCloseAfterTeleport)
+ {
+ m_log.DebugFormat(
+ "[SCENE]: Not closing {0} agent {1} in {2} since another simulator has re-established the child connection",
+ sp.IsChildAgent ? "child" : "root", sp.Name, Name);
+
+ // Need to reset the flag so that a subsequent close after another teleport can succeed.
+ sp.DoNotCloseAfterTeleport = false;
+
+ return false;
+ }
+
+ sp.LifecycleState = ScenePresenceState.Removing;
}
- // Agent not here
- return false;
+ sp.ControllingClient.Close(force);
+
+ return true;
}
///
@@ -4295,44 +4754,6 @@ namespace OpenSim.Region.Framework.Scenes
ScenePresence sp = GetScenePresence(remoteClient.AgentId);
if (sp != null)
{
- uint regionX = RegionInfo.RegionLocX;
- uint regionY = RegionInfo.RegionLocY;
-
- Utils.LongToUInts(regionHandle, out regionX, out regionY);
-
- int shiftx = (int) regionX - (int) RegionInfo.RegionLocX * (int)Constants.RegionSize;
- int shifty = (int) regionY - (int) RegionInfo.RegionLocY * (int)Constants.RegionSize;
-
- position.X += shiftx;
- position.Y += shifty;
-
- bool result = false;
-
- if (TestBorderCross(position,Cardinals.N))
- result = true;
-
- if (TestBorderCross(position, Cardinals.S))
- result = true;
-
- if (TestBorderCross(position, Cardinals.E))
- result = true;
-
- if (TestBorderCross(position, Cardinals.W))
- result = true;
-
- // bordercross if position is outside of region
-
- if (!result)
- {
- regionHandle = RegionInfo.RegionHandle;
- }
- else
- {
- // not in this region, undo the shift!
- position.X -= shiftx;
- position.Y -= shifty;
- }
-
if (EntityTransferModule != null)
{
EntityTransferModule.Teleport(sp, regionHandle, position, lookAt, teleportFlags);
@@ -4473,20 +4894,7 @@ namespace OpenSim.Region.Framework.Scenes
#region Script Engine
- private List ScriptEngines = new List();
- public bool DumpAssetsToFile;
-
- ///
- ///
- ///
- ///
- public void AddScriptEngine(ScriptEngineInterface scriptEngine)
- {
- ScriptEngines.Add(scriptEngine);
- scriptEngine.InitializeEngine(this);
- }
-
- private bool ScriptDanger(SceneObjectPart part,Vector3 pos)
+ private bool ScriptDanger(SceneObjectPart part, Vector3 pos)
{
ILandObject parcel = LandChannel.GetLandObject(pos.X, pos.Y);
if (part != null)
@@ -4497,35 +4905,24 @@ namespace OpenSim.Region.Framework.Scenes
{
return true;
}
- else if ((parcel.LandData.Flags & (uint)ParcelFlags.AllowGroupScripts) != 0)
+ else if ((part.OwnerID == parcel.LandData.OwnerID) || Permissions.IsGod(part.OwnerID))
{
- if (part.OwnerID == parcel.LandData.OwnerID
- || (parcel.LandData.IsGroupOwned && part.GroupID == parcel.LandData.GroupID)
- || Permissions.IsGod(part.OwnerID))
- {
- return true;
- }
- else
- {
- return false;
- }
+ return true;
+ }
+ else if (((parcel.LandData.Flags & (uint)ParcelFlags.AllowGroupScripts) != 0)
+ && (parcel.LandData.GroupID != UUID.Zero) && (parcel.LandData.GroupID == part.GroupID))
+ {
+ return true;
}
else
{
- if (part.OwnerID == parcel.LandData.OwnerID)
- {
- return true;
- }
- else
- {
- return false;
- }
+ return false;
}
}
else
{
- if (pos.X > 0f && pos.X < Constants.RegionSize && pos.Y > 0f && pos.Y < Constants.RegionSize)
+ if (pos.X > 0f && pos.X < RegionInfo.RegionSizeX && pos.Y > 0f && pos.Y < RegionInfo.RegionSizeY)
{
// The only time parcel != null when an object is inside a region is when
// there is nothing behind the landchannel. IE, no land plugin loaded.
@@ -4854,21 +5251,6 @@ namespace OpenSim.Region.Framework.Scenes
#endregion
- public void RegionHandleRequest(IClientAPI client, UUID regionID)
- {
- ulong handle = 0;
- if (regionID == RegionInfo.RegionID)
- handle = RegionInfo.RegionHandle;
- else
- {
- GridRegion r = GridService.GetRegionByUUID(UUID.Zero, regionID);
- if (r != null)
- handle = r.RegionHandle;
- }
-
- if (handle != 0)
- client.SendRegionHandle(regionID, handle);
- }
// Commented pending deletion since this method no longer appears to do anything at all
// public bool NeedSceneCacheClear(UUID agentID)
@@ -4920,7 +5302,7 @@ namespace OpenSim.Region.Framework.Scenes
// 3 = We have seen a new user enter within the past 4 minutes
// which can be seen as positive confirmation of sim health
//
- int health=1; // Start at 1, means we're up
+ int health = 1; // Start at 1, means we're up
if ((Util.EnvironmentTickCountSubtract(m_lastFrameTick)) < 1000)
health += 1;
@@ -4967,7 +5349,7 @@ namespace OpenSim.Region.Framework.Scenes
case PhysicsJointType.Ball:
{
Vector3 jointAnchor = PhysicsScene.GetJointAnchor(joint);
- Vector3 proxyPos = new Vector3(jointAnchor.X, jointAnchor.Y, jointAnchor.Z);
+ Vector3 proxyPos = jointAnchor;
jointProxyObject.ParentGroup.UpdateGroupPosition(proxyPos); // schedules the entire group for a terse update
}
break;
@@ -4992,7 +5374,7 @@ namespace OpenSim.Region.Framework.Scenes
jointErrorMessage(joint, "joint.TrackedBodyName is null, joint " + joint.ObjectNameInScene);
}
- Vector3 proxyPos = new Vector3(jointAnchor.X, jointAnchor.Y, jointAnchor.Z);
+ Vector3 proxyPos = jointAnchor;
Quaternion q = trackedBody.RotationOffset * joint.LocalRotation;
jointProxyObject.ParentGroup.UpdateGroupPosition(proxyPos); // schedules the entire group for a terse update
@@ -5081,6 +5463,10 @@ namespace OpenSim.Region.Framework.Scenes
return null;
}
+ // Get terrain height at the specified location.
+ // Presumes the underlying implementation is a heightmap which is a 1m grid.
+ // Finds heightmap grid points before and after the point and
+ // does a linear approximation of the height at this intermediate point.
public float GetGroundHeight(float x, float y)
{
if (x < 0)
@@ -5093,8 +5479,8 @@ namespace OpenSim.Region.Framework.Scenes
y = Heightmap.Height - 1;
Vector3 p0 = new Vector3(x, y, (float)Heightmap[(int)x, (int)y]);
- Vector3 p1 = new Vector3(p0);
- Vector3 p2 = new Vector3(p0);
+ Vector3 p1 = p0;
+ Vector3 p2 = p0;
p1.X += 1.0f;
if (p1.X < Heightmap.Width)
@@ -5141,9 +5527,14 @@ namespace OpenSim.Region.Framework.Scenes
get { return m_allowScriptCrossings; }
}
- public Vector3? GetNearestAllowedPosition(ScenePresence avatar)
+ public Vector3 GetNearestAllowedPosition(ScenePresence avatar)
+ {
+ return GetNearestAllowedPosition(avatar, null);
+ }
+
+ public Vector3 GetNearestAllowedPosition(ScenePresence avatar, ILandObject excludeParcel)
{
- ILandObject nearestParcel = GetNearestAllowedParcel(avatar.UUID, avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y);
+ ILandObject nearestParcel = GetNearestAllowedParcel(avatar.UUID, avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y, excludeParcel);
if (nearestParcel != null)
{
@@ -5152,10 +5543,7 @@ namespace OpenSim.Region.Framework.Scenes
Vector3? nearestPoint = GetNearestPointInParcelAlongDirectionFromPoint(avatar.AbsolutePosition, dir, nearestParcel);
if (nearestPoint != null)
{
-// m_log.DebugFormat(
-// "[SCENE]: Found a sane previous position based on velocity for {0}, sending them to {1} in {2}",
-// avatar.Name, nearestPoint, nearestParcel.LandData.Name);
-
+ m_log.Debug("Found a sane previous position based on velocity, sending them to: " + nearestPoint.ToString());
return nearestPoint.Value;
}
@@ -5165,24 +5553,27 @@ namespace OpenSim.Region.Framework.Scenes
nearestPoint = GetNearestPointInParcelAlongDirectionFromPoint(avatar.AbsolutePosition, dir, nearestParcel);
if (nearestPoint != null)
{
-// m_log.DebugFormat(
-// "[SCENE]: {0} had a zero velocity, sending them to {1}", avatar.Name, nearestPoint);
-
+ m_log.Debug("They had a zero velocity, sending them to: " + nearestPoint.ToString());
return nearestPoint.Value;
}
- //Ultimate backup if we have no idea where they are
-// m_log.DebugFormat(
-// "[SCENE]: No idea where {0} is, sending them to {1}", avatar.Name, avatar.lastKnownAllowedPosition);
+ ILandObject dest = LandChannel.GetLandObject(avatar.lastKnownAllowedPosition.X, avatar.lastKnownAllowedPosition.Y);
+ if (dest != excludeParcel)
+ {
+ // Ultimate backup if we have no idea where they are and
+ // the last allowed position was in another parcel
+ m_log.Debug("Have no idea where they are, sending them to: " + avatar.lastKnownAllowedPosition.ToString());
+ return avatar.lastKnownAllowedPosition;
+ }
- return avatar.lastKnownAllowedPosition;
+ // else fall through to region edge
}
//Go to the edge, this happens in teleporting to a region with no available parcels
Vector3 nearestRegionEdgePoint = GetNearestRegionEdgePosition(avatar);
- //Debug.WriteLine("They are really in a place they don't belong, sending them to: " + nearestRegionEdgePoint.ToString());
-
+ //m_log.Debug("They are really in a place they don't belong, sending them to: " + nearestRegionEdgePoint.ToString());
+
return nearestRegionEdgePoint;
}
@@ -5196,7 +5587,7 @@ namespace OpenSim.Region.Framework.Scenes
{
Vector3 unitDirection = Vector3.Normalize(direction);
//Making distance to search go through some sane limit of distance
- for (float distance = 0; distance < Constants.RegionSize * 2; distance += .5f)
+ for (float distance = 0; distance < Math.Max(RegionInfo.RegionSizeX, RegionInfo.RegionSizeY) * 2; distance += .5f)
{
Vector3 testPos = Vector3.Add(pos, Vector3.Multiply(unitDirection, distance));
if (parcel.ContainsPoint((int)testPos.X, (int)testPos.Y))
@@ -5209,13 +5600,18 @@ namespace OpenSim.Region.Framework.Scenes
public ILandObject GetNearestAllowedParcel(UUID avatarId, float x, float y)
{
+ return GetNearestAllowedParcel(avatarId, x, y, null);
+ }
+
+ public ILandObject GetNearestAllowedParcel(UUID avatarId, float x, float y, ILandObject excludeParcel)
+ {
List all = AllParcels();
float minParcelDistance = float.MaxValue;
ILandObject nearestParcel = null;
foreach (var parcel in all)
{
- if (!parcel.IsEitherBannedOrRestricted(avatarId))
+ if (!parcel.IsEitherBannedOrRestricted(avatarId) && parcel != excludeParcel)
{
float parcelDistance = GetParcelDistancefromPoint(parcel, x, y);
if (parcelDistance < minParcelDistance)
@@ -5245,9 +5641,9 @@ namespace OpenSim.Region.Framework.Scenes
int count = 0;
int avgx = 0;
int avgy = 0;
- for (int x = 0; x < Constants.RegionSize; x++)
+ for (int x = 0; x < RegionInfo.RegionSizeX; x++)
{
- for (int y = 0; y < Constants.RegionSize; y++)
+ for (int y = 0; y < RegionInfo.RegionSizeY; y++)
{
//Just keep a running average as we check if all the points are inside or not
if (parcel.ContainsPoint(x, y))
@@ -5271,31 +5667,33 @@ namespace OpenSim.Region.Framework.Scenes
private Vector3 GetNearestRegionEdgePosition(ScenePresence avatar)
{
- float xdistance = avatar.AbsolutePosition.X < Constants.RegionSize / 2 ? avatar.AbsolutePosition.X : Constants.RegionSize - avatar.AbsolutePosition.X;
- float ydistance = avatar.AbsolutePosition.Y < Constants.RegionSize / 2 ? avatar.AbsolutePosition.Y : Constants.RegionSize - avatar.AbsolutePosition.Y;
+ float xdistance = avatar.AbsolutePosition.X < RegionInfo.RegionSizeX / 2
+ ? avatar.AbsolutePosition.X : RegionInfo.RegionSizeX - avatar.AbsolutePosition.X;
+ float ydistance = avatar.AbsolutePosition.Y < RegionInfo.RegionSizeY / 2
+ ? avatar.AbsolutePosition.Y : RegionInfo.RegionSizeY - avatar.AbsolutePosition.Y;
//find out what vertical edge to go to
if (xdistance < ydistance)
{
- if (avatar.AbsolutePosition.X < Constants.RegionSize / 2)
+ if (avatar.AbsolutePosition.X < RegionInfo.RegionSizeX / 2)
{
return GetPositionAtAvatarHeightOrGroundHeight(avatar, 0.0f, avatar.AbsolutePosition.Y);
}
else
{
- return GetPositionAtAvatarHeightOrGroundHeight(avatar, Constants.RegionSize, avatar.AbsolutePosition.Y);
+ return GetPositionAtAvatarHeightOrGroundHeight(avatar, RegionInfo.RegionSizeY, avatar.AbsolutePosition.Y);
}
}
//find out what horizontal edge to go to
else
{
- if (avatar.AbsolutePosition.Y < Constants.RegionSize / 2)
+ if (avatar.AbsolutePosition.Y < RegionInfo.RegionSizeY / 2)
{
return GetPositionAtAvatarHeightOrGroundHeight(avatar, avatar.AbsolutePosition.X, 0.0f);
}
else
{
- return GetPositionAtAvatarHeightOrGroundHeight(avatar, avatar.AbsolutePosition.X, Constants.RegionSize);
+ return GetPositionAtAvatarHeightOrGroundHeight(avatar, avatar.AbsolutePosition.X, RegionInfo.RegionSizeY);
}
}
}
@@ -5336,33 +5734,7 @@ namespace OpenSim.Region.Framework.Scenes
public void TriggerEstateSunUpdate()
{
- float sun;
- if (RegionInfo.RegionSettings.UseEstateSun)
- {
- sun = (float)RegionInfo.EstateSettings.SunPosition;
- if (RegionInfo.EstateSettings.UseGlobalTime)
- {
- sun = EventManager.GetCurrentTimeAsSunLindenHour() - 6.0f;
- }
-
- //
- EventManager.TriggerEstateToolsSunUpdate(
- RegionInfo.RegionHandle,
- RegionInfo.EstateSettings.FixedSun,
- RegionInfo.RegionSettings.UseEstateSun,
- sun);
- }
- else
- {
- // Use the Sun Position from the Region Settings
- sun = (float)RegionInfo.RegionSettings.SunPosition - 6.0f;
-
- EventManager.TriggerEstateToolsSunUpdate(
- RegionInfo.RegionHandle,
- RegionInfo.RegionSettings.FixedSun,
- RegionInfo.RegionSettings.UseEstateSun,
- sun);
- }
+ EventManager.TriggerEstateToolsSunUpdate(RegionInfo.RegionHandle);
}
private void HandleReloadEstate(string module, string[] cmd)
@@ -5387,15 +5759,15 @@ namespace OpenSim.Region.Framework.Scenes
///
///
public static Vector3[] GetCombinedBoundingBox(
- List objects,
+ List objects,
out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ)
{
- minX = 256;
- maxX = -256;
- minY = 256;
- maxY = -256;
- minZ = 8192;
- maxZ = -256;
+ minX = float.MaxValue;
+ maxX = float.MinValue;
+ minY = float.MaxValue;
+ maxY = float.MinValue;
+ minZ = float.MaxValue;
+ maxZ = float.MinValue;
List offsets = new List();
@@ -5406,7 +5778,7 @@ namespace OpenSim.Region.Framework.Scenes
Vector3 vec = g.AbsolutePosition;
g.GetAxisAlignedBoundingBoxRaw(out ominX, out omaxX, out ominY, out omaxY, out ominZ, out omaxZ);
-
+
// m_log.DebugFormat(
// "[SCENE]: For {0} found AxisAlignedBoundingBoxRaw {1}, {2}",
// g.Name, new Vector3(ominX, ominY, ominZ), new Vector3(omaxX, omaxY, omaxZ));
@@ -5465,7 +5837,7 @@ namespace OpenSim.Region.Framework.Scenes
// so that all simulators can retrieve it
string error = GridService.RegisterRegion(RegionInfo.ScopeID, new GridRegion(RegionInfo));
if (error != string.Empty)
- throw new Exception(error);
+ throw new Exception(error);
}
///
@@ -5479,22 +5851,23 @@ namespace OpenSim.Region.Framework.Scenes
/// or corssing the broder walking, but will NOT prevent
/// child agent creation, thereby emulating the SL behavior.
///
- ///
+ /// The visitor's User ID
+ /// The visitor's Home URI (may be null)
///
///
///
- public bool QueryAccess(UUID agentID, Vector3 position, out string reason)
+ public bool QueryAccess(UUID agentID, string agentHomeURI, bool viaTeleport, Vector3 position, List features, out string reason)
{
- if (EntityTransferModule.IsInTransit(agentID))
- {
- reason = "Agent is still in transit from this region";
+ reason = string.Empty;
- m_log.WarnFormat(
- "[SCENE]: Denying agent {0} entry into {1} since region still has them registered as in transit",
- agentID, RegionInfo.RegionName);
+ if (Permissions.IsGod(agentID))
+ {
+ reason = String.Empty;
+ return true;
+ }
+ if (!AllowAvatarCrossing && !viaTeleport)
return false;
- }
// FIXME: Root agent count is currently known to be inaccurate. This forces a recount before we check.
// However, the long term fix is to make sure root agent count is always accurate.
@@ -5516,7 +5889,43 @@ namespace OpenSim.Region.Framework.Scenes
}
}
- if (position == Vector3.Zero) // Teleport
+ ScenePresence presence = GetScenePresence(agentID);
+ IClientAPI client = null;
+ AgentCircuitData aCircuit = null;
+
+ if (presence != null)
+ {
+ client = presence.ControllingClient;
+ if (client != null)
+ aCircuit = client.RequestClientInfo();
+ }
+
+ // We may be called before there is a presence or a client.
+ // Fake AgentCircuitData to keep IAuthorizationModule smiling
+ if (client == null)
+ {
+ aCircuit = new AgentCircuitData();
+ aCircuit.AgentID = agentID;
+ aCircuit.firstname = String.Empty;
+ aCircuit.lastname = String.Empty;
+ }
+
+ try
+ {
+ if (!AuthorizeUser(aCircuit, false, out reason))
+ {
+ //m_log.DebugFormat("[SCENE]: Denying access for {0}", agentID);
+ return false;
+ }
+ }
+ catch (Exception e)
+ {
+ m_log.DebugFormat("[SCENE]: Exception authorizing agent: {0} " + e.StackTrace, e.Message);
+ reason = "Error authorizing agent: " + e.Message;
+ return false;
+ }
+
+ if (viaTeleport)
{
if (!RegionInfo.EstateSettings.AllowDirectTeleport)
{
@@ -5539,11 +5948,47 @@ namespace OpenSim.Region.Framework.Scenes
if (banned)
{
- reason = "No suitable landing point found";
- return false;
+ if (Permissions.IsAdministrator(agentID) == false || Permissions.IsGridGod(agentID) == false)
+ {
+ reason = "No suitable landing point found";
+ return false;
+ }
+ reason = "Administrative access only";
+ return true;
}
}
}
+
+ float posX = 128.0f;
+ float posY = 128.0f;
+
+ if (!TestLandRestrictions(agentID, out reason, ref posX, ref posY))
+ {
+ // m_log.DebugFormat("[SCENE]: Denying {0} because they are banned on all parcels", agentID);
+ reason = "You are banned from the region on all parcels";
+ return false;
+ }
+ }
+ else // Walking
+ {
+ ILandObject land = LandChannel.GetLandObject(position.X, position.Y);
+ if (land == null)
+ {
+ reason = "No parcel found";
+ return false;
+ }
+
+ bool banned = land.IsBannedFromLand(agentID);
+ bool restricted = land.IsRestrictedFromLand(agentID);
+
+ if (banned || restricted)
+ {
+ if (banned)
+ reason = "You are banned from the parcel";
+ else
+ reason = "The parcel is restricted";
+ return false;
+ }
}
reason = String.Empty;
diff --git a/OpenSim/Region/Framework/Scenes/SceneBase.cs b/OpenSim/Region/Framework/Scenes/SceneBase.cs
index d3e968e..7ff3d40 100644
--- a/OpenSim/Region/Framework/Scenes/SceneBase.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneBase.cs
@@ -44,6 +44,10 @@ namespace OpenSim.Region.Framework.Scenes
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+#pragma warning disable 414
+ private static readonly string LogHeader = "[SCENE]";
+#pragma warning restore 414
+
#region Events
public event restart OnRestart;
@@ -78,6 +82,13 @@ namespace OpenSim.Region.Framework.Scenes
///
protected Dictionary> ModuleInterfaces = new Dictionary>();
+ ///
+ /// These two objects hold the information about any formats used
+ /// by modules that hold agent specific data.
+ ///
+ protected List FormatsOffered = new List();
+ protected Dictionary