aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Framework/Scenes
diff options
context:
space:
mode:
authorDavid Walter Seikel2016-11-03 21:44:39 +1000
committerDavid Walter Seikel2016-11-03 21:44:39 +1000
commit134f86e8d5c414409631b25b8c6f0ee45fbd8631 (patch)
tree216b89d3fb89acfb81be1e440c25c41ab09fa96d /OpenSim/Region/Framework/Scenes
parentMore changing to production grid. Double oops. (diff)
downloadopensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.zip
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.gz
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.bz2
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.xz
Initial update to OpenSim 0.8.2.1 source code.
Diffstat (limited to '')
-rw-r--r--OpenSim/Data/IOfflineIMData.cs (renamed from OpenSim/Region/Framework/Scenes/Scripting/IScriptHost.cs)26
-rw-r--r--OpenSim/Framework/ServiceAuth/CompoundAuthentication.cs (renamed from OpenSim/Region/Framework/Scenes/Scripting/NullScriptHost.cs)67
-rw-r--r--OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs119
-rw-r--r--OpenSim/Region/Framework/Scenes/Animation/BinBVHAnimation.cs49
-rw-r--r--OpenSim/Region/Framework/Scenes/Animation/DefaultAvatarAnimations.cs26
-rw-r--r--OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs38
-rw-r--r--OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs10
-rw-r--r--OpenSim/Region/Framework/Scenes/Border.cs7
-rw-r--r--OpenSim/Region/Framework/Scenes/EventManager.cs291
-rw-r--r--OpenSim/Region/Framework/Scenes/KeyframeMotion.cs829
-rw-r--r--OpenSim/Region/Framework/Scenes/Prioritizer.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/RegionStatsHandler.cs27
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.Inventory.cs575
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs68
-rwxr-xr-x[-rw-r--r--]OpenSim/Region/Framework/Scenes/Scene.cs2597
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneBase.cs78
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs64
-rwxr-xr-x[-rw-r--r--]OpenSim/Region/Framework/Scenes/SceneGraph.cs175
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneManager.cs48
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs8
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs509
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPart.cs918
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs132
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresence.cs2577
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresenceStateMachine.cs113
-rw-r--r--OpenSim/Region/Framework/Scenes/Scripting/ScriptEngineInterface.cs38
-rw-r--r--OpenSim/Region/Framework/Scenes/Scripting/ScriptEngineLoader.cs119
-rw-r--r--OpenSim/Region/Framework/Scenes/Scripting/ScriptUtils.cs107
-rw-r--r--OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs87
-rw-r--r--OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs604
-rw-r--r--OpenSim/Region/Framework/Scenes/Serialization/SceneXmlLoader.cs2
-rwxr-xr-x[-rw-r--r--]OpenSim/Region/Framework/Scenes/SimStatsReporter.cs259
-rw-r--r--OpenSim/Region/Framework/Scenes/TerrainChannel.cs346
-rw-r--r--OpenSim/Region/Framework/Scenes/TerrainCompressor.cs948
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/EntityManagerTests.cs1
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/SceneGraphTests.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/SceneManagerTests.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/SceneObjectCopyTests.cs346
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/SceneObjectCrossingTests.cs259
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs111
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs39
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/SceneObjectResizeTests.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/SceneObjectScriptTests.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/SceneObjectSerializationTests.cs135
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/SceneObjectSpatialTests.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs21
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/SceneObjectUndoRedoTests.cs6
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/SceneObjectUserGroupTests.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs218
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAnimationTests.cs4
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAutopilotTests.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCapabilityTests.cs86
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs247
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/ScenePresenceSitTests.cs81
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs302
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/SceneStatisticsTests.cs69
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/SceneTelehubTests.cs118
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs25
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/SharedRegionModuleTests.cs249
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/TaskInventoryTests.cs18
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/UserInventoryTests.cs18
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs91
-rw-r--r--OpenSim/Region/Framework/Scenes/UuidGatherer.cs604
64 files changed, 11197 insertions, 3730 deletions
diff --git a/OpenSim/Region/Framework/Scenes/Scripting/IScriptHost.cs b/OpenSim/Data/IOfflineIMData.cs
index f3be028..58501a3 100644
--- a/OpenSim/Region/Framework/Scenes/Scripting/IScriptHost.cs
+++ b/OpenSim/Data/IOfflineIMData.cs
@@ -25,22 +25,26 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System.Collections.Generic;
29using OpenSim.Data;
28using OpenMetaverse; 30using OpenMetaverse;
29 31
30namespace OpenSim.Region.Framework.Scenes.Scripting 32namespace OpenSim.Data
31{ 33{
32 public interface IScriptHost 34 public class OfflineIMData
33 { 35 {
34 string Name { get; set; } 36 public UUID PrincipalID;
35 string Description { get; set; } 37 public UUID FromID;
38 public Dictionary<string, string> Data;
39 }
36 40
37 UUID UUID { get; }
38 UUID OwnerID { get; }
39 UUID CreatorID { get; }
40 Vector3 AbsolutePosition { get; }
41 41
42 string SitName { get; set; } 42 public interface IOfflineIMData
43 string TouchName { get; set; } 43 {
44 void SetText(string text, Vector3 color, double alpha); 44 OfflineIMData[] Get(string field, string val);
45 long GetCount(string field, string key);
46 bool Store(OfflineIMData data);
47 bool Delete(string field, string val);
48 void DeleteOld();
45 } 49 }
46} 50}
diff --git a/OpenSim/Region/Framework/Scenes/Scripting/NullScriptHost.cs b/OpenSim/Framework/ServiceAuth/CompoundAuthentication.cs
index d7198f0..a49952c 100644
--- a/OpenSim/Region/Framework/Scenes/Scripting/NullScriptHost.cs
+++ b/OpenSim/Framework/ServiceAuth/CompoundAuthentication.cs
@@ -26,66 +26,57 @@
26 */ 26 */
27 27
28using System; 28using System;
29using OpenMetaverse; 29using System.Collections.Generic;
30using log4net; 30using System.Collections.Specialized;
31using System.Reflection; 31using System.Linq;
32using OpenSim.Framework; 32using System.Net;
33 33
34namespace OpenSim.Region.Framework.Scenes.Scripting 34namespace OpenSim.Framework.ServiceAuth
35{ 35{
36 public class NullScriptHost : IScriptHost 36 public class CompoundAuthentication : IServiceAuth
37 { 37 {
38 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 38 public string Name { get { return "Compound"; } }
39 39
40 private Vector3 m_pos = new Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 30); 40 private List<IServiceAuth> m_authentications = new List<IServiceAuth>();
41 41
42 public string Name 42 public int Count { get { return m_authentications.Count; } }
43 {
44 get { return "Object"; }
45 set { }
46 }
47 43
48 public string SitName 44 public List<IServiceAuth> GetAuthentors()
49 { 45 {
50 get { return String.Empty; } 46 return new List<IServiceAuth>(m_authentications);
51 set { }
52 } 47 }
53 48
54 public string TouchName 49 public void AddAuthenticator(IServiceAuth auth)
55 { 50 {
56 get { return String.Empty; } 51 m_authentications.Add(auth);
57 set { }
58 } 52 }
59 53
60 public string Description 54 public void RemoveAuthenticator(IServiceAuth auth)
61 { 55 {
62 get { return String.Empty; } 56 m_authentications.Remove(auth);
63 set { }
64 } 57 }
65 58
66 public UUID UUID 59 public void AddAuthorization(NameValueCollection headers)
67 { 60 {
68 get { return UUID.Zero; } 61 foreach (IServiceAuth auth in m_authentications)
62 auth.AddAuthorization(headers);
69 } 63 }
70 64
71 public UUID OwnerID 65 public bool Authenticate(string data)
72 { 66 {
73 get { return UUID.Zero; } 67 return m_authentications.TrueForAll(a => a.Authenticate(data));
74 } 68 }
75 69
76 public UUID CreatorID 70 public bool Authenticate(NameValueCollection requestHeaders, AddHeaderDelegate d, out HttpStatusCode statusCode)
77 { 71 {
78 get { return UUID.Zero; } 72 foreach (IServiceAuth auth in m_authentications)
79 } 73 {
74 if (!auth.Authenticate(requestHeaders, d, out statusCode))
75 return false;
76 }
80 77
81 public Vector3 AbsolutePosition 78 statusCode = HttpStatusCode.OK;
82 { 79 return true;
83 get { return m_pos; }
84 }
85
86 public void SetText(string text, Vector3 color, double alpha)
87 {
88 m_log.Warn("Tried to SetText "+text+" on NullScriptHost");
89 } 80 }
90 } 81 }
91} 82} \ No newline at end of file
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 @@
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Reflection; 30using System.Reflection;
31using System.Text;
31using log4net; 32using log4net;
32using OpenMetaverse; 33using OpenMetaverse;
34using OpenMetaverse.StructuredData;
35
33using OpenSim.Framework; 36using OpenSim.Framework;
34 37
35using Animation = OpenSim.Framework.Animation; 38using Animation = OpenSim.Framework.Animation;
@@ -60,6 +63,12 @@ namespace OpenSim.Region.Framework.Scenes.Animation
60 ResetDefaultAnimation(); 63 ResetDefaultAnimation();
61 } 64 }
62 65
66 public AnimationSet(OSDArray pArray)
67 {
68 ResetDefaultAnimation();
69 FromOSDArray(pArray);
70 }
71
63 public bool HasAnimation(UUID animID) 72 public bool HasAnimation(UUID animID)
64 { 73 {
65 if (m_defaultAnimation.AnimID == animID) 74 if (m_defaultAnimation.AnimID == animID)
@@ -218,5 +227,115 @@ namespace OpenSim.Region.Framework.Scenes.Animation
218 foreach (OpenSim.Framework.Animation anim in theArray) 227 foreach (OpenSim.Framework.Animation anim in theArray)
219 m_animations.Add(anim); 228 m_animations.Add(anim);
220 } 229 }
230
231 // Create representation of this AnimationSet as an OSDArray.
232 // First two entries in the array are the default and implicitDefault animations
233 // followed by the other animations.
234 public OSDArray ToOSDArray()
235 {
236 OSDArray ret = new OSDArray();
237 ret.Add(DefaultAnimation.PackUpdateMessage());
238 ret.Add(ImplicitDefaultAnimation.PackUpdateMessage());
239
240 foreach (OpenSim.Framework.Animation anim in m_animations)
241 ret.Add(anim.PackUpdateMessage());
242
243 return ret;
244 }
245
246 public void FromOSDArray(OSDArray pArray)
247 {
248 this.Clear();
249
250 if (pArray.Count >= 1)
251 {
252 m_defaultAnimation = new OpenSim.Framework.Animation((OSDMap)pArray[0]);
253 }
254 if (pArray.Count >= 2)
255 {
256 m_implicitDefaultAnimation = new OpenSim.Framework.Animation((OSDMap)pArray[1]);
257 }
258 for (int ii = 2; ii < pArray.Count; ii++)
259 {
260 m_animations.Add(new OpenSim.Framework.Animation((OSDMap)pArray[ii]));
261 }
262 }
263
264 // Compare two AnimationSets and return 'true' if the default animations are the same
265 // and all of the animations in the list are equal.
266 public override bool Equals(object obj)
267 {
268 AnimationSet other = obj as AnimationSet;
269 if (other != null)
270 {
271 if (this.DefaultAnimation.Equals(other.DefaultAnimation)
272 && this.ImplicitDefaultAnimation.Equals(other.ImplicitDefaultAnimation))
273 {
274 // The defaults are the same. Is the list of animations the same?
275 OpenSim.Framework.Animation[] thisAnims = this.ToArray();
276 OpenSim.Framework.Animation[] otherAnims = other.ToArray();
277 if (thisAnims.Length == 0 && otherAnims.Length == 0)
278 return true; // the common case
279 if (thisAnims.Length == otherAnims.Length)
280 {
281 // Do this the hard way but since the list is usually short this won't take long.
282 foreach (OpenSim.Framework.Animation thisAnim in thisAnims)
283 {
284 bool found = false;
285 foreach (OpenSim.Framework.Animation otherAnim in otherAnims)
286 {
287 if (thisAnim.Equals(otherAnim))
288 {
289 found = true;
290 break;
291 }
292 }
293 if (!found)
294 {
295 // If anything is not in the other list, these are not equal
296 return false;
297 }
298 }
299 // Found everything in the other list. Since lists are equal length, they must be equal.
300 return true;
301 }
302 }
303 return false;
304 }
305 // Don't know what was passed, but the base system will figure it out for me.
306 return base.Equals(obj);
307 }
308
309 public override int GetHashCode()
310 {
311 return base.GetHashCode();
312 }
313
314 public override string ToString()
315 {
316 StringBuilder buff = new StringBuilder();
317 buff.Append("dflt=");
318 buff.Append(DefaultAnimation.ToString());
319 buff.Append(",iDflt=");
320 if (DefaultAnimation.Equals(ImplicitDefaultAnimation))
321 buff.Append("same");
322 else
323 buff.Append(ImplicitDefaultAnimation.ToString());
324 if (m_animations.Count > 0)
325 {
326 buff.Append(",anims=");
327 bool firstTime = true;
328 foreach (OpenSim.Framework.Animation anim in m_animations)
329 {
330 if (!firstTime)
331 buff.Append(",");
332 buff.Append("<");
333 buff.Append(anim.ToString());
334 buff.Append(">");
335 firstTime = false;
336 }
337 }
338 return buff.ToString();
339 }
221 } 340 }
222} 341}
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 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
@@ -113,31 +113,34 @@ namespace OpenSim.Region.Framework.Scenes.Animation
113 113
114 public byte[] ToBytes() 114 public byte[] ToBytes()
115 { 115 {
116 byte[] outputbytes = new byte[0]; 116 byte[] outputbytes;
117 117
118 BinaryWriter iostream = new BinaryWriter(new MemoryStream()); 118 using (MemoryStream ms = new MemoryStream())
119 iostream.Write(BinBVHUtil.ES(Utils.UInt16ToBytes(unknown0))); 119 using (BinaryWriter iostream = new BinaryWriter(ms))
120 iostream.Write(BinBVHUtil.ES(Utils.UInt16ToBytes(unknown1)));
121 iostream.Write(BinBVHUtil.ES(Utils.IntToBytes(Priority)));
122 iostream.Write(BinBVHUtil.ES(Utils.FloatToBytes(Length)));
123 iostream.Write(BinBVHUtil.WriteNullTerminatedString(ExpressionName));
124 iostream.Write(BinBVHUtil.ES(Utils.FloatToBytes(InPoint)));
125 iostream.Write(BinBVHUtil.ES(Utils.FloatToBytes(OutPoint)));
126 iostream.Write(BinBVHUtil.ES(Utils.IntToBytes(Loop ? 1 : 0)));
127 iostream.Write(BinBVHUtil.ES(Utils.FloatToBytes(EaseInTime)));
128 iostream.Write(BinBVHUtil.ES(Utils.FloatToBytes(EaseOutTime)));
129 iostream.Write(BinBVHUtil.ES(Utils.UIntToBytes(HandPose)));
130 iostream.Write(BinBVHUtil.ES(Utils.UIntToBytes((uint)(Joints.Length))));
131
132 for (int i = 0; i < Joints.Length; i++)
133 { 120 {
134 Joints[i].WriteBytesToStream(iostream, InPoint, OutPoint); 121 iostream.Write(BinBVHUtil.ES(Utils.UInt16ToBytes(unknown0)));
122 iostream.Write(BinBVHUtil.ES(Utils.UInt16ToBytes(unknown1)));
123 iostream.Write(BinBVHUtil.ES(Utils.IntToBytes(Priority)));
124 iostream.Write(BinBVHUtil.ES(Utils.FloatToBytes(Length)));
125 iostream.Write(BinBVHUtil.WriteNullTerminatedString(ExpressionName));
126 iostream.Write(BinBVHUtil.ES(Utils.FloatToBytes(InPoint)));
127 iostream.Write(BinBVHUtil.ES(Utils.FloatToBytes(OutPoint)));
128 iostream.Write(BinBVHUtil.ES(Utils.IntToBytes(Loop ? 1 : 0)));
129 iostream.Write(BinBVHUtil.ES(Utils.FloatToBytes(EaseInTime)));
130 iostream.Write(BinBVHUtil.ES(Utils.FloatToBytes(EaseOutTime)));
131 iostream.Write(BinBVHUtil.ES(Utils.UIntToBytes(HandPose)));
132 iostream.Write(BinBVHUtil.ES(Utils.UIntToBytes((uint)(Joints.Length))));
133
134 for (int i = 0; i < Joints.Length; i++)
135 {
136 Joints[i].WriteBytesToStream(iostream, InPoint, OutPoint);
137 }
138 iostream.Write(BinBVHUtil.ES(Utils.IntToBytes(0)));
139
140 using (MemoryStream ms2 = (MemoryStream)iostream.BaseStream)
141 outputbytes = ms2.ToArray();
135 } 142 }
136 iostream.Write(BinBVHUtil.ES(Utils.IntToBytes(0))); 143
137 MemoryStream ms = (MemoryStream)iostream.BaseStream;
138 outputbytes = ms.ToArray();
139 ms.Close();
140 iostream.Close();
141 return outputbytes; 144 return outputbytes;
142 } 145 }
143 146
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
104 104
105 return UUID.Zero; 105 return UUID.Zero;
106 } 106 }
107
108 /// <summary>
109 /// Get the name of the animation given a UUID. If there is no matching animation
110 /// return the UUID as a string.
111 /// </summary>
112 public static string GetDefaultAnimationName(UUID uuid)
113 {
114 string ret = "unknown";
115 if (AnimsUUID.ContainsValue(uuid))
116 {
117 foreach (KeyValuePair<string, UUID> kvp in AnimsUUID)
118 {
119 if (kvp.Value == uuid)
120 {
121 ret = kvp.Key;
122 break;
123 }
124 }
125 }
126 else
127 {
128 ret = uuid.ToString();
129 }
130
131 return ret;
132 }
107 } 133 }
108} \ No newline at end of file 134} \ 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;
35using OpenSim.Framework; 35using OpenSim.Framework;
36using OpenSim.Region.Framework.Interfaces; 36using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Region.Framework.Scenes; 37using OpenSim.Region.Framework.Scenes;
38using OpenSim.Region.Physics.Manager; 38using OpenSim.Region.PhysicsModules.SharedBase;
39 39
40namespace OpenSim.Region.Framework.Scenes.Animation 40namespace OpenSim.Region.Framework.Scenes.Animation
41{ 41{
@@ -92,7 +92,10 @@ namespace OpenSim.Region.Framework.Scenes.Animation
92 GetAnimName(animID), animID, m_scenePresence.Name); 92 GetAnimName(animID), animID, m_scenePresence.Name);
93 93
94 if (m_animations.Add(animID, m_scenePresence.ControllingClient.NextAnimationSequenceNumber, objectID)) 94 if (m_animations.Add(animID, m_scenePresence.ControllingClient.NextAnimationSequenceNumber, objectID))
95 {
95 SendAnimPack(); 96 SendAnimPack();
97 m_scenePresence.TriggerScenePresenceUpdated();
98 }
96 } 99 }
97 100
98 // Called from scripts 101 // Called from scripts
@@ -131,7 +134,10 @@ namespace OpenSim.Region.Framework.Scenes.Animation
131 GetAnimName(animID), animID, m_scenePresence.Name); 134 GetAnimName(animID), animID, m_scenePresence.Name);
132 135
133 if (m_animations.Remove(animID, allowNoDefault)) 136 if (m_animations.Remove(animID, allowNoDefault))
137 {
134 SendAnimPack(); 138 SendAnimPack();
139 m_scenePresence.TriggerScenePresenceUpdated();
140 }
135 } 141 }
136 142
137 // Called from scripts 143 // Called from scripts
@@ -163,8 +169,10 @@ namespace OpenSim.Region.Framework.Scenes.Animation
163 /// The movement animation is reserved for "main" animations 169 /// The movement animation is reserved for "main" animations
164 /// that are mutually exclusive, e.g. flying and sitting. 170 /// that are mutually exclusive, e.g. flying and sitting.
165 /// </summary> 171 /// </summary>
166 public void TrySetMovementAnimation(string anim) 172 /// <returns>'true' if the animation was updated</returns>
173 public bool TrySetMovementAnimation(string anim)
167 { 174 {
175 bool ret = false;
168 if (!m_scenePresence.IsChildAgent) 176 if (!m_scenePresence.IsChildAgent)
169 { 177 {
170// m_log.DebugFormat( 178// m_log.DebugFormat(
@@ -181,6 +189,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation
181 // 16384 is CHANGED_ANIMATION 189 // 16384 is CHANGED_ANIMATION
182 m_scenePresence.SendScriptEventToAttachments("changed", new Object[] { (int)Changed.ANIMATION}); 190 m_scenePresence.SendScriptEventToAttachments("changed", new Object[] { (int)Changed.ANIMATION});
183 SendAnimPack(); 191 SendAnimPack();
192 ret = true;
184 } 193 }
185 } 194 }
186 else 195 else
@@ -189,6 +198,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation
189 "[SCENE PRESENCE ANIMATOR]: Tried to set movement animation {0} on child presence {1}", 198 "[SCENE PRESENCE ANIMATOR]: Tried to set movement animation {0} on child presence {1}",
190 anim, m_scenePresence.Name); 199 anim, m_scenePresence.Name);
191 } 200 }
201 return ret;
192 } 202 }
193 203
194 /// <summary> 204 /// <summary>
@@ -393,11 +403,18 @@ namespace OpenSim.Region.Framework.Scenes.Animation
393 Falling = false; 403 Falling = false;
394 // Walking / crouchwalking / running 404 // Walking / crouchwalking / running
395 if (move.Z < 0f) 405 if (move.Z < 0f)
406 {
396 return "CROUCHWALK"; 407 return "CROUCHWALK";
397 else if (m_scenePresence.SetAlwaysRun) 408 }
398 return "RUN"; 409 // We need to prevent these animations if the user tries to make their avatar walk or run whilst
399 else 410 // specifying AGENT_CONTROL_STOP (pressing down space on viewers).
400 return "WALK"; 411 else if (!m_scenePresence.AgentControlStopActive)
412 {
413 if (m_scenePresence.SetAlwaysRun)
414 return "RUN";
415 else
416 return "WALK";
417 }
401 } 418 }
402 else if (!m_jumping) 419 else if (!m_jumping)
403 { 420 {
@@ -422,8 +439,12 @@ namespace OpenSim.Region.Framework.Scenes.Animation
422 /// <summary> 439 /// <summary>
423 /// Update the movement animation of this avatar according to its current state 440 /// Update the movement animation of this avatar according to its current state
424 /// </summary> 441 /// </summary>
425 public void UpdateMovementAnimations() 442 /// <returns>'true' if the animation was changed</returns>
443 public bool UpdateMovementAnimations()
426 { 444 {
445// m_log.DebugFormat("[SCENE PRESENCE ANIMATOR]: Updating movement animations for {0}", m_scenePresence.Name);
446
447 bool ret = false;
427 lock (m_animations) 448 lock (m_animations)
428 { 449 {
429 string newMovementAnimation = DetermineMovementAnimation(); 450 string newMovementAnimation = DetermineMovementAnimation();
@@ -437,9 +458,10 @@ namespace OpenSim.Region.Framework.Scenes.Animation
437 458
438 // Only set it if it's actually changed, give a script 459 // Only set it if it's actually changed, give a script
439 // a chance to stop a default animation 460 // a chance to stop a default animation
440 TrySetMovementAnimation(CurrentMovementAnimation); 461 ret = TrySetMovementAnimation(CurrentMovementAnimation);
441 } 462 }
442 } 463 }
464 return ret;
443 } 465 }
444 466
445 public UUID[] GetAnimationArray() 467 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
104 // better than losing the object for now. 104 // better than losing the object for now.
105 if (permissionToDelete) 105 if (permissionToDelete)
106 { 106 {
107 List<uint> killIDs = new List<uint>();
108
109 foreach (SceneObjectGroup g in objectGroups) 107 foreach (SceneObjectGroup g in objectGroups)
110 { killIDs.Add(g.LocalId); 108 g.DeleteGroupFromScene(false);
111 g.DeleteGroupFromScene(true);
112 }
113
114 m_scene.SendKillObject(killIDs);
115 } 109 }
116 } 110 }
117 111
@@ -160,7 +154,7 @@ namespace OpenSim.Region.Framework.Scenes
160 if (x.permissionToDelete) 154 if (x.permissionToDelete)
161 { 155 {
162 foreach (SceneObjectGroup g in x.objectGroups) 156 foreach (SceneObjectGroup g in x.objectGroups)
163 m_scene.DeleteSceneObject(g, false); 157 m_scene.DeleteSceneObject(g, true);
164 } 158 }
165 } 159 }
166 catch (Exception e) 160 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;
33namespace OpenSim.Region.Framework.Scenes 33namespace OpenSim.Region.Framework.Scenes
34{ 34{
35 public class Border 35 public class Border
36 { 36 {
37
38 /// <summary> 37 /// <summary>
39 /// Line perpendicular to the Direction Cardinal. Z value is the 38 /// Line perpendicular to the Direction Cardinal. Z value is the
40 /// </summary> 39 /// </summary>
@@ -81,6 +80,10 @@ namespace OpenSim.Region.Framework.Scenes
81 TriggerRegionY = triggerRegionY; 80 TriggerRegionY = triggerRegionY;
82 } 81 }
83 82
83 /// <summary>
84 /// Tests to see if the given position would cross this border.
85 /// </summary>
86 /// <returns></returns>
84 public bool TestCross(Vector3 position) 87 public bool TestCross(Vector3 position)
85 { 88 {
86 bool result = false; 89 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
144 /// Triggered when a new presence is added to the scene 144 /// Triggered when a new presence is added to the scene
145 /// </summary> 145 /// </summary>
146 /// <remarks> 146 /// <remarks>
147 /// Triggered in <see cref="OpenSim.Region.Framework.Scenes.Scene.AddNewClient"/> which is used by both 147 /// Triggered in <see cref="OpenSim.Region.Framework.Scenes.Scene.AddNewAgent"/> which is used by both
148 /// <see cref="OpenSim.Framework.PresenceType.User">users</see> and <see cref="OpenSim.Framework.PresenceType.Npc">NPCs</see> 148 /// <see cref="OpenSim.Framework.PresenceType.User">users</see> and <see cref="OpenSim.Framework.PresenceType.Npc">NPCs</see>
149 /// </remarks> 149 /// </remarks>
150 public event OnNewPresenceDelegate OnNewPresence; 150 public event OnNewPresenceDelegate OnNewPresence;
@@ -155,7 +155,7 @@ namespace OpenSim.Region.Framework.Scenes
155 /// Triggered when a presence is removed from the scene 155 /// Triggered when a presence is removed from the scene
156 /// </summary> 156 /// </summary>
157 /// <remarks> 157 /// <remarks>
158 /// Triggered in <see cref="OpenSim.Region.Framework.Scenes.Scene.AddNewClient"/> which is used by both 158 /// Triggered in <see cref="OpenSim.Region.Framework.Scenes.Scene.AddNewAgent"/> which is used by both
159 /// <see cref="OpenSim.Framework.PresenceType.User">users</see> and <see cref="OpenSim.Framework.PresenceType.Npc">NPCs</see> 159 /// <see cref="OpenSim.Framework.PresenceType.User">users</see> and <see cref="OpenSim.Framework.PresenceType.Npc">NPCs</see>
160 /// 160 ///
161 /// Triggered under per-agent lock. So if you want to perform any long-running operations, please 161 /// 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
339 /// in <see cref="Scene.SetScriptRunning"/> 339 /// in <see cref="Scene.SetScriptRunning"/>
340 /// via <see cref="OpenSim.Framework.IClientAPI.OnSetScriptRunning"/>, 340 /// via <see cref="OpenSim.Framework.IClientAPI.OnSetScriptRunning"/>,
341 /// via <see cref="OpenSim.Region.ClientStack.LindenUDP.HandleSetScriptRunning"/> 341 /// via <see cref="OpenSim.Region.ClientStack.LindenUDP.HandleSetScriptRunning"/>
342 /// XXX: This is only triggered when it is the client that starts the script, not in other situations where
343 /// a script is started, unlike OnStopScript!
342 /// </remarks> 344 /// </remarks>
343 public event StartScript OnStartScript; 345 public event StartScript OnStartScript;
344 346
@@ -352,6 +354,7 @@ namespace OpenSim.Region.Framework.Scenes
352 /// in <see cref="SceneObjectPartInventory.CreateScriptInstance"/>, 354 /// in <see cref="SceneObjectPartInventory.CreateScriptInstance"/>,
353 /// <see cref="SceneObjectPartInventory.StopScriptInstance"/>, 355 /// <see cref="SceneObjectPartInventory.StopScriptInstance"/>,
354 /// <see cref="Scene.SetScriptRunning"/> 356 /// <see cref="Scene.SetScriptRunning"/>
357 /// XXX: This is triggered when a sciprt is stopped for any reason, unlike OnStartScript!
355 /// </remarks> 358 /// </remarks>
356 public event StopScript OnStopScript; 359 public event StopScript OnStopScript;
357 360
@@ -427,6 +430,9 @@ namespace OpenSim.Region.Framework.Scenes
427 public delegate void IncomingInstantMessage(GridInstantMessage message); 430 public delegate void IncomingInstantMessage(GridInstantMessage message);
428 public event IncomingInstantMessage OnIncomingInstantMessage; 431 public event IncomingInstantMessage OnIncomingInstantMessage;
429 432
433 public delegate void CrossAgentToNewRegion(ScenePresence sp, bool isFlying, GridRegion newRegion);
434 public event CrossAgentToNewRegion OnCrossAgentToNewRegion;
435
430 public event IncomingInstantMessage OnUnhandledInstantMessage; 436 public event IncomingInstantMessage OnUnhandledInstantMessage;
431 437
432 public delegate void ClientClosed(UUID clientID, Scene scene); 438 public delegate void ClientClosed(UUID clientID, Scene scene);
@@ -546,6 +552,20 @@ namespace OpenSim.Region.Framework.Scenes
546 /// </remarks> 552 /// </remarks>
547 public event ScriptControlEvent OnScriptControlEvent; 553 public event ScriptControlEvent OnScriptControlEvent;
548 554
555 public delegate void ScriptMovingStartEvent(uint localID);
556
557 /// <summary>
558 /// TODO: Should be triggered when a physics object starts moving.
559 /// </summary>
560 public event ScriptMovingStartEvent OnScriptMovingStartEvent;
561
562 public delegate void ScriptMovingEndEvent(uint localID);
563
564 /// <summary>
565 /// TODO: Should be triggered when a physics object stops moving.
566 /// </summary>
567 public event ScriptMovingEndEvent OnScriptMovingEndEvent;
568
549 public delegate void ScriptAtTargetEvent(uint localID, uint handle, Vector3 targetpos, Vector3 atpos); 569 public delegate void ScriptAtTargetEvent(uint localID, uint handle, Vector3 targetpos, Vector3 atpos);
550 570
551 /// <summary> 571 /// <summary>
@@ -612,8 +632,8 @@ namespace OpenSim.Region.Framework.Scenes
612 /// Triggered by <see cref="TriggerScriptCollidingStart"/> 632 /// Triggered by <see cref="TriggerScriptCollidingStart"/>
613 /// in <see cref="SceneObjectPart.SendCollisionEvent"/> 633 /// in <see cref="SceneObjectPart.SendCollisionEvent"/>
614 /// via <see cref="SceneObjectPart.PhysicsCollision"/> 634 /// via <see cref="SceneObjectPart.PhysicsCollision"/>
615 /// via <see cref="OpenSim.Region.Physics.Manager.PhysicsActor.OnCollisionUpdate"/> 635 /// via <see cref="OpenSim.Region.PhysicsModule.SharedBase.PhysicsActor.OnCollisionUpdate"/>
616 /// via <see cref="OpenSim.Region.Physics.Manager.PhysicsActor.SendCollisionUpdate"/> 636 /// via <see cref="OpenSim.Region.PhysicsModule.SharedBase.PhysicsActor.SendCollisionUpdate"/>
617 /// </remarks> 637 /// </remarks>
618 public event ScriptColliding OnScriptColliderStart; 638 public event ScriptColliding OnScriptColliderStart;
619 639
@@ -626,8 +646,8 @@ namespace OpenSim.Region.Framework.Scenes
626 /// Triggered by <see cref="TriggerScriptColliding"/> 646 /// Triggered by <see cref="TriggerScriptColliding"/>
627 /// in <see cref="SceneObjectPart.SendCollisionEvent"/> 647 /// in <see cref="SceneObjectPart.SendCollisionEvent"/>
628 /// via <see cref="SceneObjectPart.PhysicsCollision"/> 648 /// via <see cref="SceneObjectPart.PhysicsCollision"/>
629 /// via <see cref="OpenSim.Region.Physics.Manager.PhysicsActor.OnCollisionUpdate"/> 649 /// via <see cref="OpenSim.Region.PhysicsModule.SharedBase.PhysicsActor.OnCollisionUpdate"/>
630 /// via <see cref="OpenSim.Region.Physics.Manager.PhysicsActor.SendCollisionUpdate"/> 650 /// via <see cref="OpenSim.Region.PhysicsModule.SharedBase.PhysicsActor.SendCollisionUpdate"/>
631 /// </remarks> 651 /// </remarks>
632 public event ScriptColliding OnScriptColliding; 652 public event ScriptColliding OnScriptColliding;
633 653
@@ -639,8 +659,8 @@ namespace OpenSim.Region.Framework.Scenes
639 /// Triggered by <see cref="TriggerScriptCollidingEnd"/> 659 /// Triggered by <see cref="TriggerScriptCollidingEnd"/>
640 /// in <see cref="SceneObjectPart.SendCollisionEvent"/> 660 /// in <see cref="SceneObjectPart.SendCollisionEvent"/>
641 /// via <see cref="SceneObjectPart.PhysicsCollision"/> 661 /// via <see cref="SceneObjectPart.PhysicsCollision"/>
642 /// via <see cref="OpenSim.Region.Physics.Manager.PhysicsActor.OnCollisionUpdate"/> 662 /// via <see cref="OpenSim.Region.PhysicsModule.SharedBase.PhysicsActor.OnCollisionUpdate"/>
643 /// via <see cref="OpenSim.Region.Physics.Manager.PhysicsActor.SendCollisionUpdate"/> 663 /// via <see cref="OpenSim.Region.PhysicsModule.SharedBase.PhysicsActor.SendCollisionUpdate"/>
644 /// </remarks> 664 /// </remarks>
645 public event ScriptColliding OnScriptCollidingEnd; 665 public event ScriptColliding OnScriptCollidingEnd;
646 666
@@ -652,8 +672,8 @@ namespace OpenSim.Region.Framework.Scenes
652 /// Triggered by <see cref="TriggerScriptLandCollidingStart"/> 672 /// Triggered by <see cref="TriggerScriptLandCollidingStart"/>
653 /// in <see cref="SceneObjectPart.SendLandCollisionEvent"/> 673 /// in <see cref="SceneObjectPart.SendLandCollisionEvent"/>
654 /// via <see cref="SceneObjectPart.PhysicsCollision"/> 674 /// via <see cref="SceneObjectPart.PhysicsCollision"/>
655 /// via <see cref="OpenSim.Region.Physics.Manager.PhysicsActor.OnCollisionUpdate"/> 675 /// via <see cref="OpenSim.Region.PhysicsModule.SharedBase.PhysicsActor.OnCollisionUpdate"/>
656 /// via <see cref="OpenSim.Region.Physics.Manager.PhysicsActor.SendCollisionUpdate"/> 676 /// via <see cref="OpenSim.Region.PhysicsModule.SharedBase.PhysicsActor.SendCollisionUpdate"/>
657 /// </remarks> 677 /// </remarks>
658 public event ScriptColliding OnScriptLandColliderStart; 678 public event ScriptColliding OnScriptLandColliderStart;
659 679
@@ -665,8 +685,8 @@ namespace OpenSim.Region.Framework.Scenes
665 /// Triggered by <see cref="TriggerScriptLandColliding"/> 685 /// Triggered by <see cref="TriggerScriptLandColliding"/>
666 /// in <see cref="SceneObjectPart.SendLandCollisionEvent"/> 686 /// in <see cref="SceneObjectPart.SendLandCollisionEvent"/>
667 /// via <see cref="SceneObjectPart.PhysicsCollision"/> 687 /// via <see cref="SceneObjectPart.PhysicsCollision"/>
668 /// via <see cref="OpenSim.Region.Physics.Manager.PhysicsActor.OnCollisionUpdate"/> 688 /// via <see cref="OpenSim.Region.PhysicsModule.SharedBase.PhysicsActor.OnCollisionUpdate"/>
669 /// via <see cref="OpenSim.Region.Physics.Manager.PhysicsActor.SendCollisionUpdate"/> 689 /// via <see cref="OpenSim.Region.PhysicsModule.SharedBase.PhysicsActor.SendCollisionUpdate"/>
670 /// </remarks> 690 /// </remarks>
671 public event ScriptColliding OnScriptLandColliding; 691 public event ScriptColliding OnScriptLandColliding;
672 692
@@ -678,8 +698,8 @@ namespace OpenSim.Region.Framework.Scenes
678 /// Triggered by <see cref="TriggerScriptLandCollidingEnd"/> 698 /// Triggered by <see cref="TriggerScriptLandCollidingEnd"/>
679 /// in <see cref="SceneObjectPart.SendLandCollisionEvent"/> 699 /// in <see cref="SceneObjectPart.SendLandCollisionEvent"/>
680 /// via <see cref="SceneObjectPart.PhysicsCollision"/> 700 /// via <see cref="SceneObjectPart.PhysicsCollision"/>
681 /// via <see cref="OpenSim.Region.Physics.Manager.PhysicsActor.OnCollisionUpdate"/> 701 /// via <see cref="OpenSim.Region.PhysicsModule.SharedBase.PhysicsActor.OnCollisionUpdate"/>
682 /// via <see cref="OpenSim.Region.Physics.Manager.PhysicsActor.SendCollisionUpdate"/> 702 /// via <see cref="OpenSim.Region.PhysicsModule.SharedBase.PhysicsActor.SendCollisionUpdate"/>
683 /// </remarks> 703 /// </remarks>
684 public event ScriptColliding OnScriptLandColliderEnd; 704 public event ScriptColliding OnScriptLandColliderEnd;
685 705
@@ -725,7 +745,7 @@ namespace OpenSim.Region.Framework.Scenes
725 public event OnIncomingSceneObjectDelegate OnIncomingSceneObject; 745 public event OnIncomingSceneObjectDelegate OnIncomingSceneObject;
726 public delegate void OnIncomingSceneObjectDelegate(SceneObjectGroup so); 746 public delegate void OnIncomingSceneObjectDelegate(SceneObjectGroup so);
727 747
728 public delegate void NewInventoryItemUploadComplete(UUID avatarID, UUID assetID, string name, int userlevel); 748 public delegate void NewInventoryItemUploadComplete(UUID avatarID, AssetType type, UUID assetID, string name, int userlevel);
729 749
730 public event NewInventoryItemUploadComplete OnNewInventoryItemUploadComplete; 750 public event NewInventoryItemUploadComplete OnNewInventoryItemUploadComplete;
731 751
@@ -751,7 +771,7 @@ namespace OpenSim.Region.Framework.Scenes
751 public event ScriptTimerEvent OnScriptTimerEvent; 771 public event ScriptTimerEvent OnScriptTimerEvent;
752 */ 772 */
753 773
754 public delegate void EstateToolsSunUpdate(ulong regionHandle, bool FixedTime, bool EstateSun, float LindenHour); 774 public delegate void EstateToolsSunUpdate(ulong regionHandle);
755 public delegate void GetScriptRunning(IClientAPI controllingClient, UUID objectID, UUID itemID); 775 public delegate void GetScriptRunning(IClientAPI controllingClient, UUID objectID, UUID itemID);
756 776
757 public event EstateToolsSunUpdate OnEstateToolsSunUpdate; 777 public event EstateToolsSunUpdate OnEstateToolsSunUpdate;
@@ -766,12 +786,20 @@ namespace OpenSim.Region.Framework.Scenes
766 /// <see cref="Scene.doObjectDuplicateOnRay"/> 786 /// <see cref="Scene.doObjectDuplicateOnRay"/>
767 /// </remarks> 787 /// </remarks>
768 public event Action<SceneObjectGroup> OnObjectAddedToScene; 788 public event Action<SceneObjectGroup> OnObjectAddedToScene;
769 789
770 /// <summary> 790 /// <summary>
771 /// Delegate for <see cref="OnObjectBeingRemovedFromScene"/> 791 /// When a client sends a derez request for an object inworld
792 /// but before the object is deleted
772 /// </summary> 793 /// </summary>
773 /// <param name="obj">The object being removed from the scene</param> 794 public event DeRezRequested OnDeRezRequested;
774 public delegate void ObjectBeingRemovedFromScene(SceneObjectGroup obj); 795 /// <summary>
796 /// Triggered when a client sends a derez request for an object inworld
797 /// </summary>
798 /// <param name="remoteClient">The client question (it can be null)</param>
799 /// <param name="obj">The object in question</param>
800 /// <param name="action">The exact derez action</param>
801 /// <returns>Flag indicating whether the object should be deleted from the scene or not</returns>
802 public delegate bool DeRezRequested(IClientAPI remoteClient, List<SceneObjectGroup> objs, DeRezAction action);
775 803
776 /// <summary> 804 /// <summary>
777 /// Triggered when an object is removed from the scene. 805 /// Triggered when an object is removed from the scene.
@@ -781,6 +809,24 @@ namespace OpenSim.Region.Framework.Scenes
781 /// in <see cref="Scene.DeleteSceneObject"/> 809 /// in <see cref="Scene.DeleteSceneObject"/>
782 /// </remarks> 810 /// </remarks>
783 public event ObjectBeingRemovedFromScene OnObjectBeingRemovedFromScene; 811 public event ObjectBeingRemovedFromScene OnObjectBeingRemovedFromScene;
812 /// <summary>
813 /// Delegate for <see cref="OnObjectBeingRemovedFromScene"/>
814 /// </summary>
815 /// <param name="obj">The object being removed from the scene</param>
816 public delegate void ObjectBeingRemovedFromScene(SceneObjectGroup obj);
817
818 /// <summary>
819 /// Triggered when an object is placed into the physical scene (PhysicsActor created).
820 /// </summary>
821 public event Action<SceneObjectPart> OnObjectAddedToPhysicalScene;
822 /// <summary>
823 /// Triggered when an object is removed from the physical scene (PhysicsActor destroyed).
824 /// </summary>
825 /// <remarks>
826 /// Note: this is triggered just before the PhysicsActor is removed from the
827 /// physics engine so the receiver can do any necessary cleanup before its destruction.
828 /// </remarks>
829 public event Action<SceneObjectPart> OnObjectRemovedFromPhysicalScene;
784 830
785 public delegate void NoticeNoLandDataFromStorage(); 831 public delegate void NoticeNoLandDataFromStorage();
786 public event NoticeNoLandDataFromStorage OnNoticeNoLandDataFromStorage; 832 public event NoticeNoLandDataFromStorage OnNoticeNoLandDataFromStorage;
@@ -939,6 +985,8 @@ namespace OpenSim.Region.Framework.Scenes
939 public delegate void RegionStarted(Scene scene); 985 public delegate void RegionStarted(Scene scene);
940 public event RegionStarted OnRegionStarted; 986 public event RegionStarted OnRegionStarted;
941 987
988 public delegate void RegionHeartbeatStart(Scene scene);
989 public event RegionHeartbeatStart OnRegionHeartbeatStart;
942 public delegate void RegionHeartbeatEnd(Scene scene); 990 public delegate void RegionHeartbeatEnd(Scene scene);
943 public event RegionHeartbeatEnd OnRegionHeartbeatEnd; 991 public event RegionHeartbeatEnd OnRegionHeartbeatEnd;
944 992
@@ -989,6 +1037,16 @@ namespace OpenSim.Region.Framework.Scenes
989 /// </remarks> 1037 /// </remarks>
990 public event TeleportFail OnTeleportFail; 1038 public event TeleportFail OnTeleportFail;
991 1039
1040// public delegate void GatherUuids(SceneObjectPart sop, IDictionary<UUID, AssetType> assetUuids);
1041//
1042// /// <summary>
1043// /// Triggered when UUIDs referenced by a scene object are being gathered for archiving, hg transfer, etc.
1044// /// </summary>
1045// /// <remarks>
1046// /// The listener should add references to the IDictionary<UUID, AssetType> as appropriate.
1047// /// </remarks>
1048// public event GatherUuids OnGatherUuids;
1049
992 public class MoneyTransferArgs : EventArgs 1050 public class MoneyTransferArgs : EventArgs
993 { 1051 {
994 public UUID sender; 1052 public UUID sender;
@@ -1060,7 +1118,7 @@ namespace OpenSim.Region.Framework.Scenes
1060 /// Triggered in <see cref="OpenSim.Region.Framework.Scenes.Scene.ProcessMoneyTransferRequest"/> 1118 /// Triggered in <see cref="OpenSim.Region.Framework.Scenes.Scene.ProcessMoneyTransferRequest"/>
1061 /// via <see cref="OpenSim.Region.Framework.Scenes.Scene.SubscribeToClientGridEvents"/> 1119 /// via <see cref="OpenSim.Region.Framework.Scenes.Scene.SubscribeToClientGridEvents"/>
1062 /// via <see cref="OpenSim.Region.Framework.Scenes.Scene.SubscribeToClientEvents"/> 1120 /// via <see cref="OpenSim.Region.Framework.Scenes.Scene.SubscribeToClientEvents"/>
1063 /// via <see cref="OpenSim.Region.Framework.Scenes.Scene.AddNewClient"/> 1121 /// via <see cref="OpenSim.Region.Framework.Scenes.Scene.AddNewAgent"/>
1064 /// </remarks> 1122 /// </remarks>
1065 public event MoneyTransferEvent OnMoneyTransfer; 1123 public event MoneyTransferEvent OnMoneyTransfer;
1066 1124
@@ -1476,8 +1534,33 @@ namespace OpenSim.Region.Framework.Scenes
1476 } 1534 }
1477 } 1535 }
1478 } 1536 }
1479 } 1537 }
1480 1538
1539 public bool TriggerDeRezRequested(IClientAPI client, List<SceneObjectGroup> objs, DeRezAction action)
1540 {
1541 bool canDeRez = true;
1542
1543 DeRezRequested handlerDeRezRequested = OnDeRezRequested;
1544 if (handlerDeRezRequested != null)
1545 {
1546 foreach (DeRezRequested d in handlerDeRezRequested.GetInvocationList())
1547 {
1548 try
1549 {
1550 canDeRez &= d(client, objs, action);
1551 }
1552 catch (Exception e)
1553 {
1554 m_log.ErrorFormat(
1555 "[EVENT MANAGER]: Delegate for TriggerDeRezRequested failed - continuing. {0} {1}",
1556 e.Message, e.StackTrace);
1557 }
1558 }
1559 }
1560
1561 return canDeRez;
1562 }
1563
1481 public void TriggerObjectBeingRemovedFromScene(SceneObjectGroup obj) 1564 public void TriggerObjectBeingRemovedFromScene(SceneObjectGroup obj)
1482 { 1565 {
1483 ObjectBeingRemovedFromScene handlerObjectBeingRemovedFromScene = OnObjectBeingRemovedFromScene; 1566 ObjectBeingRemovedFromScene handlerObjectBeingRemovedFromScene = OnObjectBeingRemovedFromScene;
@@ -1499,6 +1582,48 @@ namespace OpenSim.Region.Framework.Scenes
1499 } 1582 }
1500 } 1583 }
1501 1584
1585 public void TriggerObjectAddedToPhysicalScene(SceneObjectPart obj)
1586 {
1587 Action<SceneObjectPart> handler = OnObjectAddedToPhysicalScene;
1588 if (handler != null)
1589 {
1590 foreach (Action<SceneObjectPart> d in handler.GetInvocationList())
1591 {
1592 try
1593 {
1594 d(obj);
1595 }
1596 catch (Exception e)
1597 {
1598 m_log.ErrorFormat(
1599 "[EVENT MANAGER]: Delegate for TriggerObjectAddedToPhysicalScene failed - continuing. {0} {1}",
1600 e.Message, e.StackTrace);
1601 }
1602 }
1603 }
1604 }
1605
1606 public void TriggerObjectRemovedFromPhysicalScene(SceneObjectPart obj)
1607 {
1608 Action<SceneObjectPart> handler = OnObjectRemovedFromPhysicalScene;
1609 if (handler != null)
1610 {
1611 foreach (Action<SceneObjectPart> d in handler.GetInvocationList())
1612 {
1613 try
1614 {
1615 d(obj);
1616 }
1617 catch (Exception e)
1618 {
1619 m_log.ErrorFormat(
1620 "[EVENT MANAGER]: Delegate for TriggerObjectRemovedFromPhysicalScene failed - continuing. {0} {1}",
1621 e.Message, e.StackTrace);
1622 }
1623 }
1624 }
1625 }
1626
1502 public void TriggerShutdown() 1627 public void TriggerShutdown()
1503 { 1628 {
1504 Action handlerShutdown = OnShutdown; 1629 Action handlerShutdown = OnShutdown;
@@ -1876,6 +2001,27 @@ namespace OpenSim.Region.Framework.Scenes
1876 } 2001 }
1877 } 2002 }
1878 2003
2004 public void TriggerCrossAgentToNewRegion(ScenePresence agent, bool isFlying, GridRegion newRegion)
2005 {
2006 CrossAgentToNewRegion handlerCrossAgentToNewRegion = OnCrossAgentToNewRegion;
2007 if (handlerCrossAgentToNewRegion != null)
2008 {
2009 foreach (CrossAgentToNewRegion d in handlerCrossAgentToNewRegion.GetInvocationList())
2010 {
2011 try
2012 {
2013 d(agent, isFlying, newRegion);
2014 }
2015 catch (Exception e)
2016 {
2017 m_log.ErrorFormat(
2018 "[EVENT MANAGER]: Delegate for TriggerCrossAgentToNewRegion failed - continuing. {0} {1}",
2019 e.Message, e.StackTrace);
2020 }
2021 }
2022 }
2023 }
2024
1879 public void TriggerIncomingInstantMessage(GridInstantMessage message) 2025 public void TriggerIncomingInstantMessage(GridInstantMessage message)
1880 { 2026 {
1881 IncomingInstantMessage handlerIncomingInstantMessage = OnIncomingInstantMessage; 2027 IncomingInstantMessage handlerIncomingInstantMessage = OnIncomingInstantMessage;
@@ -2062,7 +2208,7 @@ namespace OpenSim.Region.Framework.Scenes
2062 } 2208 }
2063 } 2209 }
2064 2210
2065 public void TriggerOnNewInventoryItemUploadComplete(UUID agentID, UUID AssetID, String AssetName, int userlevel) 2211 public void TriggerOnNewInventoryItemUploadComplete(UUID agentID, AssetType type, UUID AssetID, String AssetName, int userlevel)
2066 { 2212 {
2067 NewInventoryItemUploadComplete handlerNewInventoryItemUpdateComplete = OnNewInventoryItemUploadComplete; 2213 NewInventoryItemUploadComplete handlerNewInventoryItemUpdateComplete = OnNewInventoryItemUploadComplete;
2068 if (handlerNewInventoryItemUpdateComplete != null) 2214 if (handlerNewInventoryItemUpdateComplete != null)
@@ -2071,7 +2217,7 @@ namespace OpenSim.Region.Framework.Scenes
2071 { 2217 {
2072 try 2218 try
2073 { 2219 {
2074 d(agentID, AssetID, AssetName, userlevel); 2220 d(agentID, type, AssetID, AssetName, userlevel);
2075 } 2221 }
2076 catch (Exception e) 2222 catch (Exception e)
2077 { 2223 {
@@ -2209,6 +2355,48 @@ namespace OpenSim.Region.Framework.Scenes
2209 } 2355 }
2210 } 2356 }
2211 2357
2358 public void TriggerMovingStartEvent(uint localID)
2359 {
2360 ScriptMovingStartEvent handlerScriptMovingStartEvent = OnScriptMovingStartEvent;
2361 if (handlerScriptMovingStartEvent != null)
2362 {
2363 foreach (ScriptMovingStartEvent d in handlerScriptMovingStartEvent.GetInvocationList())
2364 {
2365 try
2366 {
2367 d(localID);
2368 }
2369 catch (Exception e)
2370 {
2371 m_log.ErrorFormat(
2372 "[EVENT MANAGER]: Delegate for TriggerMovingStartEvent failed - continuing. {0} {1}",
2373 e.Message, e.StackTrace);
2374 }
2375 }
2376 }
2377 }
2378
2379 public void TriggerMovingEndEvent(uint localID)
2380 {
2381 ScriptMovingEndEvent handlerScriptMovingEndEvent = OnScriptMovingEndEvent;
2382 if (handlerScriptMovingEndEvent != null)
2383 {
2384 foreach (ScriptMovingEndEvent d in handlerScriptMovingEndEvent.GetInvocationList())
2385 {
2386 try
2387 {
2388 d(localID);
2389 }
2390 catch (Exception e)
2391 {
2392 m_log.ErrorFormat(
2393 "[EVENT MANAGER]: Delegate for TriggerMovingEndEvent failed - continuing. {0} {1}",
2394 e.Message, e.StackTrace);
2395 }
2396 }
2397 }
2398 }
2399
2212 public void TriggerRequestChangeWaterHeight(float height) 2400 public void TriggerRequestChangeWaterHeight(float height)
2213 { 2401 {
2214 if (height < 0) 2402 if (height < 0)
@@ -2507,13 +2695,10 @@ namespace OpenSim.Region.Framework.Scenes
2507 } 2695 }
2508 2696
2509 /// <summary> 2697 /// <summary>
2510 /// Updates the system as to how the position of the sun should be handled. 2698 /// Called when the sun's position parameters have changed in the Region and/or Estate
2511 /// </summary> 2699 /// </summary>
2512 /// <param name="regionHandle"></param> 2700 /// <param name="regionHandle">The region that changed</param>
2513 /// <param name="FixedTime">True if the Sun Position is fixed</param> 2701 public void TriggerEstateToolsSunUpdate(ulong regionHandle)
2514 /// <param name="useEstateTime">True if the Estate Settings should be used instead of region</param>
2515 /// <param name="FixedSunHour">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</param>
2516 public void TriggerEstateToolsSunUpdate(ulong regionHandle, bool FixedTime, bool useEstateTime, float FixedSunHour)
2517 { 2702 {
2518 EstateToolsSunUpdate handlerEstateToolsSunUpdate = OnEstateToolsSunUpdate; 2703 EstateToolsSunUpdate handlerEstateToolsSunUpdate = OnEstateToolsSunUpdate;
2519 if (handlerEstateToolsSunUpdate != null) 2704 if (handlerEstateToolsSunUpdate != null)
@@ -2522,7 +2707,7 @@ namespace OpenSim.Region.Framework.Scenes
2522 { 2707 {
2523 try 2708 try
2524 { 2709 {
2525 d(regionHandle, FixedTime, useEstateTime, FixedSunHour); 2710 d(regionHandle);
2526 } 2711 }
2527 catch (Exception e) 2712 catch (Exception e)
2528 { 2713 {
@@ -2957,6 +3142,27 @@ namespace OpenSim.Region.Framework.Scenes
2957 } 3142 }
2958 } 3143 }
2959 3144
3145 public void TriggerRegionHeartbeatStart(Scene scene)
3146 {
3147 RegionHeartbeatStart handler = OnRegionHeartbeatStart;
3148
3149 if (handler != null)
3150 {
3151 foreach (RegionHeartbeatStart d in handler.GetInvocationList())
3152 {
3153 try
3154 {
3155 d(scene);
3156 }
3157 catch (Exception e)
3158 {
3159 m_log.ErrorFormat("[EVENT MANAGER]: Delegate for OnRegionHeartbeatStart failed - continuing {0} - {1}",
3160 e.Message, e.StackTrace);
3161 }
3162 }
3163 }
3164 }
3165
2960 public void TriggerRegionHeartbeatEnd(Scene scene) 3166 public void TriggerRegionHeartbeatEnd(Scene scene)
2961 { 3167 {
2962 RegionHeartbeatEnd handler = OnRegionHeartbeatEnd; 3168 RegionHeartbeatEnd handler = OnRegionHeartbeatEnd;
@@ -3103,5 +3309,26 @@ namespace OpenSim.Region.Framework.Scenes
3103 } 3309 }
3104 } 3310 }
3105 } 3311 }
3312
3313// public void TriggerGatherUuids(SceneObjectPart sop, IDictionary<UUID, AssetType> assetUuids)
3314// {
3315// GatherUuids handler = OnGatherUuids;
3316//
3317// if (handler != null)
3318// {
3319// foreach (GatherUuids d in handler.GetInvocationList())
3320// {
3321// try
3322// {
3323// d(sop, assetUuids);
3324// }
3325// catch (Exception e)
3326// {
3327// m_log.ErrorFormat("[EVENT MANAGER]: Delegate for TriggerUuidGather failed - continuing {0} - {1}",
3328// e.Message, e.StackTrace);
3329// }
3330// }
3331// }
3332// }
3106 } 3333 }
3107} 3334}
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 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Timers;
30using System.Collections;
31using System.Collections.Generic;
32using System.IO;
33using System.Diagnostics;
34using System.Reflection;
35using System.Threading;
36using OpenMetaverse;
37using OpenSim.Framework;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.PhysicsModules.SharedBase;
40using OpenSim.Region.Framework.Scenes.Serialization;
41using System.Runtime.Serialization.Formatters.Binary;
42using System.Runtime.Serialization;
43using Timer = System.Timers.Timer;
44using log4net;
45
46namespace OpenSim.Region.Framework.Scenes
47{
48 public class KeyframeTimer
49 {
50 private static Dictionary<Scene, KeyframeTimer> m_timers =
51 new Dictionary<Scene, KeyframeTimer>();
52
53 private Timer m_timer;
54 private Dictionary<KeyframeMotion, object> m_motions = new Dictionary<KeyframeMotion, object>();
55 private object m_lockObject = new object();
56 private object m_timerLock = new object();
57 private const double m_tickDuration = 50.0;
58
59 public double TickDuration
60 {
61 get { return m_tickDuration; }
62 }
63
64 public KeyframeTimer(Scene scene)
65 {
66 m_timer = new Timer();
67 m_timer.Interval = TickDuration;
68 m_timer.AutoReset = true;
69 m_timer.Elapsed += OnTimer;
70 }
71
72 public void Start()
73 {
74 lock (m_timer)
75 {
76 if (!m_timer.Enabled)
77 m_timer.Start();
78 }
79 }
80
81 private void OnTimer(object sender, ElapsedEventArgs ea)
82 {
83 if (!Monitor.TryEnter(m_timerLock))
84 return;
85
86 try
87 {
88 List<KeyframeMotion> motions;
89
90 lock (m_lockObject)
91 {
92 motions = new List<KeyframeMotion>(m_motions.Keys);
93 }
94
95 foreach (KeyframeMotion m in motions)
96 {
97 try
98 {
99 m.OnTimer(TickDuration);
100 }
101 catch (Exception)
102 {
103 // Don't stop processing
104 }
105 }
106 }
107 catch (Exception)
108 {
109 // Keep running no matter what
110 }
111 finally
112 {
113 Monitor.Exit(m_timerLock);
114 }
115 }
116
117 public static void Add(KeyframeMotion motion)
118 {
119 KeyframeTimer timer;
120
121 if (motion.Scene == null)
122 return;
123
124 lock (m_timers)
125 {
126 if (!m_timers.TryGetValue(motion.Scene, out timer))
127 {
128 timer = new KeyframeTimer(motion.Scene);
129 m_timers[motion.Scene] = timer;
130
131 if (!SceneManager.Instance.AllRegionsReady)
132 {
133 // Start the timers only once all the regions are ready. This is required
134 // when using megaregions, because the megaregion is correctly configured
135 // only after all the regions have been loaded. (If we don't do this then
136 // when the prim moves it might think that it crossed into a region.)
137 SceneManager.Instance.OnRegionsReadyStatusChange += delegate(SceneManager sm)
138 {
139 if (sm.AllRegionsReady)
140 timer.Start();
141 };
142 }
143
144 // Check again, in case the regions were started while we were adding the event handler
145 if (SceneManager.Instance.AllRegionsReady)
146 {
147 timer.Start();
148 }
149 }
150 }
151
152 lock (timer.m_lockObject)
153 {
154 timer.m_motions[motion] = null;
155 }
156 }
157
158 public static void Remove(KeyframeMotion motion)
159 {
160 KeyframeTimer timer;
161
162 if (motion.Scene == null)
163 return;
164
165 lock (m_timers)
166 {
167 if (!m_timers.TryGetValue(motion.Scene, out timer))
168 {
169 return;
170 }
171 }
172
173 lock (timer.m_lockObject)
174 {
175 timer.m_motions.Remove(motion);
176 }
177 }
178 }
179
180 [Serializable]
181 public class KeyframeMotion
182 {
183 //private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
184
185 public enum PlayMode : int
186 {
187 Forward = 0,
188 Reverse = 1,
189 Loop = 2,
190 PingPong = 3
191 };
192
193 [Flags]
194 public enum DataFormat : int
195 {
196 Translation = 2,
197 Rotation = 1
198 }
199
200 [Serializable]
201 public struct Keyframe
202 {
203 public Vector3? Position;
204 public Quaternion? Rotation;
205 public Quaternion StartRotation;
206 public int TimeMS;
207 public int TimeTotal;
208 public Vector3 AngularVelocity;
209 public Vector3 StartPosition;
210 };
211
212 private Vector3 m_serializedPosition;
213 private Vector3 m_basePosition;
214 private Quaternion m_baseRotation;
215
216 private Keyframe m_currentFrame;
217
218 private List<Keyframe> m_frames = new List<Keyframe>();
219
220 private Keyframe[] m_keyframes;
221
222 // skip timer events.
223 //timer.stop doesn't assure there aren't event threads still being fired
224 [NonSerialized()]
225 private bool m_timerStopped;
226
227 [NonSerialized()]
228 private bool m_isCrossing;
229
230 [NonSerialized()]
231 private bool m_waitingCrossing;
232
233 // retry position for cross fail
234 [NonSerialized()]
235 private Vector3 m_nextPosition;
236
237 [NonSerialized()]
238 private SceneObjectGroup m_group;
239
240 private PlayMode m_mode = PlayMode.Forward;
241 private DataFormat m_data = DataFormat.Translation | DataFormat.Rotation;
242
243 private bool m_running = false;
244
245 [NonSerialized()]
246 private bool m_selected = false;
247
248 private int m_iterations = 0;
249
250 private int m_skipLoops = 0;
251
252 [NonSerialized()]
253 private Scene m_scene;
254
255 public Scene Scene
256 {
257 get { return m_scene; }
258 }
259
260 public DataFormat Data
261 {
262 get { return m_data; }
263 }
264
265 public bool Selected
266 {
267 set
268 {
269 if (m_group != null)
270 {
271 if (!value)
272 {
273 // Once we're let go, recompute positions
274 if (m_selected)
275 UpdateSceneObject(m_group);
276 }
277 else
278 {
279 // Save selection position in case we get moved
280 if (!m_selected)
281 {
282 StopTimer();
283 m_serializedPosition = m_group.AbsolutePosition;
284 }
285 }
286 }
287 m_isCrossing = false;
288 m_waitingCrossing = false;
289 m_selected = value;
290 }
291 }
292
293 private void StartTimer()
294 {
295 KeyframeTimer.Add(this);
296 m_timerStopped = false;
297 }
298
299 private void StopTimer()
300 {
301 m_timerStopped = true;
302 KeyframeTimer.Remove(this);
303 }
304
305 public static KeyframeMotion FromData(SceneObjectGroup grp, Byte[] data)
306 {
307 KeyframeMotion newMotion = null;
308
309 try
310 {
311 using (MemoryStream ms = new MemoryStream(data))
312 {
313 BinaryFormatter fmt = new BinaryFormatter();
314 newMotion = (KeyframeMotion)fmt.Deserialize(ms);
315 }
316
317 newMotion.m_group = grp;
318
319 if (grp != null)
320 {
321 newMotion.m_scene = grp.Scene;
322 if (grp.IsSelected)
323 newMotion.m_selected = true;
324 }
325
326 newMotion.m_timerStopped = false;
327 newMotion.m_running = true;
328 newMotion.m_isCrossing = false;
329 newMotion.m_waitingCrossing = false;
330 }
331 catch
332 {
333 newMotion = null;
334 }
335
336 return newMotion;
337 }
338
339 public void UpdateSceneObject(SceneObjectGroup grp)
340 {
341 m_isCrossing = false;
342 m_waitingCrossing = false;
343 StopTimer();
344
345 if (grp == null)
346 return;
347
348 m_group = grp;
349 m_scene = grp.Scene;
350
351 Vector3 grppos = grp.AbsolutePosition;
352 Vector3 offset = grppos - m_serializedPosition;
353 // avoid doing it more than once
354 // current this will happen dragging a prim to other region
355 m_serializedPosition = grppos;
356
357 m_basePosition += offset;
358 m_nextPosition += offset;
359
360 m_currentFrame.StartPosition += offset;
361 m_currentFrame.Position += offset;
362
363 for (int i = 0; i < m_frames.Count; i++)
364 {
365 Keyframe k = m_frames[i];
366 k.StartPosition += offset;
367 k.Position += offset;
368 m_frames[i]=k;
369 }
370
371 if (m_running)
372 Start();
373 }
374
375 public KeyframeMotion(SceneObjectGroup grp, PlayMode mode, DataFormat data)
376 {
377 m_mode = mode;
378 m_data = data;
379
380 m_group = grp;
381 if (grp != null)
382 {
383 m_basePosition = grp.AbsolutePosition;
384 m_baseRotation = grp.GroupRotation;
385 m_scene = grp.Scene;
386 }
387
388 m_timerStopped = true;
389 m_isCrossing = false;
390 m_waitingCrossing = false;
391 }
392
393 public void SetKeyframes(Keyframe[] frames)
394 {
395 m_keyframes = frames;
396 }
397
398 public KeyframeMotion Copy(SceneObjectGroup newgrp)
399 {
400 StopTimer();
401
402 KeyframeMotion newmotion = new KeyframeMotion(null, m_mode, m_data);
403
404 newmotion.m_group = newgrp;
405 newmotion.m_scene = newgrp.Scene;
406
407 if (m_keyframes != null)
408 {
409 newmotion.m_keyframes = new Keyframe[m_keyframes.Length];
410 m_keyframes.CopyTo(newmotion.m_keyframes, 0);
411 }
412
413 newmotion.m_frames = new List<Keyframe>(m_frames);
414
415 newmotion.m_basePosition = m_basePosition;
416 newmotion.m_baseRotation = m_baseRotation;
417
418 if (m_selected)
419 newmotion.m_serializedPosition = m_serializedPosition;
420 else
421 {
422 if (m_group != null)
423 newmotion.m_serializedPosition = m_group.AbsolutePosition;
424 else
425 newmotion.m_serializedPosition = m_serializedPosition;
426 }
427
428 newmotion.m_currentFrame = m_currentFrame;
429
430 newmotion.m_iterations = m_iterations;
431 newmotion.m_running = m_running;
432
433 if (m_running && !m_waitingCrossing)
434 StartTimer();
435
436 return newmotion;
437 }
438
439 public void Delete()
440 {
441 m_running = false;
442 StopTimer();
443 m_isCrossing = false;
444 m_waitingCrossing = false;
445 m_frames.Clear();
446 m_keyframes = null;
447 }
448
449 public void Start()
450 {
451 m_isCrossing = false;
452 m_waitingCrossing = false;
453 if (m_keyframes != null && m_group != null && m_keyframes.Length > 0)
454 {
455 StartTimer();
456 m_running = true;
457 m_group.Scene.EventManager.TriggerMovingStartEvent(m_group.RootPart.LocalId);
458 }
459 else
460 {
461 m_running = false;
462 StopTimer();
463 }
464 }
465
466 public void Stop()
467 {
468 m_running = false;
469 m_isCrossing = false;
470 m_waitingCrossing = false;
471
472 StopTimer();
473
474 m_basePosition = m_group.AbsolutePosition;
475 m_baseRotation = m_group.GroupRotation;
476
477 m_group.RootPart.Velocity = Vector3.Zero;
478 m_group.RootPart.AngularVelocity = Vector3.Zero;
479 m_group.SendGroupRootTerseUpdate();
480// m_group.RootPart.ScheduleTerseUpdate();
481 m_frames.Clear();
482 }
483
484 public void Pause()
485 {
486 m_running = false;
487 StopTimer();
488
489 m_group.RootPart.Velocity = Vector3.Zero;
490 m_group.RootPart.AngularVelocity = Vector3.Zero;
491 m_group.SendGroupRootTerseUpdate();
492// m_group.RootPart.ScheduleTerseUpdate();
493
494 }
495
496 private void GetNextList()
497 {
498 m_frames.Clear();
499 Vector3 pos = m_basePosition;
500 Quaternion rot = m_baseRotation;
501
502 if (m_mode == PlayMode.Loop || m_mode == PlayMode.PingPong || m_iterations == 0)
503 {
504 int direction = 1;
505 if (m_mode == PlayMode.Reverse || ((m_mode == PlayMode.PingPong) && ((m_iterations & 1) != 0)))
506 direction = -1;
507
508 int start = 0;
509 int end = m_keyframes.Length;
510
511 if (direction < 0)
512 {
513 start = m_keyframes.Length - 1;
514 end = -1;
515 }
516
517 for (int i = start; i != end ; i += direction)
518 {
519 Keyframe k = m_keyframes[i];
520
521 k.StartPosition = pos;
522 if (k.Position.HasValue)
523 {
524 k.Position = (k.Position * direction);
525// k.Velocity = (Vector3)k.Position / (k.TimeMS / 1000.0f);
526 k.Position += pos;
527 }
528 else
529 {
530 k.Position = pos;
531// k.Velocity = Vector3.Zero;
532 }
533
534 k.StartRotation = rot;
535 if (k.Rotation.HasValue)
536 {
537 if (direction == -1)
538 k.Rotation = Quaternion.Conjugate((Quaternion)k.Rotation);
539 k.Rotation = rot * k.Rotation;
540 }
541 else
542 {
543 k.Rotation = rot;
544 }
545
546/* ang vel not in use for now
547
548 float angle = 0;
549
550 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;
551 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;
552 float aa_bb = aa * bb;
553
554 if (aa_bb == 0)
555 {
556 angle = 0;
557 }
558 else
559 {
560 float ab = k.StartRotation.X * ((Quaternion)k.Rotation).X +
561 k.StartRotation.Y * ((Quaternion)k.Rotation).Y +
562 k.StartRotation.Z * ((Quaternion)k.Rotation).Z +
563 k.StartRotation.W * ((Quaternion)k.Rotation).W;
564 float q = (ab * ab) / aa_bb;
565
566 if (q > 1.0f)
567 {
568 angle = 0;
569 }
570 else
571 {
572 angle = (float)Math.Acos(2 * q - 1);
573 }
574 }
575
576 k.AngularVelocity = (new Vector3(0, 0, 1) * (Quaternion)k.Rotation) * (angle / (k.TimeMS / 1000));
577 */
578 k.TimeTotal = k.TimeMS;
579
580 m_frames.Add(k);
581
582 pos = (Vector3)k.Position;
583 rot = (Quaternion)k.Rotation;
584 }
585
586 m_basePosition = pos;
587 m_baseRotation = rot;
588
589 m_iterations++;
590 }
591 }
592
593 public void OnTimer(double tickDuration)
594 {
595 if (m_skipLoops > 0)
596 {
597 m_skipLoops--;
598 return;
599 }
600
601 if (m_timerStopped) // trap events still in air even after a timer.stop
602 return;
603
604 if (m_group == null)
605 return;
606
607 bool update = false;
608
609 if (m_selected)
610 {
611 if (m_group.RootPart.Velocity != Vector3.Zero)
612 {
613 m_group.RootPart.Velocity = Vector3.Zero;
614 m_group.SendGroupRootTerseUpdate();
615
616 }
617 return;
618 }
619
620 if (m_isCrossing)
621 {
622 // if crossing and timer running then cross failed
623 // wait some time then
624 // retry to set the position that evtually caused the outbound
625 // if still outside region this will call startCrossing below
626 m_isCrossing = false;
627 m_group.AbsolutePosition = m_nextPosition;
628 if (!m_isCrossing)
629 {
630 StopTimer();
631 StartTimer();
632 }
633 return;
634 }
635
636 if (m_frames.Count == 0)
637 {
638 if (!m_running) return;
639
640 GetNextList();
641
642 if (m_frames.Count == 0)
643 {
644 Stop();
645// Scene scene = m_group.Scene;
646//
647// IScriptModule[] scriptModules = scene.RequestModuleInterfaces<IScriptModule>();
648// foreach (IScriptModule m in scriptModules)
649// {
650// if (m == null)
651// continue;
652// m.PostObjectEvent(m_group.RootPart.UUID, "moving_end", new object[0]);
653// }
654
655 m_group.Scene.EventManager.TriggerMovingEndEvent(m_group.RootPart.LocalId);
656
657 return;
658 }
659
660 m_currentFrame = m_frames[0];
661 m_currentFrame.TimeMS += (int)tickDuration;
662
663 //force a update on a keyframe transition
664 update = true;
665 }
666
667 m_currentFrame.TimeMS -= (int)tickDuration;
668
669 // Do the frame processing
670 double remainingSteps = (double)m_currentFrame.TimeMS / tickDuration;
671
672 if (remainingSteps <= 0.0)
673 {
674 m_group.RootPart.Velocity = Vector3.Zero;
675 m_group.RootPart.AngularVelocity = Vector3.Zero;
676
677 m_nextPosition = (Vector3)m_currentFrame.Position;
678 m_group.AbsolutePosition = m_nextPosition;
679
680 // we are sending imediate updates, no doing force a extra terseUpdate
681 // m_group.UpdateGroupRotationR((Quaternion)m_currentFrame.Rotation);
682
683 m_group.RootPart.RotationOffset = (Quaternion)m_currentFrame.Rotation;
684 m_frames.RemoveAt(0);
685 if (m_frames.Count > 0)
686 m_currentFrame = m_frames[0];
687
688 update = true;
689 }
690 else
691 {
692 float completed = ((float)m_currentFrame.TimeTotal - (float)m_currentFrame.TimeMS) / (float)m_currentFrame.TimeTotal;
693 bool lastStep = m_currentFrame.TimeMS <= tickDuration;
694
695 Vector3 positionThisStep = m_currentFrame.StartPosition + (m_currentFrame.Position.Value - m_currentFrame.StartPosition) * completed;
696 Vector3 motionThisStep = positionThisStep - m_group.AbsolutePosition;
697
698 float mag = Vector3.Mag(motionThisStep);
699
700 if ((mag >= 0.02f) || lastStep)
701 {
702 m_nextPosition = m_group.AbsolutePosition + motionThisStep;
703 m_group.AbsolutePosition = m_nextPosition;
704 update = true;
705 }
706
707 //int totalSteps = m_currentFrame.TimeTotal / (int)tickDuration;
708 //m_log.DebugFormat("KeyframeMotion.OnTimer: step {0}/{1}, curPosition={2}, finalPosition={3}, motionThisStep={4} (scene {5})",
709 // totalSteps - remainingSteps + 1, totalSteps, m_group.AbsolutePosition, m_currentFrame.Position, motionThisStep, m_scene.RegionInfo.RegionName);
710
711 if ((Quaternion)m_currentFrame.Rotation != m_group.GroupRotation)
712 {
713 Quaternion current = m_group.GroupRotation;
714
715 Quaternion step = Quaternion.Slerp(m_currentFrame.StartRotation, (Quaternion)m_currentFrame.Rotation, completed);
716 step.Normalize();
717/* use simpler change detection
718* float angle = 0;
719
720 float aa = current.X * current.X + current.Y * current.Y + current.Z * current.Z + current.W * current.W;
721 float bb = step.X * step.X + step.Y * step.Y + step.Z * step.Z + step.W * step.W;
722 float aa_bb = aa * bb;
723
724 if (aa_bb == 0)
725 {
726 angle = 0;
727 }
728 else
729 {
730 float ab = current.X * step.X +
731 current.Y * step.Y +
732 current.Z * step.Z +
733 current.W * step.W;
734 float q = (ab * ab) / aa_bb;
735
736 if (q > 1.0f)
737 {
738 angle = 0;
739 }
740 else
741 {
742 angle = (float)Math.Acos(2 * q - 1);
743 }
744 }
745
746 if (angle > 0.01f)
747*/
748 if(Math.Abs(step.X - current.X) > 0.001f
749 || Math.Abs(step.Y - current.Y) > 0.001f
750 || Math.Abs(step.Z - current.Z) > 0.001f
751 || lastStep)
752 // assuming w is a dependente var
753
754 {
755// m_group.UpdateGroupRotationR(step);
756 m_group.RootPart.RotationOffset = step;
757
758 //m_group.RootPart.UpdateAngularVelocity(m_currentFrame.AngularVelocity / 2);
759 update = true;
760 }
761 }
762 }
763
764 if (update)
765 {
766 m_group.SendGroupRootTerseUpdate();
767 }
768 }
769
770 public Byte[] Serialize()
771 {
772 StopTimer();
773
774 SceneObjectGroup tmp = m_group;
775 m_group = null;
776 if (!m_selected && tmp != null)
777 m_serializedPosition = tmp.AbsolutePosition;
778
779 using (MemoryStream ms = new MemoryStream())
780 {
781 BinaryFormatter fmt = new BinaryFormatter();
782 fmt.Serialize(ms, this);
783 m_group = tmp;
784 if (m_running && !m_waitingCrossing)
785 StartTimer();
786
787 return ms.ToArray();
788 }
789 }
790
791 public void StartCrossingCheck()
792 {
793 // timer will be restart by crossingFailure
794 // or never since crossing worked and this
795 // should be deleted
796 StopTimer();
797
798 m_isCrossing = true;
799 m_waitingCrossing = true;
800
801 // to remove / retune to smoth crossings
802 if (m_group.RootPart.Velocity != Vector3.Zero)
803 {
804 m_group.RootPart.Velocity = Vector3.Zero;
805 m_group.SendGroupRootTerseUpdate();
806// m_group.RootPart.ScheduleTerseUpdate();
807 }
808 }
809
810 public void CrossingFailure()
811 {
812 m_waitingCrossing = false;
813
814 if (m_group != null)
815 {
816 m_group.RootPart.Velocity = Vector3.Zero;
817 m_group.SendGroupRootTerseUpdate();
818// m_group.RootPart.ScheduleTerseUpdate();
819
820 if (m_running)
821 {
822 StopTimer();
823 m_skipLoops = 1200; // 60 seconds
824 StartTimer();
825 }
826 }
827 }
828 }
829}
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;
31using Nini.Config; 31using Nini.Config;
32using OpenSim.Framework; 32using OpenSim.Framework;
33using OpenMetaverse; 33using OpenMetaverse;
34using OpenSim.Region.Physics.Manager; 34using OpenSim.Region.PhysicsModules.SharedBase;
35 35
36/* 36/*
37 * Steps to add a new prioritization policy: 37 * 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;
35using OpenMetaverse; 35using OpenMetaverse;
36using OpenMetaverse.StructuredData; 36using OpenMetaverse.StructuredData;
37using OpenSim.Framework; 37using OpenSim.Framework;
38using OpenSim.Framework.Communications;
39using OpenSim.Framework.Console; 38using OpenSim.Framework.Console;
40using OpenSim.Framework.Servers; 39using OpenSim.Framework.Servers;
41using OpenSim.Framework.Servers.HttpServer; 40using OpenSim.Framework.Servers.HttpServer;
@@ -46,47 +45,33 @@ using OpenSim.Region.Framework.Scenes;
46 45
47namespace OpenSim.Region.Framework.Scenes 46namespace OpenSim.Region.Framework.Scenes
48{ 47{
49 public class RegionStatsHandler : IStreamedRequestHandler 48 public class RegionStatsHandler : BaseStreamHandler
50 { 49 {
51 //private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 50 //private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
52 51
53 private string osRXStatsURI = String.Empty;
54 private string osXStatsURI = String.Empty; 52 private string osXStatsURI = String.Empty;
55 //private string osSecret = String.Empty; 53 //private string osSecret = String.Empty;
56 private OpenSim.Framework.RegionInfo regionInfo; 54 private OpenSim.Framework.RegionInfo regionInfo;
57 public string localZone = TimeZone.CurrentTimeZone.StandardName; 55 public string localZone = TimeZone.CurrentTimeZone.StandardName;
58 public TimeSpan utcOffset = TimeZone.CurrentTimeZone.GetUtcOffset(DateTime.Now); 56 public TimeSpan utcOffset = TimeZone.CurrentTimeZone.GetUtcOffset(DateTime.Now);
59 57
60 public string Name { get { return "RegionStats"; } } 58 public RegionStatsHandler(RegionInfo region_info)
61 public string Description { get { return "Region Statistics"; } } 59 : base("GET", "/" + Util.SHA1Hash(region_info.regionSecret), "RegionStats", "Region Statistics")
62
63 public RegionStatsHandler(RegionInfo region_info)
64 { 60 {
65 regionInfo = region_info; 61 regionInfo = region_info;
66 osRXStatsURI = Util.SHA1Hash(regionInfo.regionSecret);
67 osXStatsURI = Util.SHA1Hash(regionInfo.osSecret); 62 osXStatsURI = Util.SHA1Hash(regionInfo.osSecret);
68 } 63 }
69 64
70 public byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) 65 protected override byte[] ProcessRequest(
66 string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
71 { 67 {
72 return Util.UTF8.GetBytes(Report()); 68 return Util.UTF8.GetBytes(Report());
73 } 69 }
74 70
75 public string ContentType 71 public override string ContentType
76 { 72 {
77 get { return "text/plain"; } 73 get { return "text/plain"; }
78 } 74 }
79
80 public string HttpMethod
81 {
82 get { return "GET"; }
83 }
84
85 public string Path
86 {
87 // This is for the region and is the regionSecret hashed
88 get { return "/" + osRXStatsURI; }
89 }
90 75
91 private string Report() 76 private string Report()
92 { 77 {
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;
30using System.Collections; 30using System.Collections;
31using System.Reflection; 31using System.Reflection;
32using System.Text; 32using System.Text;
33using System.Threading;
33using System.Timers; 34using System.Timers;
35using System.Xml;
34using OpenMetaverse; 36using OpenMetaverse;
35using OpenMetaverse.Packets; 37using OpenMetaverse.Packets;
36using log4net; 38using log4net;
37using OpenSim.Framework; 39using OpenSim.Framework;
40using OpenSim.Framework.Serialization.External;
38using OpenSim.Region.Framework; 41using OpenSim.Region.Framework;
39using OpenSim.Framework.Client; 42using OpenSim.Framework.Client;
40using OpenSim.Region.Framework.Interfaces; 43using OpenSim.Region.Framework.Interfaces;
41using OpenSim.Region.Framework.Scenes.Serialization; 44using OpenSim.Region.Framework.Scenes.Serialization;
45using OpenSim.Services.Interfaces;
46using PermissionMask = OpenSim.Framework.PermissionMask;
42 47
43namespace OpenSim.Region.Framework.Scenes 48namespace OpenSim.Region.Framework.Scenes
44{ 49{
45 public partial class Scene 50 public partial class Scene
46 { 51 {
47 private static readonly ILog m_log 52 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48 = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 53 //private static readonly string LogHeader = "[SCENE INVENTORY]";
49 54
50 /// <summary> 55 /// <summary>
51 /// Allows asynchronous derezzing of objects from the scene into a client's inventory. 56 /// Allows asynchronous derezzing of objects from the scene into a client's inventory.
@@ -125,11 +130,16 @@ namespace OpenSim.Region.Framework.Scenes
125 } 130 }
126 } 131 }
127 132
133 public bool AddInventoryItem(InventoryItemBase item)
134 {
135 return AddInventoryItem(item, true);
136 }
137
128 /// <summary> 138 /// <summary>
129 /// Add the given inventory item to a user's inventory. 139 /// Add the given inventory item to a user's inventory.
130 /// </summary> 140 /// </summary>
131 /// <param name="item"></param> 141 /// <param name="item"></param>
132 public bool AddInventoryItem(InventoryItemBase item) 142 public bool AddInventoryItem(InventoryItemBase item, bool trigger)
133 { 143 {
134 if (item.Folder != UUID.Zero && InventoryService.AddItem(item)) 144 if (item.Folder != UUID.Zero && InventoryService.AddItem(item))
135 { 145 {
@@ -138,14 +148,17 @@ namespace OpenSim.Region.Framework.Scenes
138 { 148 {
139 userlevel = 1; 149 userlevel = 1;
140 } 150 }
141 EventManager.TriggerOnNewInventoryItemUploadComplete(item.Owner, item.AssetID, item.Name, userlevel); 151 if (trigger)
152 EventManager.TriggerOnNewInventoryItemUploadComplete(item.Owner, (AssetType)item.AssetType, item.AssetID, item.Name, userlevel);
142 153
143 return true; 154 return true;
144 } 155 }
145 156
146 // OK so either the viewer didn't send a folderID or AddItem failed 157 // OK so either the viewer didn't send a folderID or AddItem failed
147 UUID originalFolder = item.Folder; 158 UUID originalFolder = item.Folder;
148 InventoryFolderBase f = InventoryService.GetFolderForType(item.Owner, (AssetType)item.AssetType); 159 InventoryFolderBase f = null;
160 if (Enum.IsDefined(typeof(FolderType), (sbyte)item.AssetType))
161 f = InventoryService.GetFolderForType(item.Owner, (FolderType)item.AssetType);
149 if (f != null) 162 if (f != null)
150 { 163 {
151 m_log.DebugFormat( 164 m_log.DebugFormat(
@@ -177,7 +190,8 @@ namespace OpenSim.Region.Framework.Scenes
177 { 190 {
178 userlevel = 1; 191 userlevel = 1;
179 } 192 }
180 EventManager.TriggerOnNewInventoryItemUploadComplete(item.Owner, item.AssetID, item.Name, userlevel); 193 if (trigger)
194 EventManager.TriggerOnNewInventoryItemUploadComplete(item.Owner, (AssetType)item.AssetType, item.AssetID, item.Name, userlevel);
181 195
182 if (originalFolder != UUID.Zero) 196 if (originalFolder != UUID.Zero)
183 { 197 {
@@ -325,7 +339,7 @@ namespace OpenSim.Region.Framework.Scenes
325 // Update item with new asset 339 // Update item with new asset
326 item.AssetID = asset.FullID; 340 item.AssetID = asset.FullID;
327 if (group.UpdateInventoryItem(item)) 341 if (group.UpdateInventoryItem(item))
328 remoteClient.SendAgentAlertMessage("Script saved", false); 342 remoteClient.SendAlertMessage("Script saved");
329 343
330 part.SendPropertiesToClient(remoteClient); 344 part.SendPropertiesToClient(remoteClient);
331 345
@@ -341,7 +355,7 @@ namespace OpenSim.Region.Framework.Scenes
341 } 355 }
342 else 356 else
343 { 357 {
344 remoteClient.SendAgentAlertMessage("Script saved", false); 358 remoteClient.SendAlertMessage("Script saved");
345 } 359 }
346 360
347 // Tell anyone managing scripts that a script has been reloaded/changed 361 // Tell anyone managing scripts that a script has been reloaded/changed
@@ -415,20 +429,61 @@ namespace OpenSim.Region.Framework.Scenes
415// itemUpd.NextPermissions, itemUpd.GroupPermissions, itemUpd.EveryOnePermissions, item.Flags, 429// itemUpd.NextPermissions, itemUpd.GroupPermissions, itemUpd.EveryOnePermissions, item.Flags,
416// item.NextPermissions, item.GroupPermissions, item.EveryOnePermissions, item.CurrentPermissions); 430// item.NextPermissions, item.GroupPermissions, item.EveryOnePermissions, item.CurrentPermissions);
417 431
432 bool sendUpdate = false;
433
418 if (itemUpd.NextPermissions != 0) // Use this to determine validity. Can never be 0 if valid 434 if (itemUpd.NextPermissions != 0) // Use this to determine validity. Can never be 0 if valid
419 { 435 {
436 // Create a set of base permissions that will not include export if the user
437 // is not allowed to change the export flag.
438 bool denyExportChange = false;
439
440// m_log.DebugFormat("[XXX]: B: {0} O: {1} E: {2}", itemUpd.BasePermissions, itemUpd.CurrentPermissions, itemUpd.EveryOnePermissions);
441
442 // If the user is not the creator or doesn't have "E" in both "B" and "O", deny setting export
443 if ((item.BasePermissions & (uint)(PermissionMask.All | PermissionMask.Export)) != (uint)(PermissionMask.All | PermissionMask.Export) || (item.CurrentPermissions & (uint)PermissionMask.Export) == 0 || item.CreatorIdAsUuid != item.Owner)
444 denyExportChange = true;
445
446// m_log.DebugFormat("[XXX]: Deny Export Update {0}", denyExportChange);
447
448 // If it is already set, force it set and also force full perm
449 // else prevent setting it. It can and should never be set unless
450 // set in base, so the condition above is valid
451 if (denyExportChange)
452 {
453 // If we are not allowed to change it, then force it to the
454 // original item's setting and if it was on, also force full perm
455 if ((item.EveryOnePermissions & (uint)PermissionMask.Export) != 0)
456 {
457 itemUpd.NextPermissions = (uint)(PermissionMask.All);
458 itemUpd.EveryOnePermissions |= (uint)PermissionMask.Export;
459 }
460 else
461 {
462 itemUpd.EveryOnePermissions &= ~(uint)PermissionMask.Export;
463 }
464 }
465 else
466 {
467 // If the new state is exportable, force full perm
468 if ((itemUpd.EveryOnePermissions & (uint)PermissionMask.Export) != 0)
469 {
470// m_log.DebugFormat("[XXX]: Force full perm");
471 itemUpd.NextPermissions = (uint)(PermissionMask.All);
472 }
473 }
474
420 if (item.NextPermissions != (itemUpd.NextPermissions & item.BasePermissions)) 475 if (item.NextPermissions != (itemUpd.NextPermissions & item.BasePermissions))
421 item.Flags |= (uint)InventoryItemFlags.ObjectOverwriteNextOwner; 476 item.Flags |= (uint)InventoryItemFlags.ObjectOverwriteNextOwner;
422 item.NextPermissions = itemUpd.NextPermissions & item.BasePermissions; 477 item.NextPermissions = itemUpd.NextPermissions & item.BasePermissions;
478
423 if (item.EveryOnePermissions != (itemUpd.EveryOnePermissions & item.BasePermissions)) 479 if (item.EveryOnePermissions != (itemUpd.EveryOnePermissions & item.BasePermissions))
424 item.Flags |= (uint)InventoryItemFlags.ObjectOverwriteEveryone; 480 item.Flags |= (uint)InventoryItemFlags.ObjectOverwriteEveryone;
425 item.EveryOnePermissions = itemUpd.EveryOnePermissions & item.BasePermissions; 481 item.EveryOnePermissions = itemUpd.EveryOnePermissions & item.BasePermissions;
482
426 if (item.GroupPermissions != (itemUpd.GroupPermissions & item.BasePermissions)) 483 if (item.GroupPermissions != (itemUpd.GroupPermissions & item.BasePermissions))
427 item.Flags |= (uint)InventoryItemFlags.ObjectOverwriteGroup; 484 item.Flags |= (uint)InventoryItemFlags.ObjectOverwriteGroup;
428
429// m_log.DebugFormat("[USER INVENTORY]: item.Flags {0}", item.Flags);
430
431 item.GroupPermissions = itemUpd.GroupPermissions & item.BasePermissions; 485 item.GroupPermissions = itemUpd.GroupPermissions & item.BasePermissions;
486
432 item.GroupID = itemUpd.GroupID; 487 item.GroupID = itemUpd.GroupID;
433 item.GroupOwned = itemUpd.GroupOwned; 488 item.GroupOwned = itemUpd.GroupOwned;
434 item.CreationDate = itemUpd.CreationDate; 489 item.CreationDate = itemUpd.CreationDate;
@@ -449,6 +504,12 @@ namespace OpenSim.Region.Framework.Scenes
449 item.SalePrice = itemUpd.SalePrice; 504 item.SalePrice = itemUpd.SalePrice;
450 item.SaleType = itemUpd.SaleType; 505 item.SaleType = itemUpd.SaleType;
451 506
507 if (item.InvType == (int)InventoryType.Wearable && (item.Flags & 0xf) == 0 && (itemUpd.Flags & 0xf) != 0)
508 {
509 item.Flags = (uint)(item.Flags & 0xfffffff0) | (itemUpd.Flags & 0xf);
510 sendUpdate = true;
511 }
512
452 InventoryService.UpdateItem(item); 513 InventoryService.UpdateItem(item);
453 } 514 }
454 515
@@ -459,6 +520,17 @@ namespace OpenSim.Region.Framework.Scenes
459 AgentTransactionsModule.HandleItemUpdateFromTransaction(remoteClient, transactionID, item); 520 AgentTransactionsModule.HandleItemUpdateFromTransaction(remoteClient, transactionID, item);
460 } 521 }
461 } 522 }
523 else
524 {
525 // This MAY be problematic, if it is, another solution
526 // needs to be found. If inventory item flags are updated
527 // the viewer's notion of the item needs to be refreshed.
528 //
529 // In other situations we cannot send out a bulk update here, since this will cause editing of clothing to start
530 // failing frequently. Possibly this is a race with a separate transaction that uploads the asset.
531 if (sendUpdate)
532 remoteClient.SendBulkUpdateInventory(item);
533 }
462 } 534 }
463 else 535 else
464 { 536 {
@@ -474,9 +546,9 @@ namespace OpenSim.Region.Framework.Scenes
474 /// <param name="recipientClient"></param> 546 /// <param name="recipientClient"></param>
475 /// <param name="senderId">ID of the sender of the item</param> 547 /// <param name="senderId">ID of the sender of the item</param>
476 /// <param name="itemId"></param> 548 /// <param name="itemId"></param>
477 public virtual void GiveInventoryItem(IClientAPI recipientClient, UUID senderId, UUID itemId) 549 public virtual void GiveInventoryItem(IClientAPI recipientClient, UUID senderId, UUID itemId, out string message)
478 { 550 {
479 InventoryItemBase itemCopy = GiveInventoryItem(recipientClient.AgentId, senderId, itemId); 551 InventoryItemBase itemCopy = GiveInventoryItem(recipientClient.AgentId, senderId, itemId, out message);
480 552
481 if (itemCopy != null) 553 if (itemCopy != null)
482 recipientClient.SendBulkUpdateInventory(itemCopy); 554 recipientClient.SendBulkUpdateInventory(itemCopy);
@@ -489,9 +561,9 @@ namespace OpenSim.Region.Framework.Scenes
489 /// <param name="senderId">ID of the sender of the item</param> 561 /// <param name="senderId">ID of the sender of the item</param>
490 /// <param name="itemId"></param> 562 /// <param name="itemId"></param>
491 /// <returns>The inventory item copy given, null if the give was unsuccessful</returns> 563 /// <returns>The inventory item copy given, null if the give was unsuccessful</returns>
492 public virtual InventoryItemBase GiveInventoryItem(UUID recipient, UUID senderId, UUID itemId) 564 public virtual InventoryItemBase GiveInventoryItem(UUID recipient, UUID senderId, UUID itemId, out string message)
493 { 565 {
494 return GiveInventoryItem(recipient, senderId, itemId, UUID.Zero); 566 return GiveInventoryItem(recipient, senderId, itemId, UUID.Zero, out message);
495 } 567 }
496 568
497 /// <summary> 569 /// <summary>
@@ -508,10 +580,16 @@ namespace OpenSim.Region.Framework.Scenes
508 /// The inventory item copy given, null if the give was unsuccessful 580 /// The inventory item copy given, null if the give was unsuccessful
509 /// </returns> 581 /// </returns>
510 public virtual InventoryItemBase GiveInventoryItem( 582 public virtual InventoryItemBase GiveInventoryItem(
511 UUID recipient, UUID senderId, UUID itemId, UUID recipientFolderId) 583 UUID recipient, UUID senderId, UUID itemId, UUID recipientFolderId, out string message)
512 { 584 {
513 //Console.WriteLine("Scene.Inventory.cs: GiveInventoryItem"); 585 //Console.WriteLine("Scene.Inventory.cs: GiveInventoryItem");
514 586
587 if (!Permissions.CanTransferUserInventory(itemId, senderId, recipient))
588 {
589 message = "Not allowed to transfer this item.";
590 return null;
591 }
592
515 InventoryItemBase item = new InventoryItemBase(itemId, senderId); 593 InventoryItemBase item = new InventoryItemBase(itemId, senderId);
516 item = InventoryService.GetItem(item); 594 item = InventoryService.GetItem(item);
517 595
@@ -519,6 +597,7 @@ namespace OpenSim.Region.Framework.Scenes
519 { 597 {
520 m_log.WarnFormat( 598 m_log.WarnFormat(
521 "[AGENT INVENTORY]: Failed to find item {0} sent by {1} to {2}", itemId, senderId, recipient); 599 "[AGENT INVENTORY]: Failed to find item {0} sent by {1} to {2}", itemId, senderId, recipient);
600 message = string.Format("Item not found: {0}.", itemId);
522 return null; 601 return null;
523 } 602 }
524 603
@@ -527,6 +606,7 @@ namespace OpenSim.Region.Framework.Scenes
527 m_log.WarnFormat( 606 m_log.WarnFormat(
528 "[AGENT INVENTORY]: Attempt to send item {0} {1} to {2} failed because sender {3} did not match item owner {4}", 607 "[AGENT INVENTORY]: Attempt to send item {0} {1} to {2} failed because sender {3} did not match item owner {4}",
529 item.Name, item.ID, recipient, senderId, item.Owner); 608 item.Name, item.ID, recipient, senderId, item.Owner);
609 message = "Sender did not match item owner.";
530 return null; 610 return null;
531 } 611 }
532 612
@@ -537,7 +617,10 @@ namespace OpenSim.Region.Framework.Scenes
537 if (!Permissions.BypassPermissions()) 617 if (!Permissions.BypassPermissions())
538 { 618 {
539 if ((item.CurrentPermissions & (uint)PermissionMask.Transfer) == 0) 619 if ((item.CurrentPermissions & (uint)PermissionMask.Transfer) == 0)
620 {
621 message = "Item doesn't have the Transfer permission.";
540 return null; 622 return null;
623 }
541 } 624 }
542 625
543 // Insert a copy of the item into the recipient 626 // Insert a copy of the item into the recipient
@@ -606,17 +689,13 @@ namespace OpenSim.Region.Framework.Scenes
606 // a mask 689 // a mask
607 if (item.InvType == (int)InventoryType.Object) 690 if (item.InvType == (int)InventoryType.Object)
608 { 691 {
609 // Create a safe mask for the current perms
610 uint foldedPerms = (item.CurrentPermissions & 7) << 13;
611 foldedPerms |= permsMask;
612
613 bool isRootMod = (item.CurrentPermissions & 692 bool isRootMod = (item.CurrentPermissions &
614 (uint)PermissionMask.Modify) != 0 ? 693 (uint)PermissionMask.Modify) != 0 ?
615 true : false; 694 true : false;
616 695
617 // Mask the owner perms to the folded perms 696 // Mask the owner perms to the folded perms
618 ownerPerms &= foldedPerms; 697 PermissionsUtil.ApplyFoldedPermissions(item.CurrentPermissions, ref ownerPerms);
619 basePerms &= foldedPerms; 698 PermissionsUtil.ApplyFoldedPermissions(item.CurrentPermissions, ref basePerms);
620 699
621 // If the root was mod, let the mask reflect that 700 // If the root was mod, let the mask reflect that
622 // We also need to adjust the base here, because 701 // We also need to adjust the base here, because
@@ -666,7 +745,9 @@ namespace OpenSim.Region.Framework.Scenes
666 745
667 if (itemCopy.Folder == UUID.Zero) 746 if (itemCopy.Folder == UUID.Zero)
668 { 747 {
669 InventoryFolderBase folder = InventoryService.GetFolderForType(recipient, (AssetType)itemCopy.AssetType); 748 InventoryFolderBase folder = null;
749 if (Enum.IsDefined(typeof(FolderType), (sbyte)item.AssetType))
750 folder = InventoryService.GetFolderForType(recipient, (FolderType)itemCopy.AssetType);
670 751
671 if (folder != null) 752 if (folder != null)
672 { 753 {
@@ -677,9 +758,14 @@ namespace OpenSim.Region.Framework.Scenes
677 InventoryFolderBase root = InventoryService.GetRootFolder(recipient); 758 InventoryFolderBase root = InventoryService.GetRootFolder(recipient);
678 759
679 if (root != null) 760 if (root != null)
761 {
680 itemCopy.Folder = root.ID; 762 itemCopy.Folder = root.ID;
763 }
681 else 764 else
682 return null; // No destination 765 {
766 message = "Can't find a folder to add the item to.";
767 return null;
768 }
683 } 769 }
684 } 770 }
685 771
@@ -692,7 +778,7 @@ namespace OpenSim.Region.Framework.Scenes
692 IInventoryAccessModule invAccess = RequestModuleInterface<IInventoryAccessModule>(); 778 IInventoryAccessModule invAccess = RequestModuleInterface<IInventoryAccessModule>();
693 if (invAccess != null) 779 if (invAccess != null)
694 invAccess.TransferInventoryAssets(itemCopy, senderId, recipient); 780 invAccess.TransferInventoryAssets(itemCopy, senderId, recipient);
695 AddInventoryItem(itemCopy); 781 AddInventoryItem(itemCopy, false);
696 782
697 if (!Permissions.BypassPermissions()) 783 if (!Permissions.BypassPermissions())
698 { 784 {
@@ -704,6 +790,7 @@ namespace OpenSim.Region.Framework.Scenes
704 } 790 }
705 } 791 }
706 792
793 message = null;
707 return itemCopy; 794 return itemCopy;
708 } 795 }
709 796
@@ -721,11 +808,11 @@ namespace OpenSim.Region.Framework.Scenes
721 /// <returns> 808 /// <returns>
722 /// The inventory folder copy given, null if the copy was unsuccessful 809 /// The inventory folder copy given, null if the copy was unsuccessful
723 /// </returns> 810 /// </returns>
724 public virtual InventoryFolderBase GiveInventoryFolder( 811 public virtual InventoryFolderBase GiveInventoryFolder(IClientAPI client,
725 UUID recipientId, UUID senderId, UUID folderId, UUID recipientParentFolderId) 812 UUID recipientId, UUID senderId, UUID folderId, UUID recipientParentFolderId)
726 { 813 {
727 //// Retrieve the folder from the sender 814 //// Retrieve the folder from the sender
728 InventoryFolderBase folder = InventoryService.GetFolder(new InventoryFolderBase(folderId)); 815 InventoryFolderBase folder = InventoryService.GetFolder(new InventoryFolderBase(folderId, senderId));
729 if (null == folder) 816 if (null == folder)
730 { 817 {
731 m_log.ErrorFormat( 818 m_log.ErrorFormat(
@@ -756,13 +843,18 @@ namespace OpenSim.Region.Framework.Scenes
756 InventoryCollection contents = InventoryService.GetFolderContent(senderId, folderId); 843 InventoryCollection contents = InventoryService.GetFolderContent(senderId, folderId);
757 foreach (InventoryFolderBase childFolder in contents.Folders) 844 foreach (InventoryFolderBase childFolder in contents.Folders)
758 { 845 {
759 GiveInventoryFolder(recipientId, senderId, childFolder.ID, newFolder.ID); 846 GiveInventoryFolder(client, recipientId, senderId, childFolder.ID, newFolder.ID);
760 } 847 }
761 848
762 // Give all the items 849 // Give all the items
763 foreach (InventoryItemBase item in contents.Items) 850 foreach (InventoryItemBase item in contents.Items)
764 { 851 {
765 GiveInventoryItem(recipientId, senderId, item.ID, newFolder.ID); 852 string message;
853 if (GiveInventoryItem(recipientId, senderId, item.ID, newFolder.ID, out message) == null)
854 {
855 if (client != null)
856 client.SendAgentAlertMessage(message, false);
857 }
766 } 858 }
767 859
768 return newFolder; 860 return newFolder;
@@ -794,51 +886,34 @@ namespace OpenSim.Region.Framework.Scenes
794 return; 886 return;
795 } 887 }
796 888
797 AssetBase asset = AssetService.Get(item.AssetID.ToString()); 889 if (newName == String.Empty)
890 newName = item.Name;
798 891
799 if (asset != null) 892 if (remoteClient.AgentId == oldAgentID
893 || (LibraryService != null
894 && LibraryService.LibraryRootFolder != null
895 && oldAgentID == LibraryService.LibraryRootFolder.Owner))
800 { 896 {
801 if (newName != String.Empty) 897 CreateNewInventoryItem(
802 { 898 remoteClient, item.CreatorId, item.CreatorData, newFolderID,
803 asset.Name = newName; 899 newName, item.Description, item.Flags, callbackID, item.AssetID, (sbyte)item.AssetType, (sbyte)item.InvType,
804 } 900 item.BasePermissions, item.CurrentPermissions, item.EveryOnePermissions,
805 else 901 item.NextPermissions, item.GroupPermissions, Util.UnixTimeSinceEpoch(), false);
806 { 902 }
807 newName = item.Name; 903 else
808 } 904 {
809 905 // If item is transfer or permissions are off or calling agent is allowed to copy item owner's inventory item.
810 if (remoteClient.AgentId == oldAgentID 906 if (((item.CurrentPermissions & (uint)PermissionMask.Transfer) != 0)
811 || (LibraryService != null 907 && (m_permissions.BypassPermissions()
812 && LibraryService.LibraryRootFolder != null 908 || m_permissions.CanCopyUserInventory(remoteClient.AgentId, oldItemID)))
813 && oldAgentID == LibraryService.LibraryRootFolder.Owner))
814 { 909 {
815 CreateNewInventoryItem( 910 CreateNewInventoryItem(
816 remoteClient, item.CreatorId, item.CreatorData, newFolderID, 911 remoteClient, item.CreatorId, item.CreatorData, newFolderID, newName, item.Description, item.Flags, callbackID,
817 newName, item.Description, item.Flags, callbackID, asset, (sbyte)item.InvType, 912 item.AssetID, (sbyte)item.AssetType, (sbyte) item.InvType,
818 item.BasePermissions, item.CurrentPermissions, item.EveryOnePermissions, 913 item.NextPermissions, item.NextPermissions, item.EveryOnePermissions & item.NextPermissions,
819 item.NextPermissions, item.GroupPermissions, Util.UnixTimeSinceEpoch()); 914 item.NextPermissions, item.GroupPermissions, Util.UnixTimeSinceEpoch(), false);
820 }
821 else
822 {
823 // If item is transfer or permissions are off or calling agent is allowed to copy item owner's inventory item.
824 if (((item.CurrentPermissions & (uint)PermissionMask.Transfer) != 0)
825 && (m_permissions.BypassPermissions()
826 || m_permissions.CanCopyUserInventory(remoteClient.AgentId, oldItemID)))
827 {
828 CreateNewInventoryItem(
829 remoteClient, item.CreatorId, item.CreatorData, newFolderID, newName, item.Description, item.Flags, callbackID,
830 asset, (sbyte) item.InvType,
831 item.NextPermissions, item.NextPermissions, item.EveryOnePermissions & item.NextPermissions,
832 item.NextPermissions, item.GroupPermissions, Util.UnixTimeSinceEpoch());
833 }
834 } 915 }
835 } 916 }
836 else
837 {
838 m_log.ErrorFormat(
839 "[AGENT INVENTORY]: Could not copy item {0} since asset {1} could not be found",
840 item.Name, item.AssetID);
841 }
842 } 917 }
843 918
844 /// <summary> 919 /// <summary>
@@ -888,11 +963,12 @@ namespace OpenSim.Region.Framework.Scenes
888 public void CreateNewInventoryItem( 963 public void CreateNewInventoryItem(
889 IClientAPI remoteClient, string creatorID, string creatorData, UUID folderID, 964 IClientAPI remoteClient, string creatorID, string creatorData, UUID folderID,
890 string name, string description, uint flags, uint callbackID, 965 string name, string description, uint flags, uint callbackID,
891 AssetBase asset, sbyte invType, uint nextOwnerMask, int creationDate) 966 UUID assetID, sbyte assetType, sbyte invType, uint nextOwnerMask, int creationDate)
892 { 967 {
893 CreateNewInventoryItem( 968 CreateNewInventoryItem(
894 remoteClient, creatorID, creatorData, folderID, name, description, flags, callbackID, asset, invType, 969 remoteClient, creatorID, creatorData, folderID, name, description, flags, callbackID, assetID, assetType, invType,
895 (uint)PermissionMask.All, (uint)PermissionMask.All, 0, nextOwnerMask, 0, creationDate); 970 (uint)PermissionMask.All | (uint)PermissionMask.Export, (uint)PermissionMask.All | (uint)PermissionMask.Export, 0, nextOwnerMask, 0,
971 creationDate, true);
896 } 972 }
897 973
898 /// <summary> 974 /// <summary>
@@ -916,19 +992,20 @@ namespace OpenSim.Region.Framework.Scenes
916 /// <param name="creationDate">Unix timestamp at which this item was created.</param> 992 /// <param name="creationDate">Unix timestamp at which this item was created.</param>
917 private void CreateNewInventoryItem( 993 private void CreateNewInventoryItem(
918 IClientAPI remoteClient, string creatorID, string creatorData, UUID folderID, 994 IClientAPI remoteClient, string creatorID, string creatorData, UUID folderID,
919 string name, string description, uint flags, uint callbackID, AssetBase asset, sbyte invType, 995 string name, string description, uint flags, uint callbackID, UUID assetID, sbyte assetType, sbyte invType,
920 uint baseMask, uint currentMask, uint everyoneMask, uint nextOwnerMask, uint groupMask, int creationDate) 996 uint baseMask, uint currentMask, uint everyoneMask, uint nextOwnerMask, uint groupMask, int creationDate,
997 bool assetUpload)
921 { 998 {
922 InventoryItemBase item = new InventoryItemBase(); 999 InventoryItemBase item = new InventoryItemBase();
923 item.Owner = remoteClient.AgentId; 1000 item.Owner = remoteClient.AgentId;
924 item.CreatorId = creatorID; 1001 item.CreatorId = creatorID;
925 item.CreatorData = creatorData; 1002 item.CreatorData = creatorData;
926 item.ID = UUID.Random(); 1003 item.ID = UUID.Random();
927 item.AssetID = asset.FullID; 1004 item.AssetID = assetID;
928 item.Name = name; 1005 item.Name = name;
929 item.Description = description; 1006 item.Description = description;
930 item.Flags = flags; 1007 item.Flags = flags;
931 item.AssetType = asset.Type; 1008 item.AssetType = assetType;
932 item.InvType = invType; 1009 item.InvType = invType;
933 item.Folder = folderID; 1010 item.Folder = folderID;
934 item.CurrentPermissions = currentMask; 1011 item.CurrentPermissions = currentMask;
@@ -938,7 +1015,7 @@ namespace OpenSim.Region.Framework.Scenes
938 item.BasePermissions = baseMask; 1015 item.BasePermissions = baseMask;
939 item.CreationDate = creationDate; 1016 item.CreationDate = creationDate;
940 1017
941 if (AddInventoryItem(item)) 1018 if (AddInventoryItem(item, assetUpload))
942 { 1019 {
943 remoteClient.SendInventoryItemCreateUpdate(item, callbackID); 1020 remoteClient.SendInventoryItemCreateUpdate(item, callbackID);
944 } 1021 }
@@ -1001,17 +1078,12 @@ namespace OpenSim.Region.Framework.Scenes
1001// return; 1078// return;
1002// } 1079// }
1003 1080
1004 AssetBase asset = new AssetBase();
1005 asset.FullID = olditemID;
1006 asset.Type = type;
1007 asset.Name = name;
1008 asset.Description = description;
1009
1010 CreateNewInventoryItem( 1081 CreateNewInventoryItem(
1011 remoteClient, remoteClient.AgentId.ToString(), string.Empty, folderID, 1082 remoteClient, remoteClient.AgentId.ToString(), string.Empty, folderID,
1012 name, description, 0, callbackID, asset, invType, 1083 name, description, 0, callbackID, olditemID, type, invType,
1013 (uint)PermissionMask.All, (uint)PermissionMask.All, (uint)PermissionMask.All, 1084 (uint)PermissionMask.All | (uint)PermissionMask.Export, (uint)PermissionMask.All | (uint)PermissionMask.Export, (uint)PermissionMask.All,
1014 (uint)PermissionMask.All, (uint)PermissionMask.All, Util.UnixTimeSinceEpoch()); 1085 (uint)PermissionMask.All | (uint)PermissionMask.Export, (uint)PermissionMask.All | (uint)PermissionMask.Export, Util.UnixTimeSinceEpoch(),
1086 false);
1015 } 1087 }
1016 else 1088 else
1017 { 1089 {
@@ -1087,13 +1159,21 @@ namespace OpenSim.Region.Framework.Scenes
1087 if (item == null) 1159 if (item == null)
1088 return; 1160 return;
1089 1161
1090 InventoryFolderBase destFolder = InventoryService.GetFolderForType(remoteClient.AgentId, AssetType.TrashFolder); 1162 InventoryFolderBase destFolder = InventoryService.GetFolderForType(remoteClient.AgentId, FolderType.Trash);
1091 1163
1092 // Move the item to trash. If this is a copiable item, only 1164 // Move the item to trash. If this is a copyable item, only
1093 // a copy will be moved and we will still need to delete 1165 // a copy will be moved and we will still need to delete
1094 // the item from the prim. If it was no copy, is will be 1166 // the item from the prim. If it was no copy, it will be
1095 // deleted by this method. 1167 // deleted by this method.
1096 MoveTaskInventoryItem(remoteClient, destFolder.ID, part, itemID); 1168 string message;
1169 InventoryItemBase item2 = MoveTaskInventoryItem(remoteClient, destFolder.ID, part, itemID, out message);
1170
1171 if (item2 == null)
1172 {
1173 m_log.WarnFormat("[SCENE INVENTORY]: RemoveTaskInventory of item {0} failed: {1}", itemID, message);
1174 remoteClient.SendAgentAlertMessage(message, false);
1175 return;
1176 }
1097 1177
1098 if (group.GetInventoryItem(localID, itemID) != null) 1178 if (group.GetInventoryItem(localID, itemID) != null)
1099 { 1179 {
@@ -1105,11 +1185,16 @@ namespace OpenSim.Region.Framework.Scenes
1105 1185
1106 group.RemoveInventoryItem(localID, itemID); 1186 group.RemoveInventoryItem(localID, itemID);
1107 } 1187 }
1188
1108 part.SendPropertiesToClient(remoteClient); 1189 part.SendPropertiesToClient(remoteClient);
1109 } 1190 }
1110 } 1191 }
1111 1192
1112 private InventoryItemBase CreateAgentInventoryItemFromTask(UUID destAgent, SceneObjectPart part, UUID itemId) 1193
1194 /// <summary>
1195 /// Creates (in memory only) a user inventory item that will contain a copy of a task inventory item.
1196 /// </summary>
1197 private InventoryItemBase CreateAgentInventoryItemFromTask(UUID destAgent, SceneObjectPart part, UUID itemId, out string message)
1113 { 1198 {
1114 TaskInventoryItem taskItem = part.Inventory.GetInventoryItem(itemId); 1199 TaskInventoryItem taskItem = part.Inventory.GetInventoryItem(itemId);
1115 1200
@@ -1120,12 +1205,13 @@ namespace OpenSim.Region.Framework.Scenes
1120 + " inventory item from a prim's inventory item " 1205 + " inventory item from a prim's inventory item "
1121 + " but the required item does not exist in the prim's inventory", 1206 + " but the required item does not exist in the prim's inventory",
1122 itemId, part.Name, part.UUID); 1207 itemId, part.Name, part.UUID);
1123 1208 message = "Item not found: " + itemId;
1124 return null; 1209 return null;
1125 } 1210 }
1126 1211
1127 if ((destAgent != taskItem.OwnerID) && ((taskItem.CurrentPermissions & (uint)PermissionMask.Transfer) == 0)) 1212 if ((destAgent != taskItem.OwnerID) && ((taskItem.CurrentPermissions & (uint)PermissionMask.Transfer) == 0))
1128 { 1213 {
1214 message = "Item doesn't have the Transfer permission.";
1129 return null; 1215 return null;
1130 } 1216 }
1131 1217
@@ -1146,9 +1232,21 @@ namespace OpenSim.Region.Framework.Scenes
1146 { 1232 {
1147 agentItem.BasePermissions = taskItem.BasePermissions & (taskItem.NextPermissions | (uint)PermissionMask.Move); 1233 agentItem.BasePermissions = taskItem.BasePermissions & (taskItem.NextPermissions | (uint)PermissionMask.Move);
1148 if (taskItem.InvType == (int)InventoryType.Object) 1234 if (taskItem.InvType == (int)InventoryType.Object)
1149 agentItem.CurrentPermissions = agentItem.BasePermissions & (((taskItem.CurrentPermissions & 7) << 13) | (taskItem.CurrentPermissions & (uint)PermissionMask.Move)); 1235 {
1150 else 1236 // Bake the new base permissions from folded permissions
1151 agentItem.CurrentPermissions = agentItem.BasePermissions & taskItem.CurrentPermissions; 1237 // The folded perms are in the lowest 3 bits of the current perms
1238 // We use base permissions here to avoid baking the "Locked" status
1239 // into the item as it is passed.
1240 uint perms = taskItem.BasePermissions & taskItem.NextPermissions;
1241 PermissionsUtil.ApplyFoldedPermissions(taskItem.CurrentPermissions, ref perms);
1242 // Avoid the "lock trap" - move must always be enabled but the above may remove it
1243 // Add it back here.
1244 agentItem.BasePermissions = perms | (uint)PermissionMask.Move;
1245 // Newly given items cannot be "locked" on rez. Make sure by
1246 // setting current equal to base.
1247 }
1248
1249 agentItem.CurrentPermissions = agentItem.BasePermissions;
1152 1250
1153 agentItem.Flags |= (uint)InventoryItemFlags.ObjectSlamPerm; 1251 agentItem.Flags |= (uint)InventoryItemFlags.ObjectSlamPerm;
1154 agentItem.NextPermissions = taskItem.NextPermissions; 1252 agentItem.NextPermissions = taskItem.NextPermissions;
@@ -1164,11 +1262,24 @@ namespace OpenSim.Region.Framework.Scenes
1164 agentItem.GroupPermissions = taskItem.GroupPermissions; 1262 agentItem.GroupPermissions = taskItem.GroupPermissions;
1165 } 1263 }
1166 1264
1265 message = null;
1266 return agentItem;
1267 }
1268
1269 /// <summary>
1270 /// If the task item is not-copyable then remove it from the prim.
1271 /// </summary>
1272 private void RemoveNonCopyTaskItemFromPrim(SceneObjectPart part, UUID itemId)
1273 {
1274 TaskInventoryItem taskItem = part.Inventory.GetInventoryItem(itemId);
1275 if (taskItem == null)
1276 return;
1277
1167 if (!Permissions.BypassPermissions()) 1278 if (!Permissions.BypassPermissions())
1168 { 1279 {
1169 if ((taskItem.CurrentPermissions & (uint)PermissionMask.Copy) == 0) 1280 if ((taskItem.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
1170 { 1281 {
1171 if (taskItem.Type == 10) 1282 if (taskItem.Type == (int)AssetType.LSLText)
1172 { 1283 {
1173 part.RemoveScriptEvents(itemId); 1284 part.RemoveScriptEvents(itemId);
1174 EventManager.TriggerRemoveScript(part.LocalId, itemId); 1285 EventManager.TriggerRemoveScript(part.LocalId, itemId);
@@ -1177,8 +1288,6 @@ namespace OpenSim.Region.Framework.Scenes
1177 part.Inventory.RemoveInventoryItem(itemId); 1288 part.Inventory.RemoveInventoryItem(itemId);
1178 } 1289 }
1179 } 1290 }
1180
1181 return agentItem;
1182 } 1291 }
1183 1292
1184 /// <summary> 1293 /// <summary>
@@ -1188,19 +1297,22 @@ namespace OpenSim.Region.Framework.Scenes
1188 /// <param name="folderID"></param> 1297 /// <param name="folderID"></param>
1189 /// <param name="part"></param> 1298 /// <param name="part"></param>
1190 /// <param name="itemID"></param> 1299 /// <param name="itemID"></param>
1191 public InventoryItemBase MoveTaskInventoryItem(IClientAPI remoteClient, UUID folderId, SceneObjectPart part, UUID itemId) 1300 public InventoryItemBase MoveTaskInventoryItem(IClientAPI remoteClient, UUID folderId, SceneObjectPart part, UUID itemId, out string message)
1192 { 1301 {
1193 m_log.DebugFormat( 1302 m_log.DebugFormat(
1194 "[PRIM INVENTORY]: Adding item {0} from {1} to folder {2} for {3}", 1303 "[PRIM INVENTORY]: Adding item {0} from {1} to folder {2} for {3}",
1195 itemId, part.Name, folderId, remoteClient.Name); 1304 itemId, part.Name, folderId, remoteClient.Name);
1196 1305
1197 InventoryItemBase agentItem = CreateAgentInventoryItemFromTask(remoteClient.AgentId, part, itemId); 1306 InventoryItemBase agentItem = CreateAgentInventoryItemFromTask(remoteClient.AgentId, part, itemId, out message);
1198
1199 if (agentItem == null) 1307 if (agentItem == null)
1200 return null; 1308 return null;
1201 1309
1202 agentItem.Folder = folderId; 1310 agentItem.Folder = folderId;
1203 AddInventoryItem(remoteClient, agentItem); 1311 AddInventoryItem(remoteClient, agentItem);
1312
1313 RemoveNonCopyTaskItemFromPrim(part, itemId);
1314
1315 message = null;
1204 return agentItem; 1316 return agentItem;
1205 } 1317 }
1206 1318
@@ -1251,7 +1363,11 @@ namespace OpenSim.Region.Framework.Scenes
1251 return; 1363 return;
1252 } 1364 }
1253 1365
1254 MoveTaskInventoryItem(remoteClient, folderId, part, itemId); 1366 string message;
1367 InventoryItemBase item = MoveTaskInventoryItem(remoteClient, folderId, part, itemId, out message);
1368
1369 if (item == null)
1370 remoteClient.SendAgentAlertMessage(message, false);
1255 } 1371 }
1256 1372
1257 /// <summary> 1373 /// <summary>
@@ -1265,17 +1381,17 @@ namespace OpenSim.Region.Framework.Scenes
1265 /// </param> 1381 /// </param>
1266 /// <param name="part"></param> 1382 /// <param name="part"></param>
1267 /// <param name="itemID"></param> 1383 /// <param name="itemID"></param>
1268 public InventoryItemBase MoveTaskInventoryItem(UUID avatarId, UUID folderId, SceneObjectPart part, UUID itemId) 1384 public InventoryItemBase MoveTaskInventoryItem(UUID avatarId, UUID folderId, SceneObjectPart part, UUID itemId, out string message)
1269 { 1385 {
1270 ScenePresence avatar; 1386 ScenePresence avatar;
1271 1387
1272 if (TryGetScenePresence(avatarId, out avatar)) 1388 if (TryGetScenePresence(avatarId, out avatar))
1273 { 1389 {
1274 return MoveTaskInventoryItem(avatar.ControllingClient, folderId, part, itemId); 1390 return MoveTaskInventoryItem(avatar.ControllingClient, folderId, part, itemId, out message);
1275 } 1391 }
1276 else 1392 else
1277 { 1393 {
1278 InventoryItemBase agentItem = CreateAgentInventoryItemFromTask(avatarId, part, itemId); 1394 InventoryItemBase agentItem = CreateAgentInventoryItemFromTask(avatarId, part, itemId, out message);
1279 1395
1280 if (agentItem == null) 1396 if (agentItem == null)
1281 return null; 1397 return null;
@@ -1284,6 +1400,8 @@ namespace OpenSim.Region.Framework.Scenes
1284 1400
1285 AddInventoryItem(agentItem); 1401 AddInventoryItem(agentItem);
1286 1402
1403 RemoveNonCopyTaskItemFromPrim(part, itemId);
1404
1287 return agentItem; 1405 return agentItem;
1288 } 1406 }
1289 } 1407 }
@@ -1389,6 +1507,11 @@ namespace OpenSim.Region.Framework.Scenes
1389 1507
1390 public UUID MoveTaskInventoryItems(UUID destID, string category, SceneObjectPart host, List<UUID> items) 1508 public UUID MoveTaskInventoryItems(UUID destID, string category, SceneObjectPart host, List<UUID> items)
1391 { 1509 {
1510 ScenePresence avatar;
1511 IClientAPI remoteClient = null;
1512 if (TryGetScenePresence(destID, out avatar))
1513 remoteClient = avatar.ControllingClient;
1514
1392 InventoryFolderBase rootFolder = InventoryService.GetRootFolder(destID); 1515 InventoryFolderBase rootFolder = InventoryService.GetRootFolder(destID);
1393 1516
1394 UUID newFolderID = UUID.Random(); 1517 UUID newFolderID = UUID.Random();
@@ -1398,26 +1521,28 @@ namespace OpenSim.Region.Framework.Scenes
1398 1521
1399 foreach (UUID itemID in items) 1522 foreach (UUID itemID in items)
1400 { 1523 {
1401 InventoryItemBase agentItem = CreateAgentInventoryItemFromTask(destID, host, itemID); 1524 string message;
1525 InventoryItemBase agentItem = CreateAgentInventoryItemFromTask(destID, host, itemID, out message);
1402 1526
1403 if (agentItem != null) 1527 if (agentItem != null)
1404 { 1528 {
1405 agentItem.Folder = newFolderID; 1529 agentItem.Folder = newFolderID;
1406 1530
1407 AddInventoryItem(agentItem); 1531 AddInventoryItem(agentItem);
1532
1533 RemoveNonCopyTaskItemFromPrim(host, itemID);
1534 }
1535 else
1536 {
1537 if (remoteClient != null)
1538 remoteClient.SendAgentAlertMessage(message, false);
1408 } 1539 }
1409 } 1540 }
1410 1541
1411 ScenePresence avatar = null; 1542 if (remoteClient != null)
1412 if (TryGetScenePresence(destID, out avatar))
1413 { 1543 {
1414 //profile.SendInventoryDecendents(avatar.ControllingClient, 1544 SendInventoryUpdate(remoteClient, rootFolder, true, false);
1415 // profile.RootFolder.ID, true, false); 1545 SendInventoryUpdate(remoteClient, newFolder, false, true);
1416 //profile.SendInventoryDecendents(avatar.ControllingClient,
1417 // newFolderID, false, true);
1418
1419 SendInventoryUpdate(avatar.ControllingClient, rootFolder, true, false);
1420 SendInventoryUpdate(avatar.ControllingClient, newFolder, false, true);
1421 } 1546 }
1422 1547
1423 return newFolderID; 1548 return newFolderID;
@@ -1572,11 +1697,11 @@ namespace OpenSim.Region.Framework.Scenes
1572 remoteClient, part, transactionID, currentItem); 1697 remoteClient, part, transactionID, currentItem);
1573 1698
1574 if ((InventoryType)itemInfo.InvType == InventoryType.Notecard) 1699 if ((InventoryType)itemInfo.InvType == InventoryType.Notecard)
1575 remoteClient.SendAgentAlertMessage("Notecard saved", false); 1700 remoteClient.SendAlertMessage("Notecard saved");
1576 else if ((InventoryType)itemInfo.InvType == InventoryType.LSL) 1701 else if ((InventoryType)itemInfo.InvType == InventoryType.LSL)
1577 remoteClient.SendAgentAlertMessage("Script saved", false); 1702 remoteClient.SendAlertMessage("Script saved");
1578 else 1703 else
1579 remoteClient.SendAgentAlertMessage("Item saved", false); 1704 remoteClient.SendAlertMessage("Item saved");
1580 } 1705 }
1581 1706
1582 // Base ALWAYS has move 1707 // Base ALWAYS has move
@@ -1739,6 +1864,21 @@ namespace OpenSim.Region.Framework.Scenes
1739 /// <returns>The part where the script was rezzed if successful. False otherwise.</returns> 1864 /// <returns>The part where the script was rezzed if successful. False otherwise.</returns>
1740 public SceneObjectPart RezNewScript(UUID agentID, InventoryItemBase itemBase) 1865 public SceneObjectPart RezNewScript(UUID agentID, InventoryItemBase itemBase)
1741 { 1866 {
1867 return RezNewScript(
1868 agentID,
1869 itemBase,
1870 "default\n{\n state_entry()\n {\n llSay(0, \"Script running\");\n }\n}");
1871 }
1872
1873 /// <summary>
1874 /// Rez a new script from nothing with given script text.
1875 /// </summary>
1876 /// <param name="remoteClient"></param>
1877 /// <param name="itemBase">Template item.</param>
1878 /// <param name="scriptText"></param>
1879 /// <returns>The part where the script was rezzed if successful. False otherwise.</returns>
1880 public SceneObjectPart RezNewScript(UUID agentID, InventoryItemBase itemBase, string scriptText)
1881 {
1742 // The part ID is the folder ID! 1882 // The part ID is the folder ID!
1743 SceneObjectPart part = GetSceneObjectPart(itemBase.Folder); 1883 SceneObjectPart part = GetSceneObjectPart(itemBase.Folder);
1744 if (part == null) 1884 if (part == null)
@@ -1758,9 +1898,14 @@ namespace OpenSim.Region.Framework.Scenes
1758 return null; 1898 return null;
1759 } 1899 }
1760 1900
1761 AssetBase asset = CreateAsset(itemBase.Name, itemBase.Description, (sbyte)itemBase.AssetType, 1901 AssetBase asset
1762 Encoding.ASCII.GetBytes("default\n{\n state_entry()\n {\n llSay(0, \"Script running\");\n }\n}"), 1902 = CreateAsset(
1763 agentID); 1903 itemBase.Name,
1904 itemBase.Description,
1905 (sbyte)itemBase.AssetType,
1906 Encoding.ASCII.GetBytes(scriptText),
1907 agentID);
1908
1764 AssetService.Store(asset); 1909 AssetService.Store(asset);
1765 1910
1766 TaskInventoryItem taskItem = new TaskInventoryItem(); 1911 TaskInventoryItem taskItem = new TaskInventoryItem();
@@ -1801,8 +1946,11 @@ namespace OpenSim.Region.Framework.Scenes
1801 /// Rez a script into a prim's inventory from another prim 1946 /// Rez a script into a prim's inventory from another prim
1802 /// </summary> 1947 /// </summary>
1803 /// <param name="remoteClient"></param> 1948 /// <param name="remoteClient"></param>
1804 /// <param name="itemID"> </param> 1949 /// <param name="srcPart"> </param>
1805 /// <param name="localID"></param> 1950 /// <param name="destId"> </param>
1951 /// <param name="pin"></param>
1952 /// <param name="running"></param>
1953 /// <param name="start_param"></param>
1806 public void RezScriptFromPrim(UUID srcId, SceneObjectPart srcPart, UUID destId, int pin, int running, int start_param) 1954 public void RezScriptFromPrim(UUID srcId, SceneObjectPart srcPart, UUID destId, int pin, int running, int start_param)
1807 { 1955 {
1808 TaskInventoryItem srcTaskItem = srcPart.Inventory.GetInventoryItem(srcId); 1956 TaskInventoryItem srcTaskItem = srcPart.Inventory.GetInventoryItem(srcId);
@@ -1822,12 +1970,11 @@ namespace OpenSim.Region.Framework.Scenes
1822 if (destPart == null) 1970 if (destPart == null)
1823 { 1971 {
1824 m_log.ErrorFormat( 1972 m_log.ErrorFormat(
1825 "[PRIM INVENTORY]: " + 1973 "[PRIM INVENTORY]: Could not find part {0} to insert script item {1} from {2} {3} in {4}",
1826 "Could not find script for ID {0}", 1974 destId, srcId, srcPart.Name, srcPart.UUID, Name);
1827 destId);
1828 return; 1975 return;
1829 } 1976 }
1830 1977
1831 // Must own the object, and have modify rights 1978 // Must own the object, and have modify rights
1832 if (srcPart.OwnerID != destPart.OwnerID) 1979 if (srcPart.OwnerID != destPart.OwnerID)
1833 { 1980 {
@@ -1835,12 +1982,14 @@ namespace OpenSim.Region.Framework.Scenes
1835 if ((destPart.GroupID == UUID.Zero) || (destPart.GroupID != srcPart.GroupID) || 1982 if ((destPart.GroupID == UUID.Zero) || (destPart.GroupID != srcPart.GroupID) ||
1836 ((destPart.GroupMask & (uint)PermissionMask.Modify) == 0)) 1983 ((destPart.GroupMask & (uint)PermissionMask.Modify) == 0))
1837 return; 1984 return;
1838 } else { 1985 }
1986 else
1987 {
1839 if ((destPart.OwnerMask & (uint)PermissionMask.Modify) == 0) 1988 if ((destPart.OwnerMask & (uint)PermissionMask.Modify) == 0)
1840 return; 1989 return;
1841 } 1990 }
1842 1991
1843 if (destPart.ScriptAccessPin != pin) 1992 if (destPart.ScriptAccessPin == 0 || destPart.ScriptAccessPin != pin)
1844 { 1993 {
1845 m_log.WarnFormat( 1994 m_log.WarnFormat(
1846 "[PRIM INVENTORY]: " + 1995 "[PRIM INVENTORY]: " +
@@ -1954,7 +2103,7 @@ namespace OpenSim.Region.Framework.Scenes
1954 deleteGroups.Add(grp); 2103 deleteGroups.Add(grp);
1955 2104
1956 // If child prims have invalid perms, fix them 2105 // If child prims have invalid perms, fix them
1957 grp.AdjustChildPrimPermissions(); 2106 grp.AdjustChildPrimPermissions(false);
1958 2107
1959 if (remoteClient == null) 2108 if (remoteClient == null)
1960 { 2109 {
@@ -2004,7 +2153,10 @@ namespace OpenSim.Region.Framework.Scenes
2004 { 2153 {
2005 // If we don't have permission, stop right here 2154 // If we don't have permission, stop right here
2006 if (!permissionToTakeCopy) 2155 if (!permissionToTakeCopy)
2156 {
2157 remoteClient.SendAlertMessage("You don't have permission to take the object");
2007 return; 2158 return;
2159 }
2008 2160
2009 permissionToTake = true; 2161 permissionToTake = true;
2010 // Don't delete 2162 // Don't delete
@@ -2036,13 +2188,16 @@ namespace OpenSim.Region.Framework.Scenes
2036 } 2188 }
2037 } 2189 }
2038 2190
2191 // OK, we're done with permissions. Let's check if any part of the code prevents the objects from being deleted
2192 bool canDelete = EventManager.TriggerDeRezRequested(remoteClient, deleteGroups, action);
2193
2039 if (permissionToTake && (action != DeRezAction.Delete || this.m_useTrashOnDelete)) 2194 if (permissionToTake && (action != DeRezAction.Delete || this.m_useTrashOnDelete))
2040 { 2195 {
2041 m_asyncSceneObjectDeleter.DeleteToInventory( 2196 m_asyncSceneObjectDeleter.DeleteToInventory(
2042 action, destinationID, deleteGroups, remoteClient, 2197 action, destinationID, deleteGroups, remoteClient,
2043 permissionToDelete); 2198 permissionToDelete && canDelete);
2044 } 2199 }
2045 else if (permissionToDelete) 2200 else if (permissionToDelete && canDelete)
2046 { 2201 {
2047 foreach (SceneObjectGroup g in deleteGroups) 2202 foreach (SceneObjectGroup g in deleteGroups)
2048 DeleteSceneObject(g, false); 2203 DeleteSceneObject(g, false);
@@ -2050,6 +2205,112 @@ namespace OpenSim.Region.Framework.Scenes
2050 } 2205 }
2051 2206
2052 /// <summary> 2207 /// <summary>
2208 /// Returns the list of Scene Objects in an asset.
2209 /// </summary>
2210 /// <remarks>
2211 /// Returns one object if the asset is a regular object, and multiple objects for a coalesced object.
2212 /// </remarks>
2213 /// <param name="assetData">Asset data</param>
2214 /// <param name="isAttachment">True if the object is an attachment.</param>
2215 /// <param name="objlist">The objects included in the asset</param>
2216 /// <param name="veclist">Relative positions of the objects</param>
2217 /// <param name="bbox">Bounding box of all the objects</param>
2218 /// <param name="offsetHeight">Offset in the Z axis from the centre of the bounding box
2219 /// to the centre of the root prim (relevant only when returning a single object)</param>
2220 /// <returns>
2221 /// true if returning a single object or deserialization fails, false if returning the coalesced
2222 /// list of objects
2223 /// </returns>
2224 public bool GetObjectsToRez(
2225 byte[] assetData, bool isAttachment, out List<SceneObjectGroup> objlist, out List<Vector3> veclist,
2226 out Vector3 bbox, out float offsetHeight)
2227 {
2228 objlist = new List<SceneObjectGroup>();
2229 veclist = new List<Vector3>();
2230 bbox = Vector3.Zero;
2231 offsetHeight = 0;
2232
2233 string xmlData = ExternalRepresentationUtils.SanitizeXml(Utils.BytesToString(assetData));
2234
2235 try
2236 {
2237 using (XmlTextReader wrappedReader = new XmlTextReader(xmlData, XmlNodeType.Element, null))
2238 {
2239 using (XmlReader reader = XmlReader.Create(wrappedReader, new XmlReaderSettings() { IgnoreWhitespace = true, ConformanceLevel = ConformanceLevel.Fragment }))
2240 {
2241 reader.Read();
2242 bool isSingleObject = reader.Name != "CoalescedObject";
2243
2244 if (isSingleObject || isAttachment)
2245 {
2246 SceneObjectGroup g;
2247 try
2248 {
2249 g = SceneObjectSerializer.FromOriginalXmlFormat(reader);
2250 }
2251 catch (Exception e)
2252 {
2253 m_log.Error("[AGENT INVENTORY]: Deserialization of xml failed ", e);
2254 Util.LogFailedXML("[AGENT INVENTORY]:", xmlData);
2255 g = null;
2256 }
2257
2258 if (g != null)
2259 {
2260 objlist.Add(g);
2261 veclist.Add(Vector3.Zero);
2262 bbox = g.GetAxisAlignedBoundingBox(out offsetHeight);
2263 }
2264
2265 return true;
2266 }
2267 else
2268 {
2269 XmlDocument doc = new XmlDocument();
2270 doc.LoadXml(xmlData);
2271 XmlElement e = (XmlElement)doc.SelectSingleNode("/CoalescedObject");
2272 XmlElement coll = (XmlElement)e;
2273 float bx = Convert.ToSingle(coll.GetAttribute("x"));
2274 float by = Convert.ToSingle(coll.GetAttribute("y"));
2275 float bz = Convert.ToSingle(coll.GetAttribute("z"));
2276 bbox = new Vector3(bx, by, bz);
2277 offsetHeight = 0;
2278
2279 XmlNodeList groups = e.SelectNodes("SceneObjectGroup");
2280 foreach (XmlNode n in groups)
2281 {
2282 SceneObjectGroup g = SceneObjectSerializer.FromOriginalXmlFormat(n.OuterXml);
2283 if (g != null)
2284 {
2285 objlist.Add(g);
2286
2287 XmlElement el = (XmlElement)n;
2288 string rawX = el.GetAttribute("offsetx");
2289 string rawY = el.GetAttribute("offsety");
2290 string rawZ = el.GetAttribute("offsetz");
2291
2292 float x = Convert.ToSingle(rawX);
2293 float y = Convert.ToSingle(rawY);
2294 float z = Convert.ToSingle(rawZ);
2295 veclist.Add(new Vector3(x, y, z));
2296 }
2297 }
2298
2299 return false;
2300 }
2301 }
2302 }
2303 }
2304 catch (Exception e)
2305 {
2306 m_log.Error("[AGENT INVENTORY]: Deserialization of xml failed when looking for CoalescedObject tag ", e);
2307 Util.LogFailedXML("[AGENT INVENTORY]:", xmlData);
2308 }
2309
2310 return true;
2311 }
2312
2313 /// <summary>
2053 /// Event Handler Rez an object into a scene 2314 /// Event Handler Rez an object into a scene
2054 /// Calls the non-void event handler 2315 /// Calls the non-void event handler
2055 /// </summary> 2316 /// </summary>
@@ -2124,19 +2385,25 @@ namespace OpenSim.Region.Framework.Scenes
2124 /// will be used if it exists.</param> 2385 /// will be used if it exists.</param>
2125 /// <param name="vel">The velocity of the rezzed object.</param> 2386 /// <param name="vel">The velocity of the rezzed object.</param>
2126 /// <param name="param"></param> 2387 /// <param name="param"></param>
2127 /// <returns>The SceneObjectGroup rezzed or null if rez was unsuccessful</returns> 2388 /// <returns>The SceneObjectGroup(s) rezzed, or null if rez was unsuccessful</returns>
2128 public virtual SceneObjectGroup RezObject( 2389 public virtual List<SceneObjectGroup> RezObject(
2129 SceneObjectPart sourcePart, TaskInventoryItem item, Vector3 pos, Quaternion? rot, Vector3 vel, int param) 2390 SceneObjectPart sourcePart, TaskInventoryItem item, Vector3 pos, Quaternion? rot, Vector3 vel, int param)
2130 { 2391 {
2131 if (null == item) 2392 if (null == item)
2132 return null; 2393 return null;
2394
2395 List<SceneObjectGroup> objlist;
2396 List<Vector3> veclist;
2133 2397
2134 SceneObjectGroup group = sourcePart.Inventory.GetRezReadySceneObject(item); 2398 bool success = sourcePart.Inventory.GetRezReadySceneObjects(item, out objlist, out veclist);
2135 2399 if (!success)
2136 if (null == group)
2137 return null; 2400 return null;
2138 2401
2139 if (!Permissions.CanRezObject(group.PrimCount, item.OwnerID, pos)) 2402 int totalPrims = 0;
2403 foreach (SceneObjectGroup group in objlist)
2404 totalPrims += group.PrimCount;
2405
2406 if (!Permissions.CanRezObject(totalPrims, item.OwnerID, pos))
2140 return null; 2407 return null;
2141 2408
2142 if (!Permissions.BypassPermissions()) 2409 if (!Permissions.BypassPermissions())
@@ -2145,16 +2412,28 @@ namespace OpenSim.Region.Framework.Scenes
2145 sourcePart.Inventory.RemoveInventoryItem(item.ItemID); 2412 sourcePart.Inventory.RemoveInventoryItem(item.ItemID);
2146 } 2413 }
2147 2414
2148 group.FromPartID = sourcePart.UUID; 2415 for (int i = 0; i < objlist.Count; i++)
2149 AddNewSceneObject(group, true, pos, rot, vel); 2416 {
2150 2417 SceneObjectGroup group = objlist[i];
2151 // We can only call this after adding the scene object, since the scene object references the scene 2418 Vector3 curpos = pos + veclist[i];
2152 // to find out if scripts should be activated at all. 2419
2153 group.CreateScriptInstances(param, true, DefaultScriptEngine, 3); 2420 if (group.IsAttachment == false && group.RootPart.Shape.State != 0)
2154 2421 {
2155 group.ScheduleGroupForFullUpdate(); 2422 group.RootPart.AttachedPos = group.AbsolutePosition;
2156 2423 group.RootPart.Shape.LastAttachPoint = (byte)group.AttachmentPoint;
2157 return group; 2424 }
2425
2426 group.FromPartID = sourcePart.UUID;
2427 AddNewSceneObject(group, true, curpos, rot, vel);
2428
2429 // We can only call this after adding the scene object, since the scene object references the scene
2430 // to find out if scripts should be activated at all.
2431 group.CreateScriptInstances(param, true, DefaultScriptEngine, 3);
2432
2433 group.ScheduleGroupForFullUpdate();
2434 }
2435
2436 return objlist;
2158 } 2437 }
2159 2438
2160 public virtual bool returnObjects(SceneObjectGroup[] returnobjects, 2439 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;
31using OpenMetaverse; 31using OpenMetaverse;
32using OpenMetaverse.Packets; 32using OpenMetaverse.Packets;
33using OpenSim.Framework; 33using OpenSim.Framework;
34using OpenSim.Framework.Communications;
35using OpenSim.Services.Interfaces; 34using OpenSim.Services.Interfaces;
36 35
37namespace OpenSim.Region.Framework.Scenes 36namespace OpenSim.Region.Framework.Scenes
@@ -145,6 +144,21 @@ namespace OpenSim.Region.Framework.Scenes
145 } 144 }
146 145
147 /// <summary> 146 /// <summary>
147 ///
148 /// </summary>
149 /// <param name="message"></param>
150 /// <param name="type"></param>
151 /// <param name="channel"></param>
152 /// <param name="fromPos"></param>
153 /// <param name="fromName"></param>
154 /// <param name="fromAgentID"></param>
155 /// <param name="targetID"></param>
156 public void SimChatToAgent(UUID targetID, byte[] message, int channel, Vector3 fromPos, string fromName, UUID fromID, bool fromAgent)
157 {
158 SimChat(message, ChatTypeEnum.Region, channel, fromPos, fromName, fromID, targetID, fromAgent, false);
159 }
160
161 /// <summary>
148 /// Invoked when the client requests a prim. 162 /// Invoked when the client requests a prim.
149 /// </summary> 163 /// </summary>
150 /// <param name="primLocalID"></param> 164 /// <param name="primLocalID"></param>
@@ -244,25 +258,20 @@ namespace OpenSim.Region.Framework.Scenes
244 if (part.ParentGroup.RootPart.LocalId != part.LocalId) 258 if (part.ParentGroup.RootPart.LocalId != part.LocalId)
245 return; 259 return;
246 260
247 bool isAttachment = false;
248
249 // This is wrong, wrong, wrong. Selection should not be 261 // This is wrong, wrong, wrong. Selection should not be
250 // handled by group, but by prim. Legacy cruft. 262 // handled by group, but by prim. Legacy cruft.
251 // TODO: Make selection flagging per prim! 263 // TODO: Make selection flagging per prim!
252 // 264 //
253 part.ParentGroup.IsSelected = false; 265 part.ParentGroup.IsSelected = false;
254 266
255 if (part.ParentGroup.IsAttachment) 267 part.ParentGroup.ScheduleGroupForFullUpdate();
256 isAttachment = true;
257 else
258 part.ParentGroup.ScheduleGroupForFullUpdate();
259 268
260 // If it's not an attachment, and we are allowed to move it, 269 // If it's not an attachment, and we are allowed to move it,
261 // then we might have done so. If we moved across a parcel 270 // then we might have done so. If we moved across a parcel
262 // boundary, we will need to recount prims on the parcels. 271 // boundary, we will need to recount prims on the parcels.
263 // For attachments, that makes no sense. 272 // For attachments, that makes no sense.
264 // 273 //
265 if (!isAttachment) 274 if (!part.ParentGroup.IsAttachment)
266 { 275 {
267 if (Permissions.CanEditObject( 276 if (Permissions.CanEditObject(
268 part.UUID, remoteClient.AgentId) 277 part.UUID, remoteClient.AgentId)
@@ -390,6 +399,7 @@ namespace OpenSim.Region.Framework.Scenes
390 void ProcessViewerEffect(IClientAPI remoteClient, List<ViewerEffectEventHandlerArg> args) 399 void ProcessViewerEffect(IClientAPI remoteClient, List<ViewerEffectEventHandlerArg> args)
391 { 400 {
392 // TODO: don't create new blocks if recycling an old packet 401 // TODO: don't create new blocks if recycling an old packet
402 bool discardableEffects = true;
393 ViewerEffectPacket.EffectBlock[] effectBlockArray = new ViewerEffectPacket.EffectBlock[args.Count]; 403 ViewerEffectPacket.EffectBlock[] effectBlockArray = new ViewerEffectPacket.EffectBlock[args.Count];
394 for (int i = 0; i < args.Count; i++) 404 for (int i = 0; i < args.Count; i++)
395 { 405 {
@@ -401,17 +411,34 @@ namespace OpenSim.Region.Framework.Scenes
401 effect.Type = args[i].Type; 411 effect.Type = args[i].Type;
402 effect.TypeData = args[i].TypeData; 412 effect.TypeData = args[i].TypeData;
403 effectBlockArray[i] = effect; 413 effectBlockArray[i] = effect;
414
415 if ((EffectType)effect.Type != EffectType.LookAt && (EffectType)effect.Type != EffectType.Beam)
416 discardableEffects = false;
417
418 //m_log.DebugFormat("[YYY]: VE {0} {1} {2}", effect.AgentID, effect.Duration, (EffectType)effect.Type);
404 } 419 }
405 420
406 ForEachClient( 421 ForEachScenePresence(sp =>
407 delegate(IClientAPI client)
408 { 422 {
409 if (client.AgentId != remoteClient.AgentId) 423 if (sp.ControllingClient.AgentId != remoteClient.AgentId)
410 client.SendViewerEffect(effectBlockArray); 424 {
411 } 425 if (!discardableEffects ||
412 ); 426 (discardableEffects && ShouldSendDiscardableEffect(remoteClient, sp)))
427 {
428 //m_log.DebugFormat("[YYY]: Sending to {0}", sp.UUID);
429 sp.ControllingClient.SendViewerEffect(effectBlockArray);
430 }
431 //else
432 // m_log.DebugFormat("[YYY]: Not sending to {0}", sp.UUID);
433 }
434 });
413 } 435 }
414 436
437 private bool ShouldSendDiscardableEffect(IClientAPI thisClient, ScenePresence other)
438 {
439 return Vector3.Distance(other.CameraPosition, thisClient.SceneAgent.AbsolutePosition) < 10;
440 }
441
415 /// <summary> 442 /// <summary>
416 /// Tell the client about the various child items and folders contained in the requested folder. 443 /// Tell the client about the various child items and folders contained in the requested folder.
417 /// </summary> 444 /// </summary>
@@ -459,7 +486,16 @@ namespace OpenSim.Region.Framework.Scenes
459 486
460 void SendInventoryAsync(IClientAPI remoteClient, UUID folderID, UUID ownerID, bool fetchFolders, bool fetchItems, int sortOrder) 487 void SendInventoryAsync(IClientAPI remoteClient, UUID folderID, UUID ownerID, bool fetchFolders, bool fetchItems, int sortOrder)
461 { 488 {
462 SendInventoryUpdate(remoteClient, new InventoryFolderBase(folderID), fetchFolders, fetchItems); 489 try
490 {
491 SendInventoryUpdate(remoteClient, new InventoryFolderBase(folderID), fetchFolders, fetchItems);
492 }
493 catch (Exception e)
494 {
495 m_log.Error(
496 string.Format(
497 "[AGENT INVENTORY]: Error in SendInventoryAsync() for {0} with folder ID {1}. Exception ", e));
498 }
463 } 499 }
464 500
465 void SendInventoryComplete(IAsyncResult iar) 501 void SendInventoryComplete(IAsyncResult iar)
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index f87d469..2fe6e22 100644..100755
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -6,7 +6,7 @@
6 * modification, are permitted provided that the following conditions are met: 6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright 7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer. 8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD 9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution. 11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the 12 * * Neither the name of the OpenSimulator Project nor the
@@ -39,18 +39,19 @@ using Nini.Config;
39using OpenMetaverse; 39using OpenMetaverse;
40using OpenMetaverse.Packets; 40using OpenMetaverse.Packets;
41using OpenMetaverse.Imaging; 41using OpenMetaverse.Imaging;
42using OpenMetaverse.StructuredData;
42using OpenSim.Framework; 43using OpenSim.Framework;
43using OpenSim.Framework.Monitoring; 44using OpenSim.Framework.Monitoring;
44using OpenSim.Services.Interfaces; 45using OpenSim.Services.Interfaces;
45using OpenSim.Framework.Communications;
46using OpenSim.Framework.Console; 46using OpenSim.Framework.Console;
47using OpenSim.Region.Framework.Interfaces; 47using OpenSim.Region.Framework.Interfaces;
48using OpenSim.Region.Framework.Scenes.Scripting; 48using OpenSim.Region.Framework.Scenes.Scripting;
49using OpenSim.Region.Framework.Scenes.Serialization; 49using OpenSim.Region.Framework.Scenes.Serialization;
50using OpenSim.Region.Physics.Manager; 50using OpenSim.Region.PhysicsModules.SharedBase;
51using Timer=System.Timers.Timer; 51using Timer = System.Timers.Timer;
52using TPFlags = OpenSim.Framework.Constants.TeleportFlags; 52using TPFlags = OpenSim.Framework.Constants.TeleportFlags;
53using GridRegion = OpenSim.Services.Interfaces.GridRegion; 53using GridRegion = OpenSim.Services.Interfaces.GridRegion;
54using PermissionMask = OpenSim.Framework.PermissionMask;
54 55
55namespace OpenSim.Region.Framework.Scenes 56namespace OpenSim.Region.Framework.Scenes
56{ 57{
@@ -60,6 +61,8 @@ namespace OpenSim.Region.Framework.Scenes
60 { 61 {
61 private const long DEFAULT_MIN_TIME_FOR_PERSISTENCE = 60L; 62 private const long DEFAULT_MIN_TIME_FOR_PERSISTENCE = 60L;
62 private const long DEFAULT_MAX_TIME_FOR_PERSISTENCE = 600L; 63 private const long DEFAULT_MAX_TIME_FOR_PERSISTENCE = 600L;
64
65 public const int m_defaultNumberFramesStored = 10;
63 66
64 public delegate void SynchronizeSceneHandler(Scene scene); 67 public delegate void SynchronizeSceneHandler(Scene scene);
65 68
@@ -102,15 +105,37 @@ namespace OpenSim.Region.Framework.Scenes
102 /// <summary> 105 /// <summary>
103 /// If false then physical objects are disabled, though collisions will continue as normal. 106 /// If false then physical objects are disabled, though collisions will continue as normal.
104 /// </summary> 107 /// </summary>
105 public bool PhysicsEnabled { get; set; } 108 public bool PhysicsEnabled
109 {
110 get
111 {
112 return m_physicsEnabled;
113 }
114
115 set
116 {
117 m_physicsEnabled = value;
118
119 if (PhysicsScene != null)
120 {
121 IPhysicsParameters physScene = PhysicsScene as IPhysicsParameters;
122
123 if (physScene != null)
124 physScene.SetPhysicsParameter(
125 "Active", m_physicsEnabled.ToString(), PhysParameterEntry.APPLY_TO_NONE);
126 }
127 }
128 }
129
130 private bool m_physicsEnabled;
106 131
107 /// <summary> 132 /// <summary>
108 /// If false then scripts are not enabled on the smiulator 133 /// If false then scripts are not enabled on the smiulator
109 /// </summary> 134 /// </summary>
110 public bool ScriptsEnabled 135 public bool ScriptsEnabled
111 { 136 {
112 get { return m_scripts_enabled; } 137 get { return m_scripts_enabled; }
113 set 138 set
114 { 139 {
115 if (m_scripts_enabled != value) 140 if (m_scripts_enabled != value)
116 { 141 {
@@ -128,7 +153,7 @@ namespace OpenSim.Region.Framework.Scenes
128 else 153 else
129 { 154 {
130 m_log.Info("Starting all Scripts in Scene"); 155 m_log.Info("Starting all Scripts in Scene");
131 156
132 EntityBase[] entities = Entities.GetEntities(); 157 EntityBase[] entities = Entities.GetEntities();
133 foreach (EntityBase ent in entities) 158 foreach (EntityBase ent in entities)
134 { 159 {
@@ -150,7 +175,7 @@ namespace OpenSim.Region.Framework.Scenes
150 public SynchronizeSceneHandler SynchronizeScene; 175 public SynchronizeSceneHandler SynchronizeScene;
151 176
152 /// <summary> 177 /// <summary>
153 /// Used to prevent simultaneous calls to RemoveClient() for the same agent from interfering with each other. 178 /// Used to prevent simultaneous calls to code that adds and removes agents.
154 /// </summary> 179 /// </summary>
155 private object m_removeClientLock = new object(); 180 private object m_removeClientLock = new object();
156 181
@@ -159,11 +184,6 @@ namespace OpenSim.Region.Framework.Scenes
159 /// </summary> 184 /// </summary>
160 public SimStatsReporter StatsReporter { get; private set; } 185 public SimStatsReporter StatsReporter { get; private set; }
161 186
162 public List<Border> NorthBorders = new List<Border>();
163 public List<Border> EastBorders = new List<Border>();
164 public List<Border> SouthBorders = new List<Border>();
165 public List<Border> WestBorders = new List<Border>();
166
167 /// <summary> 187 /// <summary>
168 /// Controls whether physics can be applied to prims. Even if false, prims still have entries in a 188 /// Controls whether physics can be applied to prims. Even if false, prims still have entries in a
169 /// PhysicsScene in order to perform collision detection 189 /// PhysicsScene in order to perform collision detection
@@ -196,7 +216,7 @@ namespace OpenSim.Region.Framework.Scenes
196 /// <summary> 216 /// <summary>
197 /// Maximum value of the size of a physical prim in each axis 217 /// Maximum value of the size of a physical prim in each axis
198 /// </summary> 218 /// </summary>
199 public float m_maxPhys = 10; 219 public float m_maxPhys = 64;
200 220
201 /// <summary> 221 /// <summary>
202 /// Max prims an object will hold 222 /// Max prims an object will hold
@@ -205,7 +225,13 @@ namespace OpenSim.Region.Framework.Scenes
205 225
206 public bool m_clampPrimSize; 226 public bool m_clampPrimSize;
207 public bool m_trustBinaries; 227 public bool m_trustBinaries;
208 public bool m_allowScriptCrossings; 228 public bool m_allowScriptCrossings = true;
229
230 /// <summary>
231 /// Can avatars cross from and to this region?
232 /// </summary>
233 public bool AllowAvatarCrossing { get; set; }
234
209 public bool m_useFlySlow; 235 public bool m_useFlySlow;
210 public bool m_useTrashOnDelete = true; 236 public bool m_useTrashOnDelete = true;
211 237
@@ -214,21 +240,58 @@ namespace OpenSim.Region.Framework.Scenes
214 /// </summary> 240 /// </summary>
215 public bool SendPeriodicAppearanceUpdates { get; set; } 241 public bool SendPeriodicAppearanceUpdates { get; set; }
216 242
243 /// <summary>
244 /// How much a root agent has to change position before updates are sent to viewers.
245 /// </summary>
246 public float RootPositionUpdateTolerance { get; set; }
247
248 /// <summary>
249 /// How much a root agent has to rotate before updates are sent to viewers.
250 /// </summary>
251 public float RootRotationUpdateTolerance { get; set; }
252
253 /// <summary>
254 /// How much a root agent has to change velocity before updates are sent to viewers.
255 /// </summary>
256 public float RootVelocityUpdateTolerance { get; set; }
257
258 /// <summary>
259 /// If greater than 1, we only send terse updates to other root agents on every n updates.
260 /// </summary>
261 public int RootTerseUpdatePeriod { get; set; }
262
263 /// <summary>
264 /// If greater than 1, we only send terse updates to child agents on every n updates.
265 /// </summary>
266 public int ChildTerseUpdatePeriod { get; set; }
267
217 protected float m_defaultDrawDistance = 255.0f; 268 protected float m_defaultDrawDistance = 255.0f;
218 public float DefaultDrawDistance 269 public float DefaultDrawDistance
219 { 270 {
220 get { return m_defaultDrawDistance; } 271 // get { return m_defaultDrawDistance; }
272 get
273 {
274 if (RegionInfo != null)
275 {
276 float largestDimension = Math.Max(RegionInfo.RegionSizeX, RegionInfo.RegionSizeY);
277 m_defaultDrawDistance = Math.Max(m_defaultDrawDistance, largestDimension);
278
279 }
280 return m_defaultDrawDistance;
281 }
221 } 282 }
222 283
223 private List<string> m_AllowedViewers = new List<string>(); 284 private List<string> m_AllowedViewers = new List<string>();
224 private List<string> m_BannedViewers = new List<string>(); 285 private List<string> m_BannedViewers = new List<string>();
225 286
226 // TODO: need to figure out how allow client agents but deny 287 // TODO: need to figure out how allow client agents but deny
227 // root agents when ACL denies access to root agent 288 // root agents when ACL denies access to root agent
228 public bool m_strictAccessControl = true; 289 public bool m_strictAccessControl = true;
229 290
230 public int MaxUndoCount { get; set; } 291 public int MaxUndoCount { get; set; }
231 292
293 public bool SeeIntoRegion { get; set; }
294
232 // Using this for RegionReady module to prevent LoginsDisabled from changing under our feet; 295 // Using this for RegionReady module to prevent LoginsDisabled from changing under our feet;
233 public bool LoginLock = false; 296 public bool LoginLock = false;
234 297
@@ -262,6 +325,7 @@ namespace OpenSim.Region.Framework.Scenes
262 protected IUserAccountService m_UserAccountService; 325 protected IUserAccountService m_UserAccountService;
263 protected IAvatarService m_AvatarService; 326 protected IAvatarService m_AvatarService;
264 protected IGridUserService m_GridUserService; 327 protected IGridUserService m_GridUserService;
328 protected IAgentPreferencesService m_AgentPreferencesService;
265 329
266 protected IXMLRPC m_xmlrpcModule; 330 protected IXMLRPC m_xmlrpcModule;
267 protected IWorldComm m_worldCommModule; 331 protected IWorldComm m_worldCommModule;
@@ -275,6 +339,17 @@ namespace OpenSim.Region.Framework.Scenes
275 private Dictionary<string, string> m_extraSettings; 339 private Dictionary<string, string> m_extraSettings;
276 340
277 /// <summary> 341 /// <summary>
342 /// If true then the next time the scene loop is activated, updates will be performed by firing of a timer
343 /// rather than on a single thread that sleeps.
344 /// </summary>
345 public bool UpdateOnTimer { get; set; }
346
347 /// <summary>
348 /// Only used if we are updating scene on a timer rather than sleeping a thread.
349 /// </summary>
350 private Timer m_sceneUpdateTimer;
351
352 /// <summary>
278 /// Current scene frame number 353 /// Current scene frame number
279 /// </summary> 354 /// </summary>
280 public uint Frame 355 public uint Frame
@@ -289,30 +364,59 @@ namespace OpenSim.Region.Framework.Scenes
289 public uint MaintenanceRun { get; private set; } 364 public uint MaintenanceRun { get; private set; }
290 365
291 /// <summary> 366 /// <summary>
292 /// The minimum length of time in seconds that will be taken for a scene frame. If the frame takes less time then we 367 /// The minimum length of time in milliseconds that will be taken for a scene frame. If the frame takes less time then we
293 /// will sleep for the remaining period. 368 /// will sleep for the remaining period.
294 /// </summary> 369 /// </summary>
295 /// <remarks> 370 /// <remarks>
296 /// One can tweak this number to experiment. One current effect of reducing it is to make avatar animations 371 /// One can tweak this number to experiment. One current effect of reducing it is to make avatar animations
297 /// occur too quickly (viewer 1) or with even more slide (viewer 2). 372 /// occur too quickly (viewer 1) or with even more slide (viewer 2).
298 /// </remarks> 373 /// </remarks>
299 public float MinFrameTime { get; private set; } 374 public int MinFrameTicks
375 {
376 get { return m_minFrameTicks; }
377 private set
378 {
379 m_minFrameTicks = value;
380 MinFrameSeconds = (float)m_minFrameTicks / 1000;
381 }
382 }
383 private int m_minFrameTicks;
384
385 public int FrameTimeWarnPercent { get; private set; }
386 public int FrameTimeCritPercent { get; private set; }
387
388 // Normalize the frame related stats to nominal 55fps for viewer and scripts option
389 // see SimStatsReporter.cs
390 public bool Normalized55FPS { get; private set; }
391
392 /// <summary>
393 /// The minimum length of time in seconds that will be taken for a scene frame.
394 /// </summary>
395 /// <remarks>
396 /// Always derived from MinFrameTicks.
397 /// </remarks>
398 public float MinFrameSeconds { get; private set; }
300 399
301 /// <summary> 400 /// <summary>
302 /// The minimum length of time in seconds that will be taken for a maintenance run. 401 /// The minimum length of time in milliseconds that will be taken for a scene frame. If the frame takes less time then we
402 /// will sleep for the remaining period.
303 /// </summary> 403 /// </summary>
304 public float MinMaintenanceTime { get; private set; } 404 /// <remarks>
405 /// One can tweak this number to experiment. One current effect of reducing it is to make avatar animations
406 /// occur too quickly (viewer 1) or with even more slide (viewer 2).
407 /// </remarks>
408 public int MinMaintenanceTicks { get; set; }
305 409
306 private int m_update_physics = 1; 410 private int m_update_physics = 1;
307 private int m_update_entitymovement = 1; 411 private int m_update_entitymovement = 1;
308 private int m_update_objects = 1; 412 private int m_update_objects = 1;
309 private int m_update_temp_cleaning = 1000;
310 private int m_update_presences = 1; // Update scene presence movements 413 private int m_update_presences = 1; // Update scene presence movements
311 private int m_update_events = 1; 414 private int m_update_events = 1;
312 private int m_update_backup = 200; 415 private int m_update_backup = 200;
313 private int m_update_terrain = 50; 416 private int m_update_terrain = 50;
314// private int m_update_land = 1; 417 // private int m_update_land = 1;
315 private int m_update_coarse_locations = 50; 418 private int m_update_coarse_locations = 50;
419 private int m_update_temp_cleaning = 180;
316 420
317 private int agentMS; 421 private int agentMS;
318 private int frameMS; 422 private int frameMS;
@@ -326,6 +430,17 @@ namespace OpenSim.Region.Framework.Scenes
326 private int landMS; 430 private int landMS;
327 private int spareMS; 431 private int spareMS;
328 432
433 // A temporary configuration flag to enable using FireAndForget to process
434 // collisions from the physics engine. There is a problem with collisions
435 // stopping sometimes and MB's suspicion is some race condition passing
436 // collisions from the physics engine callback to the script engine.
437 // This causes the collision events to be passed with a FireAndForget
438 // call which should eliminate that linkage. Testers can turn this on
439 // and see if collisions stop. If they don't, the problem is somewhere else.
440 // This feature defaults to 'off' so, by default, the simulator operation
441 // is not changed.
442 public bool ShouldUseFireAndForgetForCollisions = false;
443
329 /// <summary> 444 /// <summary>
330 /// Tick at which the last frame was processed. 445 /// Tick at which the last frame was processed.
331 /// </summary> 446 /// </summary>
@@ -337,16 +452,28 @@ namespace OpenSim.Region.Framework.Scenes
337 private int m_lastMaintenanceTick; 452 private int m_lastMaintenanceTick;
338 453
339 /// <summary> 454 /// <summary>
455 /// Total script execution time (in Stopwatch Ticks) since the last frame
456 /// </summary>
457 private long m_scriptExecutionTime = 0;
458
459 /// <summary>
340 /// Signals whether temporary objects are currently being cleaned up. Needed because this is launched 460 /// Signals whether temporary objects are currently being cleaned up. Needed because this is launched
341 /// asynchronously from the update loop. 461 /// asynchronously from the update loop.
342 /// </summary> 462 /// </summary>
343 private bool m_cleaningTemps = false; 463 private bool m_cleaningTemps = false;
344 464
345// private Object m_heartbeatLock = new Object(); 465 /// <summary>
466 /// Used to control main scene thread looping time when not updating via timer.
467 /// </summary>
468 private ManualResetEvent m_updateWaitEvent = new ManualResetEvent(false);
469
470 /// <summary>
471 /// Used to control maintenance thread runs.
472 /// </summary>
473 private ManualResetEvent m_maintenanceWaitEvent = new ManualResetEvent(false);
346 474
347 // TODO: Possibly stop other classes being able to manipulate this directly. 475 // TODO: Possibly stop other classes being able to manipulate this directly.
348 private SceneGraph m_sceneGraph; 476 private SceneGraph m_sceneGraph;
349 private volatile int m_bordersLocked;
350 private readonly Timer m_restartTimer = new Timer(15000); // Wait before firing 477 private readonly Timer m_restartTimer = new Timer(15000); // Wait before firing
351 private volatile bool m_backingup; 478 private volatile bool m_backingup;
352 private Dictionary<UUID, ReturnInfo> m_returns = new Dictionary<UUID, ReturnInfo>(); 479 private Dictionary<UUID, ReturnInfo> m_returns = new Dictionary<UUID, ReturnInfo>();
@@ -354,6 +481,12 @@ namespace OpenSim.Region.Framework.Scenes
354 481
355 private string m_defaultScriptEngine; 482 private string m_defaultScriptEngine;
356 483
484 private int m_unixStartTime;
485 public int UnixStartTime
486 {
487 get { return m_unixStartTime; }
488 }
489
357 /// <summary> 490 /// <summary>
358 /// Tick at which the last login occurred. 491 /// Tick at which the last login occurred.
359 /// </summary> 492 /// </summary>
@@ -377,7 +510,8 @@ namespace OpenSim.Region.Framework.Scenes
377 /// Is the scene active? 510 /// Is the scene active?
378 /// </summary> 511 /// </summary>
379 /// <remarks> 512 /// <remarks>
380 /// If false, maintenance and update loops are not being run. Updates can still be triggered manually if 513 /// If false, maintenance and update loops are not being run, though after setting to false update may still
514 /// be active for a period (and IsRunning will still be true). Updates can still be triggered manually if
381 /// the scene is not active. 515 /// the scene is not active.
382 /// </remarks> 516 /// </remarks>
383 public bool Active 517 public bool Active
@@ -388,24 +522,23 @@ namespace OpenSim.Region.Framework.Scenes
388 if (value) 522 if (value)
389 { 523 {
390 if (!m_active) 524 if (!m_active)
391 Start(); 525 Start(false);
392 } 526 }
393 else 527 else
394 { 528 {
529 // This appears assymetric with Start() above but is not - setting m_active = false stops the loops
530 // XXX: Possibly this should be in an explicit Stop() method for symmetry.
395 m_active = false; 531 m_active = false;
396 } 532 }
397 } 533 }
398 } 534 }
399 private volatile bool m_active; 535 private volatile bool m_active;
400 536
401// private int m_lastUpdate; 537 /// <summary>
402// private bool m_firstHeartbeat = true; 538 /// If true then updates are running. This may be true for a short period after a scene is de-activated.
403 539 /// </summary>
404 private UpdatePrioritizationSchemes m_priorityScheme = UpdatePrioritizationSchemes.Time; 540 public bool IsRunning { get { return m_isRunning; } }
405 private bool m_reprioritizationEnabled = true; 541 private volatile bool m_isRunning;
406 private double m_reprioritizationInterval = 5000.0;
407 private double m_rootReprioritizationDistance = 10.0;
408 private double m_childReprioritizationDistance = 20.0;
409 542
410 private Timer m_mapGenerationTimer = new Timer(); 543 private Timer m_mapGenerationTimer = new Timer();
411 private bool m_generateMaptiles; 544 private bool m_generateMaptiles;
@@ -421,23 +554,18 @@ namespace OpenSim.Region.Framework.Scenes
421 set { m_splitRegionID = value; } 554 set { m_splitRegionID = value; }
422 } 555 }
423 556
424 public bool BordersLocked
425 {
426 get { return m_bordersLocked == 1; }
427 set
428 {
429 if (value == true)
430 m_bordersLocked = 1;
431 else
432 m_bordersLocked = 0;
433 }
434 }
435
436 public new float TimeDilation 557 public new float TimeDilation
437 { 558 {
438 get { return m_sceneGraph.PhysicsScene.TimeDilation; } 559 get { return m_sceneGraph.PhysicsScene.TimeDilation; }
439 } 560 }
440 561
562 public void setThreadCount(int inUseThreads)
563 {
564 // Just pass the thread count information on its way as the Scene
565 // does not require the value for anything at this time
566 StatsReporter.SetThreadCount(inUseThreads);
567 }
568
441 public SceneCommunicationService SceneGridService 569 public SceneCommunicationService SceneGridService
442 { 570 {
443 get { return m_sceneGridService; } 571 get { return m_sceneGridService; }
@@ -496,7 +624,7 @@ namespace OpenSim.Region.Framework.Scenes
496 return m_AssetService; 624 return m_AssetService;
497 } 625 }
498 } 626 }
499 627
500 public IAuthorizationService AuthorizationService 628 public IAuthorizationService AuthorizationService
501 { 629 {
502 get 630 get
@@ -624,6 +752,16 @@ namespace OpenSim.Region.Framework.Scenes
624 } 752 }
625 } 753 }
626 754
755 public IAgentPreferencesService AgentPreferencesService
756 {
757 get
758 {
759 if (m_AgentPreferencesService == null)
760 m_AgentPreferencesService = RequestModuleInterface<IAgentPreferencesService>();
761 return m_AgentPreferencesService;
762 }
763 }
764
627 public IAttachmentsModule AttachmentsModule { get; set; } 765 public IAttachmentsModule AttachmentsModule { get; set; }
628 public IEntityTransferModule EntityTransferModule { get; private set; } 766 public IEntityTransferModule EntityTransferModule { get; private set; }
629 public IAgentAssetTransactions AgentTransactionsModule { get; private set; } 767 public IAgentAssetTransactions AgentTransactionsModule { get; private set; }
@@ -633,7 +771,7 @@ namespace OpenSim.Region.Framework.Scenes
633 { 771 {
634 get { return m_AvatarFactory; } 772 get { return m_AvatarFactory; }
635 } 773 }
636 774
637 public ICapabilitiesModule CapsModule 775 public ICapabilitiesModule CapsModule
638 { 776 {
639 get { return m_capsModule; } 777 get { return m_capsModule; }
@@ -650,11 +788,11 @@ namespace OpenSim.Region.Framework.Scenes
650 public int MonitorLandTime { get { return landMS; } } 788 public int MonitorLandTime { get { return landMS; } }
651 public int MonitorLastFrameTick { get { return m_lastFrameTick; } } 789 public int MonitorLastFrameTick { get { return m_lastFrameTick; } }
652 790
653 public UpdatePrioritizationSchemes UpdatePrioritizationScheme { get { return m_priorityScheme; } } 791 public UpdatePrioritizationSchemes UpdatePrioritizationScheme { get; set; }
654 public bool IsReprioritizationEnabled { get { return m_reprioritizationEnabled; } } 792 public bool IsReprioritizationEnabled { get; set; }
655 public double ReprioritizationInterval { get { return m_reprioritizationInterval; } } 793 public double ReprioritizationInterval { get; set; }
656 public double RootReprioritizationDistance { get { return m_rootReprioritizationDistance; } } 794 public double RootReprioritizationDistance { get; set; }
657 public double ChildReprioritizationDistance { get { return m_childReprioritizationDistance; } } 795 public double ChildReprioritizationDistance { get; set; }
658 796
659 public AgentCircuitManager AuthenticateHandler 797 public AgentCircuitManager AuthenticateHandler
660 { 798 {
@@ -699,43 +837,46 @@ namespace OpenSim.Region.Framework.Scenes
699 get { return m_sceneGraph.Entities; } 837 get { return m_sceneGraph.Entities; }
700 } 838 }
701 839
702 840
703 // used in sequence see: SpawnPoint() 841 // used in sequence see: SpawnPoint()
704 private int m_SpawnPoint; 842 private int m_SpawnPoint;
705 // can be closest/random/sequence 843 // can be closest/random/sequence
706 public string SpawnPointRouting 844 public string SpawnPointRouting
707 { 845 {
708 get; private set; 846 get;
847 private set;
709 } 848 }
710 // allow landmarks to pass 849 // allow landmarks to pass
711 public bool TelehubAllowLandmarks 850 public bool TelehubAllowLandmarks
712 { 851 {
713 get; private set; 852 get;
853 private set;
714 } 854 }
715 855
716 #endregion Properties 856 #endregion Properties
717 857
718 #region Constructors 858 #region Constructors
719 859
720 public Scene(RegionInfo regInfo, AgentCircuitManager authen, 860 public Scene(RegionInfo regInfo, AgentCircuitManager authen,
721 SceneCommunicationService sceneGridService,
722 ISimulationDataService simDataService, IEstateDataService estateDataService, 861 ISimulationDataService simDataService, IEstateDataService estateDataService,
723 bool dumpAssetsToFile,
724 IConfigSource config, string simulatorVersion) 862 IConfigSource config, string simulatorVersion)
725 : this(regInfo) 863 : this(regInfo)
726 { 864 {
727 m_config = config; 865 m_config = config;
728 MinFrameTime = 0.089f; 866 MinFrameTicks = 89;
729 MinMaintenanceTime = 1; 867 FrameTimeWarnPercent = 60;
868 FrameTimeCritPercent = 40;
869 Normalized55FPS = true;
870 MinMaintenanceTicks = 1000;
871 SeeIntoRegion = true;
730 872
731 Random random = new Random(); 873 Random random = new Random();
732 874
733 m_lastAllocatedLocalId = (uint)(random.NextDouble() * (double)(uint.MaxValue / 2)) + (uint)(uint.MaxValue / 4); 875 m_lastAllocatedLocalId = (uint)(random.NextDouble() * (double)(uint.MaxValue / 2)) + (uint)(uint.MaxValue / 4);
734 m_authenticateHandler = authen; 876 m_authenticateHandler = authen;
735 m_sceneGridService = sceneGridService; 877 m_sceneGridService = new SceneCommunicationService();
736 m_SimulationDataService = simDataService; 878 m_SimulationDataService = simDataService;
737 m_EstateDataService = estateDataService; 879 m_EstateDataService = estateDataService;
738 m_regionHandle = RegionInfo.RegionHandle;
739 880
740 m_asyncSceneObjectDeleter = new AsyncSceneObjectGroupDeleter(this); 881 m_asyncSceneObjectDeleter = new AsyncSceneObjectGroupDeleter(this);
741 m_asyncSceneObjectDeleter.Enabled = true; 882 m_asyncSceneObjectDeleter.Enabled = true;
@@ -794,25 +935,8 @@ namespace OpenSim.Region.Framework.Scenes
794 EventManager.OnLandObjectRemoved += 935 EventManager.OnLandObjectRemoved +=
795 new EventManager.LandObjectRemoved(simDataService.RemoveLandObject); 936 new EventManager.LandObjectRemoved(simDataService.RemoveLandObject);
796 937
797 m_sceneGraph = new SceneGraph(this);
798
799 // If the scene graph has an Unrecoverable error, restart this sim.
800 // Currently the only thing that causes it to happen is two kinds of specific
801 // Physics based crashes.
802 //
803 // Out of memory
804 // Operating system has killed the plugin
805 m_sceneGraph.UnRecoverableError
806 += () =>
807 {
808 m_log.ErrorFormat("[SCENE]: Restarting region {0} due to unrecoverable physics crash", Name);
809 RestartNow();
810 };
811
812 RegisterDefaultSceneEvents(); 938 RegisterDefaultSceneEvents();
813 939
814 DumpAssetsToFile = dumpAssetsToFile;
815
816 // XXX: Don't set the public property since we don't want to activate here. This needs to be handled 940 // XXX: Don't set the public property since we don't want to activate here. This needs to be handled
817 // better in the future. 941 // better in the future.
818 m_scripts_enabled = !RegionInfo.RegionSettings.DisableScripts; 942 m_scripts_enabled = !RegionInfo.RegionSettings.DisableScripts;
@@ -835,10 +959,12 @@ namespace OpenSim.Region.Framework.Scenes
835 UseBackup = startupConfig.GetBoolean("UseSceneBackup", UseBackup); 959 UseBackup = startupConfig.GetBoolean("UseSceneBackup", UseBackup);
836 if (!UseBackup) 960 if (!UseBackup)
837 m_log.InfoFormat("[SCENE]: Backup has been disabled for {0}", RegionInfo.RegionName); 961 m_log.InfoFormat("[SCENE]: Backup has been disabled for {0}", RegionInfo.RegionName);
838 962
839 //Animation states 963 //Animation states
840 m_useFlySlow = startupConfig.GetBoolean("enableflyslow", false); 964 m_useFlySlow = startupConfig.GetBoolean("enableflyslow", false);
841 965
966 SeeIntoRegion = startupConfig.GetBoolean("see_into_region", SeeIntoRegion);
967
842 MaxUndoCount = startupConfig.GetInt("MaxPrimUndos", 20); 968 MaxUndoCount = startupConfig.GetInt("MaxPrimUndos", 20);
843 969
844 PhysicalPrims = startupConfig.GetBoolean("physical_prim", PhysicalPrims); 970 PhysicalPrims = startupConfig.GetBoolean("physical_prim", PhysicalPrims);
@@ -887,10 +1013,10 @@ namespace OpenSim.Region.Framework.Scenes
887 m_trustBinaries = startupConfig.GetBoolean("TrustBinaries", m_trustBinaries); 1013 m_trustBinaries = startupConfig.GetBoolean("TrustBinaries", m_trustBinaries);
888 m_allowScriptCrossings = startupConfig.GetBoolean("AllowScriptCrossing", m_allowScriptCrossings); 1014 m_allowScriptCrossings = startupConfig.GetBoolean("AllowScriptCrossing", m_allowScriptCrossings);
889 m_dontPersistBefore = 1015 m_dontPersistBefore =
890 startupConfig.GetLong("MinimumTimeBeforePersistenceConsidered", DEFAULT_MIN_TIME_FOR_PERSISTENCE); 1016 startupConfig.GetLong("MinimumTimeBeforePersistenceConsidered", DEFAULT_MIN_TIME_FOR_PERSISTENCE);
891 m_dontPersistBefore *= 10000000; 1017 m_dontPersistBefore *= 10000000;
892 m_persistAfter = 1018 m_persistAfter =
893 startupConfig.GetLong("MaximumTimeBeforePersistenceConsidered", DEFAULT_MAX_TIME_FOR_PERSISTENCE); 1019 startupConfig.GetLong("MaximumTimeBeforePersistenceConsidered", DEFAULT_MAX_TIME_FOR_PERSISTENCE);
894 m_persistAfter *= 10000000; 1020 m_persistAfter *= 10000000;
895 1021
896 m_defaultScriptEngine = startupConfig.GetString("DefaultScriptEngine", "XEngine"); 1022 m_defaultScriptEngine = startupConfig.GetString("DefaultScriptEngine", "XEngine");
@@ -900,10 +1026,15 @@ namespace OpenSim.Region.Framework.Scenes
900 1026
901 m_strictAccessControl = startupConfig.GetBoolean("StrictAccessControl", m_strictAccessControl); 1027 m_strictAccessControl = startupConfig.GetBoolean("StrictAccessControl", m_strictAccessControl);
902 1028
903 m_generateMaptiles = startupConfig.GetBoolean("GenerateMaptiles", true); 1029 string[] possibleMapConfigSections = new string[] { "Map", "Startup" };
1030
1031 m_generateMaptiles
1032 = Util.GetConfigVarFromSections<bool>(config, "GenerateMaptiles", possibleMapConfigSections, true);
1033
904 if (m_generateMaptiles) 1034 if (m_generateMaptiles)
905 { 1035 {
906 int maptileRefresh = startupConfig.GetInt("MaptileRefresh", 0); 1036 int maptileRefresh = Util.GetConfigVarFromSections<int>(config, "MaptileRefresh", possibleMapConfigSections, 0);
1037 m_log.InfoFormat("[SCENE]: Region {0}, WORLD MAP refresh time set to {1} seconds", RegionInfo.RegionName, maptileRefresh);
907 if (maptileRefresh != 0) 1038 if (maptileRefresh != 0)
908 { 1039 {
909 m_mapGenerationTimer.Interval = maptileRefresh * 1000; 1040 m_mapGenerationTimer.Interval = maptileRefresh * 1000;
@@ -914,16 +1045,29 @@ namespace OpenSim.Region.Framework.Scenes
914 } 1045 }
915 else 1046 else
916 { 1047 {
917 string tile = startupConfig.GetString("MaptileStaticUUID", UUID.Zero.ToString()); 1048 string tile
1049 = Util.GetConfigVarFromSections<string>(
1050 config, "MaptileStaticUUID", possibleMapConfigSections, UUID.Zero.ToString());
1051
918 UUID tileID; 1052 UUID tileID;
919 1053
920 if (UUID.TryParse(tile, out tileID)) 1054 if (tile != UUID.Zero.ToString() && UUID.TryParse(tile, out tileID))
921 { 1055 {
922 RegionInfo.RegionSettings.TerrainImageID = tileID; 1056 RegionInfo.RegionSettings.TerrainImageID = tileID;
923 } 1057 }
1058 else
1059 {
1060 RegionInfo.RegionSettings.TerrainImageID = RegionInfo.MaptileStaticUUID;
1061 m_log.InfoFormat("[SCENE]: Region {0}, maptile set to {1}", RegionInfo.RegionName, RegionInfo.MaptileStaticUUID.ToString());
1062 }
924 } 1063 }
925 1064
926 string grant = startupConfig.GetString("AllowedClients", String.Empty); 1065 string[] possibleAccessControlConfigSections = new string[] { "Startup", "AccessControl"};
1066
1067 string grant
1068 = Util.GetConfigVarFromSections<string>(
1069 config, "AllowedClients", possibleAccessControlConfigSections, string.Empty);
1070
927 if (grant.Length > 0) 1071 if (grant.Length > 0)
928 { 1072 {
929 foreach (string viewer in grant.Split('|')) 1073 foreach (string viewer in grant.Split('|'))
@@ -932,7 +1076,14 @@ namespace OpenSim.Region.Framework.Scenes
932 } 1076 }
933 } 1077 }
934 1078
935 grant = startupConfig.GetString("BannedClients", String.Empty); 1079 grant
1080 = Util.GetConfigVarFromSections<string>(
1081 config, "DeniedClients", possibleAccessControlConfigSections, String.Empty);
1082 // Deal with the mess of someone having used a different word at some point
1083 if (grant == String.Empty)
1084 grant = Util.GetConfigVarFromSections<string>(
1085 config, "BannedClients", possibleAccessControlConfigSections, String.Empty);
1086
936 if (grant.Length > 0) 1087 if (grant.Length > 0)
937 { 1088 {
938 foreach (string viewer in grant.Split('|')) 1089 foreach (string viewer in grant.Split('|'))
@@ -941,21 +1092,32 @@ namespace OpenSim.Region.Framework.Scenes
941 } 1092 }
942 } 1093 }
943 1094
944 MinFrameTime = startupConfig.GetFloat( "MinFrameTime", MinFrameTime); 1095 if (startupConfig.Contains("MinFrameTime"))
945 m_update_backup = startupConfig.GetInt( "UpdateStorageEveryNFrames", m_update_backup); 1096 MinFrameTicks = (int)(startupConfig.GetFloat("MinFrameTime") * 1000);
946 m_update_coarse_locations = startupConfig.GetInt( "UpdateCoarseLocationsEveryNFrames", m_update_coarse_locations); 1097 FrameTimeWarnPercent = startupConfig.GetInt( "FrameTimeWarnPercent", FrameTimeWarnPercent);
947 m_update_entitymovement = startupConfig.GetInt( "UpdateEntityMovementEveryNFrames", m_update_entitymovement); 1098 FrameTimeCritPercent = startupConfig.GetInt( "FrameTimeCritPercent", FrameTimeCritPercent);
948 m_update_events = startupConfig.GetInt( "UpdateEventsEveryNFrames", m_update_events); 1099 Normalized55FPS = startupConfig.GetBoolean( "Normalized55FPS", Normalized55FPS);
949 m_update_objects = startupConfig.GetInt( "UpdateObjectsEveryNFrames", m_update_objects); 1100
950 m_update_physics = startupConfig.GetInt( "UpdatePhysicsEveryNFrames", m_update_physics); 1101 m_update_backup = startupConfig.GetInt("UpdateStorageEveryNFrames", m_update_backup);
951 m_update_presences = startupConfig.GetInt( "UpdateAgentsEveryNFrames", m_update_presences); 1102 m_update_coarse_locations = startupConfig.GetInt("UpdateCoarseLocationsEveryNFrames", m_update_coarse_locations);
952 m_update_terrain = startupConfig.GetInt( "UpdateTerrainEveryNFrames", m_update_terrain); 1103 m_update_entitymovement = startupConfig.GetInt("UpdateEntityMovementEveryNFrames", m_update_entitymovement);
953 m_update_temp_cleaning = startupConfig.GetInt( "UpdateTempCleaningEveryNFrames", m_update_temp_cleaning); 1104 m_update_events = startupConfig.GetInt("UpdateEventsEveryNFrames", m_update_events);
1105 m_update_objects = startupConfig.GetInt("UpdateObjectsEveryNFrames", m_update_objects);
1106 m_update_physics = startupConfig.GetInt("UpdatePhysicsEveryNFrames", m_update_physics);
1107 m_update_presences = startupConfig.GetInt("UpdateAgentsEveryNFrames", m_update_presences);
1108 m_update_terrain = startupConfig.GetInt("UpdateTerrainEveryNFrames", m_update_terrain);
1109 m_update_temp_cleaning = startupConfig.GetInt("UpdateTempCleaningEveryNSeconds", m_update_temp_cleaning);
1110
1111 if (startupConfig.Contains("ShouldUseFireAndForgetForCollisions"))
1112 {
1113 ShouldUseFireAndForgetForCollisions = startupConfig.GetBoolean("ShouldUseFireAndForgetForCollisions", false);
1114 }
954 } 1115 }
955 1116
1117
956 // FIXME: Ultimately this should be in a module. 1118 // FIXME: Ultimately this should be in a module.
957 SendPeriodicAppearanceUpdates = true; 1119 SendPeriodicAppearanceUpdates = false;
958 1120
959 IConfig appearanceConfig = m_config.Configs["Appearance"]; 1121 IConfig appearanceConfig = m_config.Configs["Appearance"];
960 if (appearanceConfig != null) 1122 if (appearanceConfig != null)
961 { 1123 {
@@ -965,6 +1127,12 @@ namespace OpenSim.Region.Framework.Scenes
965 1127
966 #endregion Region Config 1128 #endregion Region Config
967 1129
1130 IConfig entityTransferConfig = m_config.Configs["EntityTransfer"];
1131 if (entityTransferConfig != null)
1132 {
1133 AllowAvatarCrossing = entityTransferConfig.GetBoolean("AllowAvatarCrossing", AllowAvatarCrossing);
1134 }
1135
968 #region Interest Management 1136 #region Interest Management
969 1137
970 IConfig interestConfig = m_config.Configs["InterestManagement"]; 1138 IConfig interestConfig = m_config.Configs["InterestManagement"];
@@ -974,59 +1142,109 @@ namespace OpenSim.Region.Framework.Scenes
974 1142
975 try 1143 try
976 { 1144 {
977 m_priorityScheme = (UpdatePrioritizationSchemes)Enum.Parse(typeof(UpdatePrioritizationSchemes), update_prioritization_scheme, true); 1145 UpdatePrioritizationScheme = (UpdatePrioritizationSchemes)Enum.Parse(typeof(UpdatePrioritizationSchemes), update_prioritization_scheme, true);
978 } 1146 }
979 catch (Exception) 1147 catch (Exception)
980 { 1148 {
981 m_log.Warn("[PRIORITIZER]: UpdatePrioritizationScheme was not recognized, setting to default prioritizer Time"); 1149 m_log.Warn("[PRIORITIZER]: UpdatePrioritizationScheme was not recognized, setting to default prioritizer Time");
982 m_priorityScheme = UpdatePrioritizationSchemes.Time; 1150 UpdatePrioritizationScheme = UpdatePrioritizationSchemes.Time;
983 } 1151 }
984 1152
985 m_reprioritizationEnabled = interestConfig.GetBoolean("ReprioritizationEnabled", true); 1153 IsReprioritizationEnabled
986 m_reprioritizationInterval = interestConfig.GetDouble("ReprioritizationInterval", 5000.0); 1154 = interestConfig.GetBoolean("ReprioritizationEnabled", IsReprioritizationEnabled);
987 m_rootReprioritizationDistance = interestConfig.GetDouble("RootReprioritizationDistance", 10.0); 1155 ReprioritizationInterval
988 m_childReprioritizationDistance = interestConfig.GetDouble("ChildReprioritizationDistance", 20.0); 1156 = interestConfig.GetDouble("ReprioritizationInterval", ReprioritizationInterval);
1157 RootReprioritizationDistance
1158 = interestConfig.GetDouble("RootReprioritizationDistance", RootReprioritizationDistance);
1159 ChildReprioritizationDistance
1160 = interestConfig.GetDouble("ChildReprioritizationDistance", ChildReprioritizationDistance);
1161
1162 RootTerseUpdatePeriod = interestConfig.GetInt("RootTerseUpdatePeriod", RootTerseUpdatePeriod);
1163 ChildTerseUpdatePeriod = interestConfig.GetInt("ChildTerseUpdatePeriod", ChildTerseUpdatePeriod);
1164
1165 RootPositionUpdateTolerance
1166 = interestConfig.GetFloat("RootPositionUpdateTolerance", RootPositionUpdateTolerance);
1167 RootRotationUpdateTolerance
1168 = interestConfig.GetFloat("RootRotationUpdateTolerance", RootRotationUpdateTolerance);
1169 RootVelocityUpdateTolerance
1170 = interestConfig.GetFloat("RootVelocityUpdateTolerance", RootVelocityUpdateTolerance);
989 } 1171 }
990 1172
991 m_log.DebugFormat("[SCENE]: Using the {0} prioritization scheme", m_priorityScheme); 1173 m_log.DebugFormat("[SCENE]: Using the {0} prioritization scheme", UpdatePrioritizationScheme);
992 1174
993 #endregion Interest Management 1175 #endregion Interest Management
994 1176
995 StatsReporter = new SimStatsReporter(this); 1177 // The timer used by the Stopwatch class depends on the system hardware and operating system; inform
1178 // if the timer is based on a high-resolution performance counter or based on the system timer;
1179 // the performance counter will provide a more precise time than the system timer
1180 if (Stopwatch.IsHighResolution)
1181 m_log.InfoFormat("[SCENE]: Using high-resolution performance counter for statistics.");
1182 else
1183 m_log.InfoFormat("[SCENE]: Using system timer for statistics.");
1184
1185 // Acquire the statistics section of the OpenSim.ini file located
1186 // in the bin directory
1187 IConfig statisticsConfig = m_config.Configs["Statistics"];
1188
1189 // Confirm that the statistics section existed in the configuration
1190 // file
1191 if (statisticsConfig != null)
1192 {
1193 // Create the StatsReporter using the number of frames to store
1194 // for the frame time statistics, or 10 frames if the config
1195 // file doesn't contain a value
1196 StatsReporter = new SimStatsReporter(this,
1197 statisticsConfig.GetInt("NumberOfFrames",
1198 m_defaultNumberFramesStored));
1199 }
1200 else
1201 {
1202 // Create a StatsReporter with the current scene and a default
1203 // 10 frames stored for the frame time statistics
1204 StatsReporter = new SimStatsReporter(this);
1205 }
1206
996 StatsReporter.OnSendStatsResult += SendSimStatsPackets; 1207 StatsReporter.OnSendStatsResult += SendSimStatsPackets;
997 StatsReporter.OnStatsIncorrect += m_sceneGraph.RecalculateStats; 1208 StatsReporter.OnStatsIncorrect += m_sceneGraph.RecalculateStats;
1209
998 } 1210 }
999 1211
1000 public Scene(RegionInfo regInfo) : base(regInfo) 1212 public Scene(RegionInfo regInfo)
1213 : base(regInfo)
1001 { 1214 {
1215 m_sceneGraph = new SceneGraph(this);
1216
1217 // If the scene graph has an Unrecoverable error, restart this sim.
1218 // Currently the only thing that causes it to happen is two kinds of specific
1219 // Physics based crashes.
1220 //
1221 // Out of memory
1222 // Operating system has killed the plugin
1223 m_sceneGraph.UnRecoverableError
1224 += () =>
1225 {
1226 m_log.ErrorFormat("[SCENE]: Restarting region {0} due to unrecoverable physics crash", Name);
1227 RestartNow();
1228 };
1229
1002 PhysicalPrims = true; 1230 PhysicalPrims = true;
1003 CollidablePrims = true; 1231 CollidablePrims = true;
1004 PhysicsEnabled = true; 1232 PhysicsEnabled = true;
1005 1233
1234 AllowAvatarCrossing = true;
1235
1006 PeriodicBackup = true; 1236 PeriodicBackup = true;
1007 UseBackup = true; 1237 UseBackup = true;
1008 1238
1009 BordersLocked = true; 1239 IsReprioritizationEnabled = true;
1010 Border northBorder = new Border(); 1240 UpdatePrioritizationScheme = UpdatePrioritizationSchemes.Time;
1011 northBorder.BorderLine = new Vector3(float.MinValue, float.MaxValue, (int)Constants.RegionSize); //<--- 1241 ReprioritizationInterval = 5000;
1012 northBorder.CrossDirection = Cardinals.N;
1013 NorthBorders.Add(northBorder);
1014
1015 Border southBorder = new Border();
1016 southBorder.BorderLine = new Vector3(float.MinValue, float.MaxValue,0); //--->
1017 southBorder.CrossDirection = Cardinals.S;
1018 SouthBorders.Add(southBorder);
1019 1242
1020 Border eastBorder = new Border(); 1243 RootRotationUpdateTolerance = 0.1f;
1021 eastBorder.BorderLine = new Vector3(float.MinValue, float.MaxValue, (int)Constants.RegionSize); //<--- 1244 RootVelocityUpdateTolerance = 0.001f;
1022 eastBorder.CrossDirection = Cardinals.E; 1245 RootPositionUpdateTolerance = 0.05f;
1023 EastBorders.Add(eastBorder); 1246 RootReprioritizationDistance = 10.0;
1024 1247 ChildReprioritizationDistance = 20.0;
1025 Border westBorder = new Border();
1026 westBorder.BorderLine = new Vector3(float.MinValue, float.MaxValue,0); //--->
1027 westBorder.CrossDirection = Cardinals.W;
1028 WestBorders.Add(westBorder);
1029 BordersLocked = false;
1030 1248
1031 m_eventManager = new EventManager(); 1249 m_eventManager = new EventManager();
1032 1250
@@ -1046,13 +1264,44 @@ namespace OpenSim.Region.Framework.Scenes
1046 get { return m_sceneGraph; } 1264 get { return m_sceneGraph; }
1047 } 1265 }
1048 1266
1049 protected virtual void RegisterDefaultSceneEvents() 1267 /// <summary>
1268 /// Called by the module loader when all modules are loaded, after each module's
1269 /// RegionLoaded hook is called. This is the earliest time where RequestModuleInterface
1270 /// may be used.
1271 /// </summary>
1272 public void AllModulesLoaded()
1050 { 1273 {
1051 IDialogModule dm = RequestModuleInterface<IDialogModule>(); 1274 IDialogModule dm = RequestModuleInterface<IDialogModule>();
1052 1275
1053 if (dm != null) 1276 if (dm != null)
1054 m_eventManager.OnPermissionError += dm.SendAlertToUser; 1277 m_eventManager.OnPermissionError += dm.SendAlertToUser;
1055 1278
1279 ISimulatorFeaturesModule fm = RequestModuleInterface<ISimulatorFeaturesModule>();
1280 if (fm != null)
1281 {
1282 OSD openSimExtras;
1283 OSDMap openSimExtrasMap;
1284
1285 if (!fm.TryGetFeature("OpenSimExtras", out openSimExtras))
1286 openSimExtras = new OSDMap();
1287
1288 float FrameTime = MinFrameTicks / 1000.0f;
1289 float statisticsFPSfactor = 1.0f;
1290 if(Normalized55FPS)
1291 statisticsFPSfactor = 55.0f * FrameTime;
1292
1293 openSimExtrasMap = (OSDMap)openSimExtras;
1294 openSimExtrasMap["SimulatorFPS"] = OSD.FromReal(1.0f / FrameTime);
1295 openSimExtrasMap["SimulatorFPSFactor"] = OSD.FromReal(statisticsFPSfactor);
1296 openSimExtrasMap["SimulatorFPSWarnPercent"] = OSD.FromInteger(FrameTimeWarnPercent);
1297 openSimExtrasMap["SimulatorFPSCritPercent"] = OSD.FromInteger(FrameTimeCritPercent);
1298
1299 fm.AddFeature("OpenSimExtras", openSimExtrasMap);
1300 }
1301 }
1302
1303 protected virtual void RegisterDefaultSceneEvents()
1304 {
1056 m_eventManager.OnSignificantClientMovement += HandleOnSignificantClientMovement; 1305 m_eventManager.OnSignificantClientMovement += HandleOnSignificantClientMovement;
1057 } 1306 }
1058 1307
@@ -1074,17 +1323,22 @@ namespace OpenSim.Region.Framework.Scenes
1074 /// <returns>True after all operations complete, throws exceptions otherwise.</returns> 1323 /// <returns>True after all operations complete, throws exceptions otherwise.</returns>
1075 public override void OtherRegionUp(GridRegion otherRegion) 1324 public override void OtherRegionUp(GridRegion otherRegion)
1076 { 1325 {
1077 uint xcell = (uint)((int)otherRegion.RegionLocX / (int)Constants.RegionSize);
1078 uint ycell = (uint)((int)otherRegion.RegionLocY / (int)Constants.RegionSize);
1079 //m_log.InfoFormat("[SCENE]: (on region {0}): Region {1} up in coords {2}-{3}",
1080 // RegionInfo.RegionName, otherRegion.RegionName, xcell, ycell);
1081
1082 if (RegionInfo.RegionHandle != otherRegion.RegionHandle) 1326 if (RegionInfo.RegionHandle != otherRegion.RegionHandle)
1083 { 1327 {
1084 // If these are cast to INT because long + negative values + abs returns invalid data 1328 //// If these are cast to INT because long + negative values + abs returns invalid data
1085 int resultX = Math.Abs((int)xcell - (int)RegionInfo.RegionLocX); 1329 //int resultX = Math.Abs((int)xcell - (int)RegionInfo.RegionLocX);
1086 int resultY = Math.Abs((int)ycell - (int)RegionInfo.RegionLocY); 1330 //int resultY = Math.Abs((int)ycell - (int)RegionInfo.RegionLocY);
1087 if (resultX <= 1 && resultY <= 1) 1331 //if (resultX <= 1 && resultY <= 1)
1332 float dist = (float)Math.Max(DefaultDrawDistance,
1333 (float)Math.Max(RegionInfo.RegionSizeX, RegionInfo.RegionSizeY));
1334 uint newRegionX, newRegionY, thisRegionX, thisRegionY;
1335 Util.RegionHandleToRegionLoc(otherRegion.RegionHandle, out newRegionX, out newRegionY);
1336 Util.RegionHandleToRegionLoc(RegionInfo.RegionHandle, out thisRegionX, out thisRegionY);
1337
1338 //m_log.InfoFormat("[SCENE]: (on region {0}): Region {1} up in coords {2}-{3}",
1339 // RegionInfo.RegionName, otherRegion.RegionName, newRegionX, newRegionY);
1340
1341 if (!Util.IsOutsideView(dist, thisRegionX, newRegionX, thisRegionY, newRegionY))
1088 { 1342 {
1089 // Let the grid service module know, so this can be cached 1343 // Let the grid service module know, so this can be cached
1090 m_eventManager.TriggerOnRegionUp(otherRegion); 1344 m_eventManager.TriggerOnRegionUp(otherRegion);
@@ -1147,46 +1401,6 @@ namespace OpenSim.Region.Framework.Scenes
1147 return found; 1401 return found;
1148 } 1402 }
1149 1403
1150 /// <summary>
1151 /// Checks whether this region has a neighbour in the given direction.
1152 /// </summary>
1153 /// <param name="car"></param>
1154 /// <param name="fix"></param>
1155 /// <returns>
1156 /// An integer which represents a compass point. N == 1, going clockwise until we reach NW == 8.
1157 /// Returns a positive integer if there is a region in that direction, a negative integer if not.
1158 /// </returns>
1159 public int HaveNeighbor(Cardinals car, ref int[] fix)
1160 {
1161 uint neighbourx = RegionInfo.RegionLocX;
1162 uint neighboury = RegionInfo.RegionLocY;
1163
1164 int dir = (int)car;
1165
1166 if (dir > 1 && dir < 5) //Heading East
1167 neighbourx++;
1168 else if (dir > 5) // Heading West
1169 neighbourx--;
1170
1171 if (dir < 3 || dir == 8) // Heading North
1172 neighboury++;
1173 else if (dir > 3 && dir < 7) // Heading Sout
1174 neighboury--;
1175
1176 int x = (int)(neighbourx * Constants.RegionSize);
1177 int y = (int)(neighboury * Constants.RegionSize);
1178 GridRegion neighbourRegion = GridService.GetRegionByPosition(RegionInfo.ScopeID, x, y);
1179
1180 if (neighbourRegion == null)
1181 {
1182 fix[0] = (int)(RegionInfo.RegionLocX - neighbourx);
1183 fix[1] = (int)(RegionInfo.RegionLocY - neighboury);
1184 return dir * (-1);
1185 }
1186 else
1187 return dir;
1188 }
1189
1190 // Alias IncomingHelloNeighbour OtherRegionUp, for now 1404 // Alias IncomingHelloNeighbour OtherRegionUp, for now
1191 public GridRegion IncomingHelloNeighbour(RegionInfo neighbour) 1405 public GridRegion IncomingHelloNeighbour(RegionInfo neighbour)
1192 { 1406 {
@@ -1270,14 +1484,14 @@ namespace OpenSim.Region.Framework.Scenes
1270 1484
1271 // Kick all ROOT agents with the message, 'The simulator is going down' 1485 // Kick all ROOT agents with the message, 'The simulator is going down'
1272 ForEachScenePresence(delegate(ScenePresence avatar) 1486 ForEachScenePresence(delegate(ScenePresence avatar)
1273 { 1487 {
1274 avatar.RemoveNeighbourRegion(RegionInfo.RegionHandle); 1488 avatar.RemoveNeighbourRegion(RegionInfo.RegionHandle);
1275 1489
1276 if (!avatar.IsChildAgent) 1490 if (!avatar.IsChildAgent)
1277 avatar.ControllingClient.Kick("The simulator is going down."); 1491 avatar.ControllingClient.Kick("The simulator is going down.");
1278 1492
1279 avatar.ControllingClient.SendShutdownConnectionNotice(); 1493 avatar.ControllingClient.SendShutdownConnectionNotice();
1280 }); 1494 });
1281 1495
1282 // Stop updating the scene objects and agents. 1496 // Stop updating the scene objects and agents.
1283 m_shuttingDown = true; 1497 m_shuttingDown = true;
@@ -1288,20 +1502,11 @@ namespace OpenSim.Region.Framework.Scenes
1288 Thread.Sleep(500); 1502 Thread.Sleep(500);
1289 1503
1290 // Stop all client threads. 1504 // Stop all client threads.
1291 ForEachScenePresence(delegate(ScenePresence avatar) { avatar.ControllingClient.Close(); }); 1505 ForEachScenePresence(delegate(ScenePresence avatar) { CloseAgent(avatar.UUID, false); });
1292 1506
1293 m_log.Debug("[SCENE]: Persisting changed objects"); 1507 m_log.Debug("[SCENE]: Persisting changed objects");
1294 EventManager.TriggerSceneShuttingDown(this); 1508 EventManager.TriggerSceneShuttingDown(this);
1295 1509 Backup(false);
1296 EntityBase[] entities = GetEntities();
1297 foreach (EntityBase entity in entities)
1298 {
1299 if (!entity.IsDeleted && entity is SceneObjectGroup && ((SceneObjectGroup)entity).HasGroupChanged)
1300 {
1301 ((SceneObjectGroup)entity).ProcessBackup(SimulationDataService, false);
1302 }
1303 }
1304
1305 m_sceneGraph.Close(); 1510 m_sceneGraph.Close();
1306 1511
1307 if (!GridService.DeregisterRegion(RegionInfo.RegionID)) 1512 if (!GridService.DeregisterRegion(RegionInfo.RegionID))
@@ -1322,28 +1527,38 @@ namespace OpenSim.Region.Framework.Scenes
1322 } 1527 }
1323 } 1528 }
1324 1529
1530 public override void Start()
1531 {
1532 Start(true);
1533 }
1534
1325 /// <summary> 1535 /// <summary>
1326 /// Start the scene 1536 /// Start the scene
1327 /// </summary> 1537 /// </summary>
1328 public void Start() 1538 /// <param name='startScripts'>
1539 /// Start the scripts within the scene.
1540 /// </param>
1541 public void Start(bool startScripts)
1329 { 1542 {
1543 if (IsRunning)
1544 return;
1545
1546 m_isRunning = true;
1330 m_active = true; 1547 m_active = true;
1331 1548
1549 m_unixStartTime = Util.UnixTimeSinceEpoch();
1332// m_log.DebugFormat("[SCENE]: Starting Heartbeat timer for {0}", RegionInfo.RegionName); 1550// m_log.DebugFormat("[SCENE]: Starting Heartbeat timer for {0}", RegionInfo.RegionName);
1333
1334 //m_heartbeatTimer.Enabled = true;
1335 //m_heartbeatTimer.Interval = (int)(m_timespan * 1000);
1336 //m_heartbeatTimer.Elapsed += new ElapsedEventHandler(Heartbeat);
1337 if (m_heartbeatThread != null) 1551 if (m_heartbeatThread != null)
1338 { 1552 {
1339 m_heartbeatThread.Abort(); 1553 m_heartbeatThread.Abort();
1340 m_heartbeatThread = null; 1554 m_heartbeatThread = null;
1341 } 1555 }
1342// m_lastUpdate = Util.EnvironmentTickCount();
1343 1556
1344 m_heartbeatThread 1557 m_heartbeatThread
1345 = Watchdog.StartThread( 1558 = WorkManager.StartThread(
1346 Heartbeat, string.Format("Heartbeat ({0})", RegionInfo.RegionName), ThreadPriority.Normal, false, false); 1559 Heartbeat, string.Format("Heartbeat-({0})", RegionInfo.RegionName.Replace(" ", "_")), ThreadPriority.Normal, false, false);
1560
1561 StartScripts();
1347 } 1562 }
1348 1563
1349 /// <summary> 1564 /// <summary>
@@ -1374,15 +1589,6 @@ namespace OpenSim.Region.Framework.Scenes
1374 /// </summary> 1589 /// </summary>
1375 private void Heartbeat() 1590 private void Heartbeat()
1376 { 1591 {
1377// if (!Monitor.TryEnter(m_heartbeatLock))
1378// {
1379// Watchdog.RemoveThread();
1380// return;
1381// }
1382
1383// try
1384// {
1385
1386 m_eventManager.TriggerOnRegionStarted(this); 1592 m_eventManager.TriggerOnRegionStarted(this);
1387 1593
1388 // The first frame can take a very long time due to physics actors being added on startup. Therefore, 1594 // 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
1390 // alarms for scenes with many objects. 1596 // alarms for scenes with many objects.
1391 Update(1); 1597 Update(1);
1392 1598
1393 Watchdog.StartThread( 1599 WorkManager.StartThread(
1394 Maintenance, string.Format("Maintenance ({0})", RegionInfo.RegionName), ThreadPriority.Normal, false, true); 1600 Maintenance, string.Format("Maintenance ({0})", RegionInfo.RegionName), ThreadPriority.Normal, false, true);
1395 1601
1396 Watchdog.GetCurrentThreadInfo().AlarmIfTimeout = true; 1602 Watchdog.GetCurrentThreadInfo().AlarmIfTimeout = true;
1397 Update(-1); 1603 m_lastFrameTick = Util.EnvironmentTickCount();
1398 1604
1399// m_lastUpdate = Util.EnvironmentTickCount(); 1605 if (UpdateOnTimer)
1400// m_firstHeartbeat = false; 1606 {
1401// } 1607 m_sceneUpdateTimer = new Timer(MinFrameTicks);
1402// finally 1608 m_sceneUpdateTimer.AutoReset = true;
1403// { 1609 m_sceneUpdateTimer.Elapsed += Update;
1404// Monitor.Pulse(m_heartbeatLock); 1610 m_sceneUpdateTimer.Start();
1405// Monitor.Exit(m_heartbeatLock); 1611 }
1406// } 1612 else
1613 {
1614 Thread.CurrentThread.Priority = ThreadPriority.Highest;
1615 Update(-1);
1616 Watchdog.RemoveThread();
1617 m_isRunning = false;
1618 }
1619 }
1407 1620
1408 Watchdog.RemoveThread(); 1621 private volatile bool m_isTimerUpdateRunning;
1622
1623 private void Update(object sender, ElapsedEventArgs e)
1624 {
1625 if (m_isTimerUpdateRunning)
1626 return;
1627
1628 m_isTimerUpdateRunning = true;
1629
1630 // If the last frame did not complete on time, then immediately start the next update on the same thread
1631 // and ignore further timed updates until we have a frame that had spare time.
1632 while (!Update(1) && Active) { }
1633
1634 if (!Active || m_shuttingDown)
1635 {
1636 m_sceneUpdateTimer.Stop();
1637 m_sceneUpdateTimer = null;
1638 m_isRunning = false;
1639 }
1640
1641 m_isTimerUpdateRunning = false;
1409 } 1642 }
1410 1643
1411 private void Maintenance() 1644 private void Maintenance()
@@ -1418,7 +1651,7 @@ namespace OpenSim.Region.Framework.Scenes
1418 public void DoMaintenance(int runs) 1651 public void DoMaintenance(int runs)
1419 { 1652 {
1420 long? endRun = null; 1653 long? endRun = null;
1421 int runtc; 1654 int runtc, tmpMS;
1422 int previousMaintenanceTick; 1655 int previousMaintenanceTick;
1423 1656
1424 if (runs >= 0) 1657 if (runs >= 0)
@@ -1432,6 +1665,8 @@ namespace OpenSim.Region.Framework.Scenes
1432 runtc = Util.EnvironmentTickCount(); 1665 runtc = Util.EnvironmentTickCount();
1433 ++MaintenanceRun; 1666 ++MaintenanceRun;
1434 1667
1668 // m_log.DebugFormat("[SCENE]: Maintenance run {0} in {1}", MaintenanceRun, Name);
1669
1435 // Coarse locations relate to positions of green dots on the mini-map (on a SecondLife client) 1670 // Coarse locations relate to positions of green dots on the mini-map (on a SecondLife client)
1436 if (MaintenanceRun % (m_update_coarse_locations / 10) == 0) 1671 if (MaintenanceRun % (m_update_coarse_locations / 10) == 0)
1437 { 1672 {
@@ -1445,7 +1680,7 @@ namespace OpenSim.Region.Framework.Scenes
1445 1680
1446 if (SendPeriodicAppearanceUpdates && MaintenanceRun % 60 == 0) 1681 if (SendPeriodicAppearanceUpdates && MaintenanceRun % 60 == 0)
1447 { 1682 {
1448// m_log.DebugFormat("[SCENE]: Sending periodic appearance updates"); 1683 // m_log.DebugFormat("[SCENE]: Sending periodic appearance updates");
1449 1684
1450 if (AvatarFactory != null) 1685 if (AvatarFactory != null)
1451 { 1686 {
@@ -1453,29 +1688,44 @@ namespace OpenSim.Region.Framework.Scenes
1453 } 1688 }
1454 } 1689 }
1455 1690
1691 // Delete temp-on-rez stuff
1692 if (MaintenanceRun % m_update_temp_cleaning == 0 && !m_cleaningTemps)
1693 {
1694 // m_log.DebugFormat("[SCENE]: Running temp-on-rez cleaning in {0}", Name);
1695 tmpMS = Util.EnvironmentTickCount();
1696 m_cleaningTemps = true;
1697
1698 WorkManager.RunInThread(
1699 delegate { CleanTempObjects(); m_cleaningTemps = false; },
1700 null,
1701 string.Format("CleanTempObjects ({0})", Name));
1702
1703 tempOnRezMS = Util.EnvironmentTickCountSubtract(tmpMS);
1704 }
1705
1456 Watchdog.UpdateThread(); 1706 Watchdog.UpdateThread();
1457 1707
1458 previousMaintenanceTick = m_lastMaintenanceTick; 1708 previousMaintenanceTick = m_lastMaintenanceTick;
1459 m_lastMaintenanceTick = Util.EnvironmentTickCount(); 1709 m_lastMaintenanceTick = Util.EnvironmentTickCount();
1460 runtc = Util.EnvironmentTickCountSubtract(m_lastMaintenanceTick, runtc); 1710 runtc = Util.EnvironmentTickCountSubtract(m_lastMaintenanceTick, runtc);
1461 runtc = (int)(MinMaintenanceTime * 1000) - runtc; 1711 runtc = MinMaintenanceTicks - runtc;
1462 1712
1463 if (runtc > 0) 1713 if (runtc > 0)
1464 Thread.Sleep(runtc); 1714 m_maintenanceWaitEvent.WaitOne(runtc);
1465 1715
1466 // Optionally warn if a frame takes double the amount of time that it should. 1716 // Optionally warn if a frame takes double the amount of time that it should.
1467 if (DebugUpdates 1717 if (DebugUpdates
1468 && Util.EnvironmentTickCountSubtract( 1718 && Util.EnvironmentTickCountSubtract(
1469 m_lastMaintenanceTick, previousMaintenanceTick) > (int)(MinMaintenanceTime * 1000 * 2)) 1719 m_lastMaintenanceTick, previousMaintenanceTick) > MinMaintenanceTicks * 2)
1470 m_log.WarnFormat( 1720 m_log.WarnFormat(
1471 "[SCENE]: Maintenance took {0} ms (desired max {1} ms) in {2}", 1721 "[SCENE]: Maintenance took {0} ms (desired max {1} ms) in {2}",
1472 Util.EnvironmentTickCountSubtract(m_lastMaintenanceTick, previousMaintenanceTick), 1722 Util.EnvironmentTickCountSubtract(m_lastMaintenanceTick, previousMaintenanceTick),
1473 MinMaintenanceTime * 1000, 1723 MinMaintenanceTicks,
1474 RegionInfo.RegionName); 1724 RegionInfo.RegionName);
1475 } 1725 }
1476 } 1726 }
1477 1727
1478 public override void Update(int frames) 1728 public override bool Update(int frames)
1479 { 1729 {
1480 long? endFrame = null; 1730 long? endFrame = null;
1481 1731
@@ -1484,101 +1734,159 @@ namespace OpenSim.Region.Framework.Scenes
1484 1734
1485 float physicsFPS = 0f; 1735 float physicsFPS = 0f;
1486 int previousFrameTick, tmpMS; 1736 int previousFrameTick, tmpMS;
1487 int maintc = Util.EnvironmentTickCount(); 1737
1738 // These variables will be used to save the precise frame time using the
1739 // Stopwatch class of Microsoft SDK; the times are recorded at the start
1740 // and end of a particular section of code, and then used to calculate
1741 // the frame times, which are the sums of the sections for each given name
1742 double preciseTotalFrameTime = 0.0;
1743 double preciseSimFrameTime = 0.0;
1744 double precisePhysicsFrameTime = 0.0;
1745 Stopwatch totalFrameStopwatch = new Stopwatch();
1746 Stopwatch simFrameStopwatch = new Stopwatch();
1747 Stopwatch physicsFrameStopwatch = new Stopwatch();
1748
1749 // Begin the stopwatch to keep track of the time that the frame
1750 // started running to determine how long the frame took to complete
1751 totalFrameStopwatch.Start();
1488 1752
1489 while (!m_shuttingDown && ((endFrame == null && Active) || Frame < endFrame)) 1753 while (!m_shuttingDown && ((endFrame == null && Active) || Frame < endFrame))
1490 { 1754 {
1491 ++Frame; 1755 ++Frame;
1492 1756
1493// m_log.DebugFormat("[SCENE]: Processing frame {0} in {1}", Frame, RegionInfo.RegionName); 1757 // m_log.DebugFormat("[SCENE]: Processing frame {0} in {1}", Frame, RegionInfo.RegionName);
1494 1758
1495 agentMS = tempOnRezMS = eventMS = backupMS = terrainMS = landMS = spareMS = 0; 1759 agentMS = eventMS = backupMS = terrainMS = landMS = spareMS = 0;
1496 1760
1497 try 1761 try
1498 { 1762 {
1763 EventManager.TriggerRegionHeartbeatStart(this);
1764
1499 // Apply taints in terrain module to terrain in physics scene 1765 // Apply taints in terrain module to terrain in physics scene
1500 if (Frame % m_update_terrain == 0) 1766 if (Frame % m_update_terrain == 0)
1501 { 1767 {
1768 // At several points inside the code there was a need to
1769 // create a more precise measurement of time elapsed.
1770 // This led to the addition of variables that have a
1771 // similar function and thus remain tightly connected to
1772 // their original counterparts. However, the original
1773 // code is not receiving comments from our group because
1774 // we don't feel right modifying the code to that degree
1775 // at this point in time, the precise values all begin
1776 // with the keyword precise
1502 tmpMS = Util.EnvironmentTickCount(); 1777 tmpMS = Util.EnvironmentTickCount();
1778 simFrameStopwatch.Start();
1503 UpdateTerrain(); 1779 UpdateTerrain();
1780
1781 // Get the simulation frame time that the avatar force
1782 // input took
1783 simFrameStopwatch.Stop();
1784 preciseSimFrameTime =
1785 simFrameStopwatch.Elapsed.TotalMilliseconds;
1504 terrainMS = Util.EnvironmentTickCountSubtract(tmpMS); 1786 terrainMS = Util.EnvironmentTickCountSubtract(tmpMS);
1505 } 1787 }
1506 1788
1789 // At several points inside the code there was a need to
1790 // create a more precise measurement of time elapsed. This
1791 // led to the addition of variables that have a similar
1792 // function and thus remain tightly connected to their
1793 // original counterparts. However, the original code is
1794 // not receiving comments from our group because we don't
1795 // feel right modifying the code to that degree at this
1796 // point in time, the precise values all begin with the
1797 // keyword precise
1798
1507 tmpMS = Util.EnvironmentTickCount(); 1799 tmpMS = Util.EnvironmentTickCount();
1800
1801 // Begin the stopwatch to track the time to prepare physics
1802 physicsFrameStopwatch.Start();
1508 if (PhysicsEnabled && Frame % m_update_physics == 0) 1803 if (PhysicsEnabled && Frame % m_update_physics == 0)
1509 m_sceneGraph.UpdatePreparePhysics(); 1804 m_sceneGraph.UpdatePreparePhysics();
1805
1806 // Get the time it took to prepare the physics, this
1807 // would report the most precise time that physics was
1808 // running on the machine and should the physics not be
1809 // enabled will report the time it took to check if physics
1810 // was enabled
1811 physicsFrameStopwatch.Stop();
1812 precisePhysicsFrameTime = physicsFrameStopwatch.Elapsed.TotalMilliseconds;
1510 physicsMS2 = Util.EnvironmentTickCountSubtract(tmpMS); 1813 physicsMS2 = Util.EnvironmentTickCountSubtract(tmpMS);
1511 1814
1512 // Apply any pending avatar force input to the avatar's velocity 1815 // Apply any pending avatar force input to the avatar's velocity
1513 tmpMS = Util.EnvironmentTickCount(); 1816 tmpMS = Util.EnvironmentTickCount();
1817 simFrameStopwatch.Restart();
1514 if (Frame % m_update_entitymovement == 0) 1818 if (Frame % m_update_entitymovement == 0)
1515 m_sceneGraph.UpdateScenePresenceMovement(); 1819 m_sceneGraph.UpdateScenePresenceMovement();
1820
1821 // Get the simulation frame time that the avatar force input
1822 // took
1823 simFrameStopwatch.Stop();
1824 preciseSimFrameTime +=
1825 simFrameStopwatch.Elapsed.TotalMilliseconds;
1516 agentMS = Util.EnvironmentTickCountSubtract(tmpMS); 1826 agentMS = Util.EnvironmentTickCountSubtract(tmpMS);
1517 1827
1518 // Perform the main physics update. This will do the actual work of moving objects and avatars according to their 1828 // Perform the main physics update. This will do the actual work of moving objects and avatars according to their
1519 // velocity 1829 // velocity
1520 tmpMS = Util.EnvironmentTickCount(); 1830 tmpMS = Util.EnvironmentTickCount();
1831 physicsFrameStopwatch.Restart();
1521 if (Frame % m_update_physics == 0) 1832 if (Frame % m_update_physics == 0)
1522 { 1833 {
1523 if (PhysicsEnabled) 1834 if (PhysicsEnabled)
1524 physicsFPS = m_sceneGraph.UpdatePhysics(MinFrameTime); 1835 physicsFPS = m_sceneGraph.UpdatePhysics(MinFrameSeconds);
1525 1836
1526 if (SynchronizeScene != null) 1837 if (SynchronizeScene != null)
1527 SynchronizeScene(this); 1838 SynchronizeScene(this);
1528 } 1839 }
1840
1841 // Add the main physics update time to the prepare physics time
1842 physicsFrameStopwatch.Stop();
1843 precisePhysicsFrameTime += physicsFrameStopwatch.Elapsed.TotalMilliseconds;
1529 physicsMS = Util.EnvironmentTickCountSubtract(tmpMS); 1844 physicsMS = Util.EnvironmentTickCountSubtract(tmpMS);
1530 1845
1846 // Start the stopwatch for the remainder of the simulation
1847 simFrameStopwatch.Restart();
1531 tmpMS = Util.EnvironmentTickCount(); 1848 tmpMS = Util.EnvironmentTickCount();
1532 1849
1533 // Check if any objects have reached their targets 1850 // Check if any objects have reached their targets
1534 CheckAtTargets(); 1851 CheckAtTargets();
1535 1852
1536 // Update SceneObjectGroups that have scheduled themselves for updates 1853 // Update SceneObjectGroups that have scheduled themselves for updates
1537 // Objects queue their updates onto all scene presences 1854 // Objects queue their updates onto all scene presences
1538 if (Frame % m_update_objects == 0) 1855 if (Frame % m_update_objects == 0)
1539 m_sceneGraph.UpdateObjectGroups(); 1856 m_sceneGraph.UpdateObjectGroups();
1540 1857
1541 // Run through all ScenePresences looking for updates 1858 // Run through all ScenePresences looking for updates
1542 // Presence updates and queued object updates for each presence are sent to clients 1859 // Presence updates and queued object updates for each presence are sent to clients
1543 if (Frame % m_update_presences == 0) 1860 if (Frame % m_update_presences == 0)
1544 m_sceneGraph.UpdatePresences(); 1861 m_sceneGraph.UpdatePresences();
1545 1862
1546 agentMS += Util.EnvironmentTickCountSubtract(tmpMS); 1863 agentMS += Util.EnvironmentTickCountSubtract(tmpMS);
1547 1864
1548 // Delete temp-on-rez stuff
1549 if (Frame % m_update_temp_cleaning == 0 && !m_cleaningTemps)
1550 {
1551 tmpMS = Util.EnvironmentTickCount();
1552 m_cleaningTemps = true;
1553 Util.FireAndForget(delegate { CleanTempObjects(); m_cleaningTemps = false; });
1554 tempOnRezMS = Util.EnvironmentTickCountSubtract(tmpMS);
1555 }
1556
1557 if (Frame % m_update_events == 0) 1865 if (Frame % m_update_events == 0)
1558 { 1866 {
1559 tmpMS = Util.EnvironmentTickCount(); 1867 tmpMS = Util.EnvironmentTickCount();
1560 UpdateEvents(); 1868 UpdateEvents();
1561 eventMS = Util.EnvironmentTickCountSubtract(tmpMS); 1869 eventMS = Util.EnvironmentTickCountSubtract(tmpMS);
1562 } 1870 }
1563 1871
1564 if (PeriodicBackup && Frame % m_update_backup == 0) 1872 if (PeriodicBackup && Frame % m_update_backup == 0)
1565 { 1873 {
1566 tmpMS = Util.EnvironmentTickCount(); 1874 tmpMS = Util.EnvironmentTickCount();
1567 UpdateStorageBackup(); 1875 UpdateStorageBackup();
1568 backupMS = Util.EnvironmentTickCountSubtract(tmpMS); 1876 backupMS = Util.EnvironmentTickCountSubtract(tmpMS);
1569 } 1877 }
1570 1878
1571 //if (Frame % m_update_land == 0) 1879 //if (Frame % m_update_land == 0)
1572 //{ 1880 //{
1573 // int ldMS = Util.EnvironmentTickCount(); 1881 // int ldMS = Util.EnvironmentTickCount();
1574 // UpdateLand(); 1882 // UpdateLand();
1575 // landMS = Util.EnvironmentTickCountSubtract(ldMS); 1883 // landMS = Util.EnvironmentTickCountSubtract(ldMS);
1576 //} 1884 //}
1577 1885
1578 if (!LoginsEnabled && Frame == 20) 1886 if (!LoginsEnabled && Frame == 20)
1579 { 1887 {
1580 // m_log.DebugFormat("{0} {1} {2}", LoginsDisabled, m_sceneGraph.GetActiveScriptsCount(), LoginLock); 1888 // m_log.DebugFormat("{0} {1} {2}", LoginsDisabled, m_sceneGraph.GetActiveScriptsCount(), LoginLock);
1581 1889
1582 // In 99.9% of cases it is a bad idea to manually force garbage collection. However, 1890 // In 99.9% of cases it is a bad idea to manually force garbage collection. However,
1583 // this is a rare case where we know we have just went through a long cycle of heap 1891 // this is a rare case where we know we have just went through a long cycle of heap
1584 // allocations, and there is no more work to be done until someone logs in 1892 // allocations, and there is no more work to be done until someone logs in
@@ -1593,7 +1901,7 @@ namespace OpenSim.Region.Framework.Scenes
1593 } 1901 }
1594 1902
1595 m_sceneGridService.InformNeighborsThatRegionisUp( 1903 m_sceneGridService.InformNeighborsThatRegionisUp(
1596 RequestModuleInterface<INeighbourService>(), RegionInfo); 1904 RequestModuleInterface<INeighbourService>(), RegionInfo);
1597 1905
1598 // Region ready should always be set 1906 // Region ready should always be set
1599 Ready = true; 1907 Ready = true;
@@ -1604,7 +1912,7 @@ namespace OpenSim.Region.Framework.Scenes
1604 if (m_sceneGraph.GetActiveScriptsCount() == 0) 1912 if (m_sceneGraph.GetActiveScriptsCount() == 0)
1605 { 1913 {
1606 // In this case, we leave it to the IRegionReadyModule to enable logins 1914 // In this case, we leave it to the IRegionReadyModule to enable logins
1607 1915
1608 // LoginLock can currently only be set by a region module implementation. 1916 // LoginLock can currently only be set by a region module implementation.
1609 // If somehow this hasn't been done then the quickest way to bugfix is to see the 1917 // If somehow this hasn't been done then the quickest way to bugfix is to see the
1610 // NullReferenceException 1918 // NullReferenceException
@@ -1620,26 +1928,42 @@ namespace OpenSim.Region.Framework.Scenes
1620 "[SCENE]: Failed on region {0} with exception {1}{2}", 1928 "[SCENE]: Failed on region {0} with exception {1}{2}",
1621 RegionInfo.RegionName, e.Message, e.StackTrace); 1929 RegionInfo.RegionName, e.Message, e.StackTrace);
1622 } 1930 }
1623 1931
1624 EventManager.TriggerRegionHeartbeatEnd(this); 1932 EventManager.TriggerRegionHeartbeatEnd(this);
1933 otherMS = eventMS + backupMS + terrainMS + landMS;
1625 1934
1626 Watchdog.UpdateThread(); 1935 // Get the elapsed time for the simulation frame
1936 simFrameStopwatch.Stop();
1937 preciseSimFrameTime +=
1938 simFrameStopwatch.Elapsed.TotalMilliseconds;
1627 1939
1628 previousFrameTick = m_lastFrameTick; 1940 if (!UpdateOnTimer)
1629 m_lastFrameTick = Util.EnvironmentTickCount(); 1941 {
1630 tmpMS = Util.EnvironmentTickCountSubtract(m_lastFrameTick, maintc); 1942 Watchdog.UpdateThread();
1631 tmpMS = (int)(MinFrameTime * 1000) - tmpMS;
1632 1943
1633 if (tmpMS > 0) 1944 spareMS = MinFrameTicks - Util.EnvironmentTickCountSubtract(m_lastFrameTick);
1945
1946 if (spareMS > 0)
1947 m_updateWaitEvent.WaitOne(spareMS);
1948 else
1949 spareMS = 0;
1950 }
1951 else
1634 { 1952 {
1635 Thread.Sleep(tmpMS); 1953 spareMS = Math.Max(0, MinFrameTicks - physicsMS2 - agentMS - physicsMS - otherMS);
1636 spareMS += tmpMS;
1637 } 1954 }
1638 1955
1639 frameMS = Util.EnvironmentTickCountSubtract(maintc); 1956 // Get the total frame time
1640 maintc = Util.EnvironmentTickCount(); 1957 totalFrameStopwatch.Stop();
1958 preciseTotalFrameTime =
1959 totalFrameStopwatch.Elapsed.TotalMilliseconds;
1641 1960
1642 otherMS = tempOnRezMS + eventMS + backupMS + terrainMS + landMS; 1961 // Restart the stopwatch for the total time of the next frame
1962 totalFrameStopwatch.Restart();
1963
1964 previousFrameTick = m_lastFrameTick;
1965 frameMS = Util.EnvironmentTickCountSubtract(m_lastFrameTick);
1966 m_lastFrameTick = Util.EnvironmentTickCount();
1643 1967
1644 // if (Frame%m_update_avatars == 0) 1968 // if (Frame%m_update_avatars == 0)
1645 // UpdateInWorldTime(); 1969 // UpdateInWorldTime();
@@ -1653,18 +1977,53 @@ namespace OpenSim.Region.Framework.Scenes
1653 StatsReporter.addOtherMS(otherMS); 1977 StatsReporter.addOtherMS(otherMS);
1654 StatsReporter.AddSpareMS(spareMS); 1978 StatsReporter.AddSpareMS(spareMS);
1655 StatsReporter.addScriptLines(m_sceneGraph.GetScriptLPS()); 1979 StatsReporter.addScriptLines(m_sceneGraph.GetScriptLPS());
1980 StatsReporter.AddScriptMS((int) GetAndResetScriptExecutionTime());
1981
1982 // Send the correct time values to the stats reporter for the
1983 // frame times
1984 StatsReporter.addFrameTimeMilliseconds(preciseTotalFrameTime,
1985 preciseSimFrameTime, precisePhysicsFrameTime, 0.0);
1986
1987 // Send the correct number of frames that the physics library
1988 // has processed to the stats reporter
1989 StatsReporter.addPhysicsFrame(1);
1656 1990
1657 // Optionally warn if a frame takes double the amount of time that it should. 1991 // Optionally warn if a frame takes double the amount of time that it should.
1658 if (DebugUpdates 1992 if (DebugUpdates
1659 && Util.EnvironmentTickCountSubtract( 1993 && Util.EnvironmentTickCountSubtract(
1660 m_lastFrameTick, previousFrameTick) > (int)(MinFrameTime * 1000 * 2)) 1994 m_lastFrameTick, previousFrameTick) > MinFrameTicks * 2)
1661 m_log.WarnFormat( 1995 m_log.WarnFormat(
1662 "[SCENE]: Frame took {0} ms (desired max {1} ms) in {2}", 1996 "[SCENE]: Frame took {0} ms (desired max {1} ms) in {2}",
1663 Util.EnvironmentTickCountSubtract(m_lastFrameTick, previousFrameTick), 1997 Util.EnvironmentTickCountSubtract(m_lastFrameTick, previousFrameTick),
1664 MinFrameTime * 1000, 1998 MinFrameTicks,
1665 RegionInfo.RegionName); 1999 RegionInfo.RegionName);
1666 } 2000 }
1667 } 2001
2002 // Finished updating scene frame, so stop the total frame's Stopwatch
2003 totalFrameStopwatch.Stop();
2004
2005 return spareMS >= 0;
2006 }
2007
2008 /// <summary>
2009 /// Adds the execution time of one script to the total scripts execution time for this region.
2010 /// </summary>
2011 /// <param name="ticks">Elapsed Stopwatch ticks</param>
2012 public void AddScriptExecutionTime(long ticks)
2013 {
2014 Interlocked.Add(ref m_scriptExecutionTime, ticks);
2015 }
2016
2017 /// <summary>
2018 /// Returns the total execution time of all the scripts in the region since the last frame
2019 /// (in milliseconds), and clears the value in preparation for the next frame.
2020 /// </summary>
2021 /// <returns>Time in milliseconds</returns>
2022 private long GetAndResetScriptExecutionTime()
2023 {
2024 long ticks = Interlocked.Exchange(ref m_scriptExecutionTime, 0);
2025 return (ticks * 1000) / Stopwatch.Frequency;
2026 }
1668 2027
1669 public void AddGroupTarget(SceneObjectGroup grp) 2028 public void AddGroupTarget(SceneObjectGroup grp)
1670 { 2029 {
@@ -1723,7 +2082,7 @@ namespace OpenSim.Region.Framework.Scenes
1723 if (!m_backingup) 2082 if (!m_backingup)
1724 { 2083 {
1725 m_backingup = true; 2084 m_backingup = true;
1726 Util.FireAndForget(BackupWaitCallback); 2085 WorkManager.RunInThread(o => Backup(false), null, string.Format("BackupWaitCallback ({0})", Name));
1727 } 2086 }
1728 } 2087 }
1729 2088
@@ -1736,16 +2095,12 @@ namespace OpenSim.Region.Framework.Scenes
1736 } 2095 }
1737 2096
1738 /// <summary> 2097 /// <summary>
1739 /// Wrapper for Backup() that can be called with Util.FireAndForget() 2098 /// Backup the scene.
1740 /// </summary>
1741 private void BackupWaitCallback(object o)
1742 {
1743 Backup(false);
1744 }
1745
1746 /// <summary>
1747 /// Backup the scene. This acts as the main method of the backup thread.
1748 /// </summary> 2099 /// </summary>
2100 /// <remarks>
2101 /// This acts as the main method of the backup thread. In a regression test whether the backup thread is not
2102 /// running independently this can be invoked directly.
2103 /// </remarks>
1749 /// <param name="forced"> 2104 /// <param name="forced">
1750 /// If true, then any changes that have not yet been persisted are persisted. If false, 2105 /// If true, then any changes that have not yet been persisted are persisted. If false,
1751 /// then the persistence decision is left to the backup code (in some situations, such as object persistence, 2106 /// 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
1784 2139
1785 IMessageTransferModule tr = RequestModuleInterface<IMessageTransferModule>(); 2140 IMessageTransferModule tr = RequestModuleInterface<IMessageTransferModule>();
1786 if (tr != null) 2141 if (tr != null)
1787 tr.SendInstantMessage(msg, delegate(bool success) {}); 2142 tr.SendInstantMessage(msg, delegate(bool success) { });
1788 } 2143 }
1789 m_returns.Clear(); 2144 m_returns.Clear();
1790 } 2145 }
@@ -1798,6 +2153,7 @@ namespace OpenSim.Region.Framework.Scenes
1798 { 2153 {
1799 if (group != null) 2154 if (group != null)
1800 { 2155 {
2156 group.HasGroupChanged = true;
1801 group.ProcessBackup(SimulationDataService, true); 2157 group.ProcessBackup(SimulationDataService, true);
1802 } 2158 }
1803 } 2159 }
@@ -1866,7 +2222,7 @@ namespace OpenSim.Region.Framework.Scenes
1866 { 2222 {
1867 try 2223 try
1868 { 2224 {
1869 double[,] map = SimulationDataService.LoadTerrain(RegionInfo.RegionID); 2225 TerrainData map = SimulationDataService.LoadTerrain(RegionInfo.RegionID, (int)RegionInfo.RegionSizeX, (int)RegionInfo.RegionSizeY, (int)RegionInfo.RegionSizeZ);
1870 if (map == null) 2226 if (map == null)
1871 { 2227 {
1872 // This should be in the Terrain module, but it isn't because 2228 // This should be in the Terrain module, but it isn't because
@@ -1877,7 +2233,7 @@ namespace OpenSim.Region.Framework.Scenes
1877 m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain); 2233 m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain);
1878 2234
1879 m_log.InfoFormat("[TERRAIN]: No default terrain. Generating a new terrain {0}.", m_InitialTerrain); 2235 m_log.InfoFormat("[TERRAIN]: No default terrain. Generating a new terrain {0}.", m_InitialTerrain);
1880 Heightmap = new TerrainChannel(m_InitialTerrain); 2236 Heightmap = new TerrainChannel(m_InitialTerrain, (int)RegionInfo.RegionSizeX, (int)RegionInfo.RegionSizeY, (int)RegionInfo.RegionSizeZ);
1881 2237
1882 SimulationDataService.StoreTerrain(Heightmap.GetDoubles(), RegionInfo.RegionID); 2238 SimulationDataService.StoreTerrain(Heightmap.GetDoubles(), RegionInfo.RegionID);
1883 } 2239 }
@@ -1891,9 +2247,9 @@ namespace OpenSim.Region.Framework.Scenes
1891 m_log.WarnFormat( 2247 m_log.WarnFormat(
1892 "[TERRAIN]: Scene.cs: LoadWorldMap() - Regenerating as failed with exception {0}{1}", 2248 "[TERRAIN]: Scene.cs: LoadWorldMap() - Regenerating as failed with exception {0}{1}",
1893 e.Message, e.StackTrace); 2249 e.Message, e.StackTrace);
1894 2250
1895 // Non standard region size. If there's an old terrain in the database, it might read past the buffer 2251 // Non standard region size. If there's an old terrain in the database, it might read past the buffer
1896 #pragma warning disable 0162 2252#pragma warning disable 0162
1897 if ((int)Constants.RegionSize != 256) 2253 if ((int)Constants.RegionSize != 256)
1898 { 2254 {
1899 Heightmap = new TerrainChannel(); 2255 Heightmap = new TerrainChannel();
@@ -1921,10 +2277,16 @@ namespace OpenSim.Region.Framework.Scenes
1921 //// stored in the GridService, because that's what the world map module uses 2277 //// stored in the GridService, because that's what the world map module uses
1922 //// to send the map image UUIDs (of other regions) to the viewer... 2278 //// to send the map image UUIDs (of other regions) to the viewer...
1923 if (m_generateMaptiles) 2279 if (m_generateMaptiles)
1924 RegenerateMaptile(); 2280 RegenerateMaptile();
1925 2281
1926 GridRegion region = new GridRegion(RegionInfo); 2282 GridRegion region = new GridRegion(RegionInfo);
1927 string error = GridService.RegisterRegion(RegionInfo.ScopeID, region); 2283 string error = GridService.RegisterRegion(RegionInfo.ScopeID, region);
2284 // m_log.DebugFormat("[SCENE]: RegisterRegionWithGrid. name={0},id={1},loc=<{2},{3}>,size=<{4},{5}>",
2285 // m_regionName,
2286 // RegionInfo.RegionID,
2287 // RegionInfo.RegionLocX, RegionInfo.RegionLocY,
2288 // RegionInfo.RegionSizeX, RegionInfo.RegionSizeY);
2289
1928 if (error != String.Empty) 2290 if (error != String.Empty)
1929 throw new Exception(error); 2291 throw new Exception(error);
1930 } 2292 }
@@ -1985,13 +2347,26 @@ namespace OpenSim.Region.Framework.Scenes
1985 rootPart.TrimPermissions(); 2347 rootPart.TrimPermissions();
1986 2348
1987 // Don't do this here - it will get done later on when sculpt data is loaded. 2349 // Don't do this here - it will get done later on when sculpt data is loaded.
1988// group.CheckSculptAndLoad(); 2350 // group.CheckSculptAndLoad();
1989 } 2351 }
1990 2352
1991 LoadingPrims = false; 2353 LoadingPrims = false;
1992 EventManager.TriggerPrimsLoaded(this); 2354 EventManager.TriggerPrimsLoaded(this);
1993 } 2355 }
1994 2356
2357 public bool SupportsRayCastFiltered()
2358 {
2359 if (PhysicsScene == null)
2360 return false;
2361 return PhysicsScene.SupportsRaycastWorldFiltered();
2362 }
2363
2364 public object RayCastFiltered(Vector3 position, Vector3 direction, float length, int Count, RayFilterFlags filter)
2365 {
2366 if (PhysicsScene == null)
2367 return null;
2368 return PhysicsScene.RaycastWorld(position, direction, length, Count, filter);
2369 }
1995 2370
1996 /// <summary> 2371 /// <summary>
1997 /// Gets a new rez location based on the raycast and the size of the object that is being rezzed. 2372 /// 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
2020 SceneObjectPart target = GetSceneObjectPart(RayTargetID); 2395 SceneObjectPart target = GetSceneObjectPart(RayTargetID);
2021 2396
2022 Vector3 direction = Vector3.Normalize(RayEnd - RayStart); 2397 Vector3 direction = Vector3.Normalize(RayEnd - RayStart);
2023 Vector3 AXOrigin = new Vector3(RayStart.X, RayStart.Y, RayStart.Z); 2398 Vector3 AXOrigin = RayStart;
2024 Vector3 AXdirection = new Vector3(direction.X, direction.Y, direction.Z); 2399 Vector3 AXdirection = direction;
2025 2400
2026 if (target != null) 2401 if (target != null)
2027 { 2402 {
@@ -2037,19 +2412,19 @@ namespace OpenSim.Region.Framework.Scenes
2037 EntityIntersection ei = target.TestIntersectionOBB(NewRay, Quaternion.Identity, frontFacesOnly, FaceCenter); 2412 EntityIntersection ei = target.TestIntersectionOBB(NewRay, Quaternion.Identity, frontFacesOnly, FaceCenter);
2038 2413
2039 // Un-comment out the following line to Get Raytrace results printed to the console. 2414 // Un-comment out the following line to Get Raytrace results printed to the console.
2040 // m_log.Info("[RAYTRACERESULTS]: Hit:" + ei.HitTF.ToString() + " Point: " + ei.ipoint.ToString() + " Normal: " + ei.normal.ToString()); 2415 // m_log.Info("[RAYTRACERESULTS]: Hit:" + ei.HitTF.ToString() + " Point: " + ei.ipoint.ToString() + " Normal: " + ei.normal.ToString());
2041 float ScaleOffset = 0.5f; 2416 float ScaleOffset = 0.5f;
2042 2417
2043 // If we hit something 2418 // If we hit something
2044 if (ei.HitTF) 2419 if (ei.HitTF)
2045 { 2420 {
2046 Vector3 scaleComponent = new Vector3(ei.AAfaceNormal.X, ei.AAfaceNormal.Y, ei.AAfaceNormal.Z); 2421 Vector3 scaleComponent = ei.AAfaceNormal;
2047 if (scaleComponent.X != 0) ScaleOffset = scale.X; 2422 if (scaleComponent.X != 0) ScaleOffset = scale.X;
2048 if (scaleComponent.Y != 0) ScaleOffset = scale.Y; 2423 if (scaleComponent.Y != 0) ScaleOffset = scale.Y;
2049 if (scaleComponent.Z != 0) ScaleOffset = scale.Z; 2424 if (scaleComponent.Z != 0) ScaleOffset = scale.Z;
2050 ScaleOffset = Math.Abs(ScaleOffset); 2425 ScaleOffset = Math.Abs(ScaleOffset);
2051 Vector3 intersectionpoint = new Vector3(ei.ipoint.X, ei.ipoint.Y, ei.ipoint.Z); 2426 Vector3 intersectionpoint = ei.ipoint;
2052 Vector3 normal = new Vector3(ei.normal.X, ei.normal.Y, ei.normal.Z); 2427 Vector3 normal = ei.normal;
2053 // Set the position to the intersection point 2428 // Set the position to the intersection point
2054 Vector3 offset = (normal * (ScaleOffset / 2f)); 2429 Vector3 offset = (normal * (ScaleOffset / 2f));
2055 pos = (intersectionpoint + offset); 2430 pos = (intersectionpoint + offset);
@@ -2058,7 +2433,7 @@ namespace OpenSim.Region.Framework.Scenes
2058 //And in cases when we weren't rezzing from inventory we were re-adding the 0.25 straight after calling this method 2433 //And in cases when we weren't rezzing from inventory we were re-adding the 0.25 straight after calling this method
2059 // Un-offset the prim (it gets offset later by the consumer method) 2434 // Un-offset the prim (it gets offset later by the consumer method)
2060 //pos.Z -= 0.25F; 2435 //pos.Z -= 0.25F;
2061 2436
2062 } 2437 }
2063 2438
2064 return pos; 2439 return pos;
@@ -2074,8 +2449,9 @@ namespace OpenSim.Region.Framework.Scenes
2074 2449
2075 if (ei.HitTF) 2450 if (ei.HitTF)
2076 { 2451 {
2077 pos = new Vector3(ei.ipoint.X, ei.ipoint.Y, ei.ipoint.Z); 2452 pos = ei.ipoint;
2078 } else 2453 }
2454 else
2079 { 2455 {
2080 // fall back to our stupid functionality 2456 // fall back to our stupid functionality
2081 pos = RayEnd; 2457 pos = RayEnd;
@@ -2137,7 +2513,7 @@ namespace OpenSim.Region.Framework.Scenes
2137 // "[SCENE]: Scene.AddNewPrim() pcode {0} called for {1} in {2}", shape.PCode, ownerID, RegionInfo.RegionName); 2513 // "[SCENE]: Scene.AddNewPrim() pcode {0} called for {1} in {2}", shape.PCode, ownerID, RegionInfo.RegionName);
2138 2514
2139 SceneObjectGroup sceneObject = null; 2515 SceneObjectGroup sceneObject = null;
2140 2516
2141 // If an entity creator has been registered for this prim type then use that 2517 // If an entity creator has been registered for this prim type then use that
2142 if (m_entityCreators.ContainsKey((PCode)shape.PCode)) 2518 if (m_entityCreators.ContainsKey((PCode)shape.PCode))
2143 { 2519 {
@@ -2158,7 +2534,7 @@ namespace OpenSim.Region.Framework.Scenes
2158 2534
2159 return sceneObject; 2535 return sceneObject;
2160 } 2536 }
2161 2537
2162 /// <summary> 2538 /// <summary>
2163 /// Add an object into the scene that has come from storage 2539 /// Add an object into the scene that has come from storage
2164 /// </summary> 2540 /// </summary>
@@ -2191,7 +2567,7 @@ namespace OpenSim.Region.Framework.Scenes
2191 return false; 2567 return false;
2192 2568
2193 } 2569 }
2194 2570
2195 /// <summary> 2571 /// <summary>
2196 /// Add an object into the scene that has come from storage 2572 /// Add an object into the scene that has come from storage
2197 /// </summary> 2573 /// </summary>
@@ -2227,7 +2603,7 @@ namespace OpenSim.Region.Framework.Scenes
2227 { 2603 {
2228 return AddNewSceneObject(sceneObject, attachToBackup, true); 2604 return AddNewSceneObject(sceneObject, attachToBackup, true);
2229 } 2605 }
2230 2606
2231 /// <summary> 2607 /// <summary>
2232 /// Add a newly created object to the scene 2608 /// Add a newly created object to the scene
2233 /// </summary> 2609 /// </summary>
@@ -2242,16 +2618,16 @@ namespace OpenSim.Region.Framework.Scenes
2242 /// </param> 2618 /// </param>
2243 /// <returns>true if the object was added. false if not</returns> 2619 /// <returns>true if the object was added. false if not</returns>
2244 public bool AddNewSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates) 2620 public bool AddNewSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates)
2245 { 2621 {
2246 if (m_sceneGraph.AddNewSceneObject(sceneObject, attachToBackup, sendClientUpdates)) 2622 if (m_sceneGraph.AddNewSceneObject(sceneObject, attachToBackup, sendClientUpdates))
2247 { 2623 {
2248 EventManager.TriggerObjectAddedToScene(sceneObject); 2624 EventManager.TriggerObjectAddedToScene(sceneObject);
2249 return true; 2625 return true;
2250 } 2626 }
2251 2627
2252 return false; 2628 return false;
2253 } 2629 }
2254 2630
2255 /// <summary> 2631 /// <summary>
2256 /// Add a newly created object to the scene. 2632 /// Add a newly created object to the scene.
2257 /// </summary> 2633 /// </summary>
@@ -2268,7 +2644,7 @@ namespace OpenSim.Region.Framework.Scenes
2268 SceneObjectGroup sceneObject, bool attachToBackup, Vector3? pos, Quaternion? rot, Vector3 vel) 2644 SceneObjectGroup sceneObject, bool attachToBackup, Vector3? pos, Quaternion? rot, Vector3 vel)
2269 { 2645 {
2270 if (m_sceneGraph.AddNewSceneObject(sceneObject, attachToBackup, pos, rot, vel)) 2646 if (m_sceneGraph.AddNewSceneObject(sceneObject, attachToBackup, pos, rot, vel))
2271 { 2647 {
2272 EventManager.TriggerObjectAddedToScene(sceneObject); 2648 EventManager.TriggerObjectAddedToScene(sceneObject);
2273 return true; 2649 return true;
2274 } 2650 }
@@ -2316,8 +2692,8 @@ namespace OpenSim.Region.Framework.Scenes
2316 /// <param name="silent">Suppress broadcasting changes to other clients.</param> 2692 /// <param name="silent">Suppress broadcasting changes to other clients.</param>
2317 /// <param name="removeScripts">If true, then scripts are removed. If false, then they are only stopped.</para> 2693 /// <param name="removeScripts">If true, then scripts are removed. If false, then they are only stopped.</para>
2318 public void DeleteSceneObject(SceneObjectGroup group, bool silent, bool removeScripts) 2694 public void DeleteSceneObject(SceneObjectGroup group, bool silent, bool removeScripts)
2319 { 2695 {
2320// m_log.DebugFormat("[SCENE]: Deleting scene object {0} {1}", group.Name, group.UUID); 2696 // m_log.DebugFormat("[SCENE]: Deleting scene object {0} {1}", group.Name, group.UUID);
2321 2697
2322 if (removeScripts) 2698 if (removeScripts)
2323 group.RemoveScriptInstances(true); 2699 group.RemoveScriptInstances(true);
@@ -2328,6 +2704,12 @@ namespace OpenSim.Region.Framework.Scenes
2328 2704
2329 foreach (SceneObjectPart part in partList) 2705 foreach (SceneObjectPart part in partList)
2330 { 2706 {
2707 if (part.KeyframeMotion != null)
2708 {
2709 part.KeyframeMotion.Delete();
2710 part.KeyframeMotion = null;
2711 }
2712
2331 if (part.IsJoint() && ((part.Flags & PrimFlags.Physics) != 0)) 2713 if (part.IsJoint() && ((part.Flags & PrimFlags.Physics) != 0))
2332 { 2714 {
2333 PhysicsScene.RequestJointDeletion(part.Name); // FIXME: what if the name changed? 2715 PhysicsScene.RequestJointDeletion(part.Name); // FIXME: what if the name changed?
@@ -2346,7 +2728,7 @@ namespace OpenSim.Region.Framework.Scenes
2346 2728
2347 group.DeleteGroupFromScene(silent); 2729 group.DeleteGroupFromScene(silent);
2348 2730
2349// m_log.DebugFormat("[SCENE]: Exit DeleteSceneObject() for {0} {1}", group.Name, group.UUID); 2731 // m_log.DebugFormat("[SCENE]: Exit DeleteSceneObject() for {0} {1}", group.Name, group.UUID);
2350 } 2732 }
2351 2733
2352 /// <summary> 2734 /// <summary>
@@ -2362,17 +2744,16 @@ namespace OpenSim.Region.Framework.Scenes
2362 { 2744 {
2363 if (!softDelete) 2745 if (!softDelete)
2364 { 2746 {
2365 // Force a database update so that the scene object group ID is accurate. It's possible that the 2747 // If the group contains prims whose SceneGroupID is incorrect then force a
2366 // group has recently been delinked from another group but that this change has not been persisted 2748 // database update, because RemoveObject() works by searching on the SceneGroupID.
2367 // to the DB.
2368 // This is an expensive thing to do so only do it if absolutely necessary. 2749 // This is an expensive thing to do so only do it if absolutely necessary.
2369 if (so.HasGroupChangedDueToDelink) 2750 if (so.GroupContainsForeignPrims)
2370 ForceSceneObjectBackup(so); 2751 ForceSceneObjectBackup(so);
2371 2752
2372 so.DetachFromBackup(); 2753 so.DetachFromBackup();
2373 SimulationDataService.RemoveObject(so.UUID, RegionInfo.RegionID); 2754 SimulationDataService.RemoveObject(so.UUID, RegionInfo.RegionID);
2374 } 2755 }
2375 2756
2376 // We need to keep track of this state in case this group is still queued for further backup. 2757 // We need to keep track of this state in case this group is still queued for further backup.
2377 so.IsDeleted = true; 2758 so.IsDeleted = true;
2378 2759
@@ -2431,186 +2812,35 @@ namespace OpenSim.Region.Framework.Scenes
2431 EntityTransferModule.Cross(grp, attemptedPosition, silent); 2812 EntityTransferModule.Cross(grp, attemptedPosition, silent);
2432 } 2813 }
2433 2814
2434 public Border GetCrossedBorder(Vector3 position, Cardinals gridline) 2815 // Simple test to see if a position is in the current region.
2816 // This test is mostly used to see if a region crossing is necessary.
2817 // Assuming the position is relative to the region so anything outside its bounds.
2818 // Return 'true' if position inside region.
2819 public bool PositionIsInCurrentRegion(Vector3 pos)
2435 { 2820 {
2436 if (BordersLocked) 2821 bool ret = false;
2437 { 2822 int xx = (int)Math.Floor(pos.X);
2438 switch (gridline) 2823 int yy = (int)Math.Floor(pos.Y);
2439 { 2824 if (xx < 0 || yy < 0)
2440 case Cardinals.N: 2825 return false;
2441 lock (NorthBorders)
2442 {
2443 foreach (Border b in NorthBorders)
2444 {
2445 if (b.TestCross(position))
2446 return b;
2447 }
2448 }
2449 break;
2450 case Cardinals.S:
2451 lock (SouthBorders)
2452 {
2453 foreach (Border b in SouthBorders)
2454 {
2455 if (b.TestCross(position))
2456 return b;
2457 }
2458 }
2459
2460 break;
2461 case Cardinals.E:
2462 lock (EastBorders)
2463 {
2464 foreach (Border b in EastBorders)
2465 {
2466 if (b.TestCross(position))
2467 return b;
2468 }
2469 }
2470
2471 break;
2472 case Cardinals.W:
2473
2474 lock (WestBorders)
2475 {
2476 foreach (Border b in WestBorders)
2477 {
2478 if (b.TestCross(position))
2479 return b;
2480 }
2481 }
2482 break;
2483 2826
2484 } 2827 IRegionCombinerModule regionCombinerModule = RequestModuleInterface<IRegionCombinerModule>();
2828 if (regionCombinerModule == null)
2829 {
2830 // Regular region. Just check for region size
2831 if (xx < RegionInfo.RegionSizeX && yy < RegionInfo.RegionSizeY)
2832 ret = true;
2485 } 2833 }
2486 else 2834 else
2487 { 2835 {
2488 switch (gridline) 2836 // We're in a mega-region so see if we are still in that larger region
2489 { 2837 ret = regionCombinerModule.PositionIsInMegaregion(this.RegionInfo.RegionID, xx, yy);
2490 case Cardinals.N:
2491 foreach (Border b in NorthBorders)
2492 {
2493 if (b.TestCross(position))
2494 return b;
2495 }
2496
2497 break;
2498 case Cardinals.S:
2499 foreach (Border b in SouthBorders)
2500 {
2501 if (b.TestCross(position))
2502 return b;
2503 }
2504 break;
2505 case Cardinals.E:
2506 foreach (Border b in EastBorders)
2507 {
2508 if (b.TestCross(position))
2509 return b;
2510 }
2511
2512 break;
2513 case Cardinals.W:
2514 foreach (Border b in WestBorders)
2515 {
2516 if (b.TestCross(position))
2517 return b;
2518 }
2519 break;
2520
2521 }
2522 } 2838 }
2523
2524 2839
2525 return null; 2840 return ret;
2526 }
2527 2841
2528 public bool TestBorderCross(Vector3 position, Cardinals border)
2529 {
2530 if (BordersLocked)
2531 {
2532 switch (border)
2533 {
2534 case Cardinals.N:
2535 lock (NorthBorders)
2536 {
2537 foreach (Border b in NorthBorders)
2538 {
2539 if (b.TestCross(position))
2540 return true;
2541 }
2542 }
2543 break;
2544 case Cardinals.E:
2545 lock (EastBorders)
2546 {
2547 foreach (Border b in EastBorders)
2548 {
2549 if (b.TestCross(position))
2550 return true;
2551 }
2552 }
2553 break;
2554 case Cardinals.S:
2555 lock (SouthBorders)
2556 {
2557 foreach (Border b in SouthBorders)
2558 {
2559 if (b.TestCross(position))
2560 return true;
2561 }
2562 }
2563 break;
2564 case Cardinals.W:
2565 lock (WestBorders)
2566 {
2567 foreach (Border b in WestBorders)
2568 {
2569 if (b.TestCross(position))
2570 return true;
2571 }
2572 }
2573 break;
2574 }
2575 }
2576 else
2577 {
2578 switch (border)
2579 {
2580 case Cardinals.N:
2581 foreach (Border b in NorthBorders)
2582 {
2583 if (b.TestCross(position))
2584 return true;
2585 }
2586 break;
2587 case Cardinals.E:
2588 foreach (Border b in EastBorders)
2589 {
2590 if (b.TestCross(position))
2591 return true;
2592 }
2593 break;
2594 case Cardinals.S:
2595 foreach (Border b in SouthBorders)
2596 {
2597 if (b.TestCross(position))
2598 return true;
2599 }
2600 break;
2601 case Cardinals.W:
2602 foreach (Border b in WestBorders)
2603 {
2604 if (b.TestCross(position))
2605 return true;
2606 }
2607 break;
2608 }
2609 }
2610 return false;
2611 } 2842 }
2612 2843
2613
2614 /// <summary> 2844 /// <summary>
2615 /// Called when objects or attachments cross the border, or teleport, between regions. 2845 /// Called when objects or attachments cross the border, or teleport, between regions.
2616 /// </summary> 2846 /// </summary>
@@ -2632,45 +2862,8 @@ namespace OpenSim.Region.Framework.Scenes
2632 return false; 2862 return false;
2633 } 2863 }
2634 2864
2635 // If the user is banned, we won't let any of their objects 2865 if (!EntityTransferModule.HandleIncomingSceneObject(newObject, newPosition))
2636 // enter. Period.
2637 //
2638 if (RegionInfo.EstateSettings.IsBanned(newObject.OwnerID))
2639 {
2640 m_log.InfoFormat("[INTERREGION]: Denied prim crossing for banned avatar {0}", newObject.OwnerID);
2641 return false;
2642 }
2643
2644 if (newPosition != Vector3.Zero)
2645 newObject.RootPart.GroupPosition = newPosition;
2646
2647 if (!AddSceneObject(newObject))
2648 {
2649 m_log.DebugFormat(
2650 "[INTERREGION]: Problem adding scene object {0} in {1} ", newObject.UUID, RegionInfo.RegionName);
2651 return false; 2866 return false;
2652 }
2653
2654 if (!newObject.IsAttachment)
2655 {
2656 // FIXME: It would be better to never add the scene object at all rather than add it and then delete
2657 // it
2658 if (!Permissions.CanObjectEntry(newObject.UUID, true, newObject.AbsolutePosition))
2659 {
2660 // Deny non attachments based on parcel settings
2661 //
2662 m_log.Info("[INTERREGION]: Denied prim crossing because of parcel settings");
2663
2664 DeleteSceneObject(newObject, false);
2665
2666 return false;
2667 }
2668
2669 // For attachments, we need to wait until the agent is root
2670 // before we restart the scripts, or else some functions won't work.
2671 newObject.RootPart.ParentGroup.CreateScriptInstances(0, false, DefaultScriptEngine, GetStateSource(newObject));
2672 newObject.ResumeScripts();
2673 }
2674 2867
2675 // Do this as late as possible so that listeners have full access to the incoming object 2868 // Do this as late as possible so that listeners have full access to the incoming object
2676 EventManager.TriggerOnIncomingSceneObject(newObject); 2869 EventManager.TriggerOnIncomingSceneObject(newObject);
@@ -2697,7 +2890,7 @@ namespace OpenSim.Region.Framework.Scenes
2697 { 2890 {
2698 sceneObject.RootPart.AddFlag(PrimFlags.TemporaryOnRez); 2891 sceneObject.RootPart.AddFlag(PrimFlags.TemporaryOnRez);
2699 sceneObject.RootPart.AddFlag(PrimFlags.Phantom); 2892 sceneObject.RootPart.AddFlag(PrimFlags.Phantom);
2700 2893
2701 // Don't sent a full update here because this will cause full updates to be sent twice for 2894 // Don't sent a full update here because this will cause full updates to be sent twice for
2702 // attachments on region crossings, resulting in viewer glitches. 2895 // attachments on region crossings, resulting in viewer glitches.
2703 AddRestoredSceneObject(sceneObject, false, false, false); 2896 AddRestoredSceneObject(sceneObject, false, false, false);
@@ -2712,15 +2905,18 @@ namespace OpenSim.Region.Framework.Scenes
2712 { 2905 {
2713 SceneObjectGroup grp = sceneObject; 2906 SceneObjectGroup grp = sceneObject;
2714 2907
2715// m_log.DebugFormat( 2908 // m_log.DebugFormat(
2716// "[ATTACHMENT]: Received attachment {0}, inworld asset id {1}", grp.FromItemID, grp.UUID); 2909 // "[ATTACHMENT]: Received attachment {0}, inworld asset id {1}", grp.FromItemID, grp.UUID);
2717// m_log.DebugFormat( 2910 // m_log.DebugFormat(
2718// "[ATTACHMENT]: Attach to avatar {0} at position {1}", sp.UUID, grp.AbsolutePosition); 2911 // "[ATTACHMENT]: Attach to avatar {0} at position {1}", sp.UUID, grp.AbsolutePosition);
2719 2912
2720 RootPrim.RemFlag(PrimFlags.TemporaryOnRez); 2913 RootPrim.RemFlag(PrimFlags.TemporaryOnRez);
2721 2914
2915 // We must currently not resume scripts at this stage since AttachmentsModule does not have the
2916 // information that this is due to a teleport/border cross rather than an ordinary attachment.
2917 // We currently do this in Scene.MakeRootAgent() instead.
2722 if (AttachmentsModule != null) 2918 if (AttachmentsModule != null)
2723 AttachmentsModule.AttachObject(sp, grp, 0, false, false); 2919 AttachmentsModule.AttachObject(sp, grp, 0, false, false, true);
2724 } 2920 }
2725 else 2921 else
2726 { 2922 {
@@ -2736,28 +2932,22 @@ namespace OpenSim.Region.Framework.Scenes
2736 return true; 2932 return true;
2737 } 2933 }
2738 2934
2739 private int GetStateSource(SceneObjectGroup sog)
2740 {
2741 ScenePresence sp = GetScenePresence(sog.OwnerID);
2742
2743 if (sp != null)
2744 return sp.GetStateSource();
2745
2746 return 2; // StateSource.PrimCrossing
2747 }
2748
2749 #endregion 2935 #endregion
2750 2936
2751 #region Add/Remove Avatar Methods 2937 #region Add/Remove Avatar Methods
2752 2938
2753 public override ISceneAgent AddNewClient(IClientAPI client, PresenceType type) 2939 public override ISceneAgent AddNewAgent(IClientAPI client, PresenceType type)
2754 { 2940 {
2755 ScenePresence sp; 2941 ScenePresence sp;
2756 bool vialogin; 2942 bool vialogin;
2943 bool reallyNew = true;
2944
2945 // Update the number of users attempting to login
2946 StatsReporter.UpdateUsersLoggingIn(true);
2757 2947
2758 // Validation occurs in LLUDPServer 2948 // Validation occurs in LLUDPServer
2759 // 2949 //
2760 // XXX: A race condition exists here where two simultaneous calls to AddNewClient can interfere with 2950 // XXX: A race condition exists here where two simultaneous calls to AddNewAgent can interfere with
2761 // each other. In practice, this does not currently occur in the code. 2951 // each other. In practice, this does not currently occur in the code.
2762 AgentCircuitData aCircuit = m_authenticateHandler.GetAgentCircuitData(client.CircuitCode); 2952 AgentCircuitData aCircuit = m_authenticateHandler.GetAgentCircuitData(client.CircuitCode);
2763 2953
@@ -2765,9 +2955,9 @@ namespace OpenSim.Region.Framework.Scenes
2765 // and a simultaneous one that removes it (as can happen if the client is closed at a particular point 2955 // and a simultaneous one that removes it (as can happen if the client is closed at a particular point
2766 // whilst connecting). 2956 // whilst connecting).
2767 // 2957 //
2768 // It would be easier to lock across all NewUserConnection(), AddNewClient() and 2958 // It would be easier to lock across all NewUserConnection(), AddNewAgent() and
2769 // RemoveClient() calls for all agents, but this would allow a slow call (e.g. because of slow service 2959 // RemoveClient() calls for all agents, but this would allow a slow call (e.g. because of slow service
2770 // response in some module listening to AddNewClient()) from holding up unrelated agent calls. 2960 // response in some module listening to AddNewAgent()) from holding up unrelated agent calls.
2771 // 2961 //
2772 // In practice, the lock (this) in LLUDPServer.AddNewClient() currently lock across all 2962 // In practice, the lock (this) in LLUDPServer.AddNewClient() currently lock across all
2773 // AddNewClient() operations (though not other ops). 2963 // AddNewClient() operations (though not other ops).
@@ -2777,68 +2967,90 @@ namespace OpenSim.Region.Framework.Scenes
2777 vialogin 2967 vialogin
2778 = (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0 2968 = (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0
2779 || (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaLogin) != 0; 2969 || (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaLogin) != 0;
2780 2970
2781 // CheckHeartbeat(); 2971 // CheckHeartbeat();
2782 2972
2783 sp = GetScenePresence(client.AgentId); 2973 sp = GetScenePresence(client.AgentId);
2784 2974
2785 // XXX: Not sure how good it is to add a new client if a scene presence already exists. Possibly this 2975 // XXX: Not sure how good it is to add a new client if a scene presence already exists. Possibly this
2786 // could occur if a viewer crashes and relogs before the old client is kicked out. But this could cause 2976 // could occur if a viewer crashes and relogs before the old client is kicked out. But this could cause
2787 // other problems, and possible the code calling AddNewClient() should ensure that no client is already 2977 // other problems, and possibly the code calling AddNewAgent() should ensure that no client is already
2788 // connected. 2978 // connected.
2789 if (sp == null) 2979 if (sp == null)
2790 { 2980 {
2791 m_log.DebugFormat( 2981 m_log.DebugFormat(
2792 "[SCENE]: Adding new child scene presence {0} {1} to scene {2} at pos {3}", 2982 "[SCENE]: Adding new child scene presence {0} {1} to scene {2} at pos {3}",
2793 client.Name, client.AgentId, RegionInfo.RegionName, client.StartPos); 2983 client.Name, client.AgentId, RegionInfo.RegionName, client.StartPos);
2794 2984
2985 sp = m_sceneGraph.CreateAndAddChildScenePresence(client, aCircuit.Appearance, type);
2986
2987 // We must set this here so that TriggerOnNewClient and TriggerOnClientLogin can determine whether the
2988 // client is for a root or child agent.
2989 // We must also set this before adding the client to the client manager so that an exception later on
2990 // does not leave a client manager entry without the scene agent set, which will cause other code
2991 // to fail since any entry in the client manager should have a ScenePresence
2992 //
2993 // XXX: This may be better set for a new client before that client is added to the client manager.
2994 // But need to know what happens in the case where a ScenePresence is already present (and if this
2995 // actually occurs).
2996 client.SceneAgent = sp;
2997
2795 m_clientManager.Add(client); 2998 m_clientManager.Add(client);
2796 SubscribeToClientEvents(client); 2999 SubscribeToClientEvents(client);
2797
2798 sp = m_sceneGraph.CreateAndAddChildScenePresence(client, aCircuit.Appearance, type);
2799 m_eventManager.TriggerOnNewPresence(sp); 3000 m_eventManager.TriggerOnNewPresence(sp);
2800 3001
2801 sp.TeleportFlags = (TPFlags)aCircuit.teleportFlags; 3002 sp.TeleportFlags = (TPFlags)aCircuit.teleportFlags;
2802
2803 // The first agent upon login is a root agent by design.
2804 // For this agent we will have to rez the attachments.
2805 // All other AddNewClient calls find aCircuit.child to be true.
2806 if (aCircuit.child == false)
2807 {
2808 // We have to set SP to be a root agent here so that SP.MakeRootAgent() will later not try to
2809 // start the scripts again (since this is done in RezAttachments()).
2810 // XXX: This is convoluted.
2811 sp.IsChildAgent = false;
2812
2813 if (AttachmentsModule != null)
2814 Util.FireAndForget(delegate(object o) { AttachmentsModule.RezAttachments(sp); });
2815 }
2816 } 3003 }
2817 else 3004 else
2818 { 3005 {
3006 // We must set this here so that TriggerOnNewClient and TriggerOnClientLogin can determine whether the
3007 // client is for a root or child agent.
3008 // XXX: This may be better set for a new client before that client is added to the client manager.
3009 // But need to know what happens in the case where a ScenePresence is already present (and if this
3010 // actually occurs).
3011 client.SceneAgent = sp;
3012
2819 m_log.WarnFormat( 3013 m_log.WarnFormat(
2820 "[SCENE]: Already found {0} scene presence for {1} in {2} when asked to add new scene presence", 3014 "[SCENE]: Already found {0} scene presence for {1} in {2} when asked to add new scene presence",
2821 sp.IsChildAgent ? "child" : "root", sp.Name, RegionInfo.RegionName); 3015 sp.IsChildAgent ? "child" : "root", sp.Name, RegionInfo.RegionName);
3016
3017 reallyNew = false;
2822 } 3018 }
2823
2824 // We must set this here so that TriggerOnNewClient and TriggerOnClientLogin can determine whether the
2825 // client is for a root or child agent.
2826 client.SceneAgent = sp;
2827 3019
2828 // Cache the user's name 3020 // This is currently also being done earlier in NewUserConnection for real users to see if this
3021 // resolves problems where HG agents are occasionally seen by others as "Unknown user" in chat and other
3022 // places. However, we still need to do it here for NPCs.
2829 CacheUserName(sp, aCircuit); 3023 CacheUserName(sp, aCircuit);
2830 3024
2831 EventManager.TriggerOnNewClient(client); 3025 if (reallyNew)
3026 EventManager.TriggerOnNewClient(client);
3027
2832 if (vialogin) 3028 if (vialogin)
2833 EventManager.TriggerOnClientLogin(client); 3029 EventManager.TriggerOnClientLogin(client);
2834 } 3030 }
2835 3031
3032 // User has logged into the scene so update the list of users logging
3033 // in
3034 StatsReporter.UpdateUsersLoggingIn(false);
3035
2836 m_LastLogin = Util.EnvironmentTickCount(); 3036 m_LastLogin = Util.EnvironmentTickCount();
2837 3037
2838 return sp; 3038 return sp;
2839 } 3039 }
2840 3040
2841 /// <summary> 3041 /// <summary>
3042 /// Returns the Home URI of the agent, or null if unknown.
3043 /// </summary>
3044 public string GetAgentHomeURI(UUID agentID)
3045 {
3046 AgentCircuitData circuit = AuthenticateHandler.GetAgentCircuitData(agentID);
3047 if (circuit != null && circuit.ServiceURLs != null && circuit.ServiceURLs.ContainsKey("HomeURI"))
3048 return circuit.ServiceURLs["HomeURI"].ToString();
3049 else
3050 return null;
3051 }
3052
3053 /// <summary>
2842 /// Cache the user name for later use. 3054 /// Cache the user name for later use.
2843 /// </summary> 3055 /// </summary>
2844 /// <param name="sp"></param> 3056 /// <param name="sp"></param>
@@ -2849,7 +3061,7 @@ namespace OpenSim.Region.Framework.Scenes
2849 { 3061 {
2850 string first = aCircuit.firstname, last = aCircuit.lastname; 3062 string first = aCircuit.firstname, last = aCircuit.lastname;
2851 3063
2852 if (sp.PresenceType == PresenceType.Npc) 3064 if (sp != null && sp.PresenceType == PresenceType.Npc)
2853 { 3065 {
2854 UserManagementModule.AddUser(aCircuit.AgentID, first, last); 3066 UserManagementModule.AddUser(aCircuit.AgentID, first, last);
2855 } 3067 }
@@ -2878,7 +3090,7 @@ namespace OpenSim.Region.Framework.Scenes
2878 private bool VerifyClient(AgentCircuitData aCircuit, System.Net.IPEndPoint ep, out bool vialogin) 3090 private bool VerifyClient(AgentCircuitData aCircuit, System.Net.IPEndPoint ep, out bool vialogin)
2879 { 3091 {
2880 vialogin = false; 3092 vialogin = false;
2881 3093
2882 // Do the verification here 3094 // Do the verification here
2883 if ((aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0) 3095 if ((aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0)
2884 { 3096 {
@@ -2929,7 +3141,7 @@ namespace OpenSim.Region.Framework.Scenes
2929 { 3141 {
2930 PresenceService.LogoutAgent(sp.ControllingClient.SessionId); 3142 PresenceService.LogoutAgent(sp.ControllingClient.SessionId);
2931 3143
2932 sp.ControllingClient.Close(); 3144 CloseAgent(sp.UUID, false);
2933 } 3145 }
2934 else 3146 else
2935 { 3147 {
@@ -2973,7 +3185,7 @@ namespace OpenSim.Region.Framework.Scenes
2973 { 3185 {
2974 client.OnRegionHandShakeReply += SendLayerData; 3186 client.OnRegionHandShakeReply += SendLayerData;
2975 } 3187 }
2976 3188
2977 public virtual void SubscribeToClientPrimEvents(IClientAPI client) 3189 public virtual void SubscribeToClientPrimEvents(IClientAPI client)
2978 { 3190 {
2979 client.OnUpdatePrimGroupPosition += m_sceneGraph.UpdatePrimGroupPosition; 3191 client.OnUpdatePrimGroupPosition += m_sceneGraph.UpdatePrimGroupPosition;
@@ -2983,7 +3195,7 @@ namespace OpenSim.Region.Framework.Scenes
2983 client.OnUpdatePrimGroupMouseRotation += m_sceneGraph.UpdatePrimGroupRotation; 3195 client.OnUpdatePrimGroupMouseRotation += m_sceneGraph.UpdatePrimGroupRotation;
2984 client.OnUpdatePrimSingleRotation += m_sceneGraph.UpdatePrimSingleRotation; 3196 client.OnUpdatePrimSingleRotation += m_sceneGraph.UpdatePrimSingleRotation;
2985 client.OnUpdatePrimSingleRotationPosition += m_sceneGraph.UpdatePrimSingleRotationPosition; 3197 client.OnUpdatePrimSingleRotationPosition += m_sceneGraph.UpdatePrimSingleRotationPosition;
2986 3198
2987 client.OnUpdatePrimScale += m_sceneGraph.UpdatePrimScale; 3199 client.OnUpdatePrimScale += m_sceneGraph.UpdatePrimScale;
2988 client.OnUpdatePrimGroupScale += m_sceneGraph.UpdatePrimGroupScale; 3200 client.OnUpdatePrimGroupScale += m_sceneGraph.UpdatePrimGroupScale;
2989 client.OnUpdateExtraParams += m_sceneGraph.UpdateExtraParam; 3201 client.OnUpdateExtraParams += m_sceneGraph.UpdateExtraParam;
@@ -2996,7 +3208,7 @@ namespace OpenSim.Region.Framework.Scenes
2996 client.OnSpinStart += m_sceneGraph.SpinStart; 3208 client.OnSpinStart += m_sceneGraph.SpinStart;
2997 client.OnSpinUpdate += m_sceneGraph.SpinObject; 3209 client.OnSpinUpdate += m_sceneGraph.SpinObject;
2998 client.OnDeRezObject += DeRezObjects; 3210 client.OnDeRezObject += DeRezObjects;
2999 3211
3000 client.OnObjectName += m_sceneGraph.PrimName; 3212 client.OnObjectName += m_sceneGraph.PrimName;
3001 client.OnObjectClickAction += m_sceneGraph.PrimClickAction; 3213 client.OnObjectClickAction += m_sceneGraph.PrimClickAction;
3002 client.OnObjectMaterial += m_sceneGraph.PrimMaterial; 3214 client.OnObjectMaterial += m_sceneGraph.PrimMaterial;
@@ -3008,7 +3220,7 @@ namespace OpenSim.Region.Framework.Scenes
3008 client.OnRequestObjectPropertiesFamily += m_sceneGraph.RequestObjectPropertiesFamily; 3220 client.OnRequestObjectPropertiesFamily += m_sceneGraph.RequestObjectPropertiesFamily;
3009 client.OnObjectPermissions += HandleObjectPermissionsUpdate; 3221 client.OnObjectPermissions += HandleObjectPermissionsUpdate;
3010 client.OnGrabObject += ProcessObjectGrab; 3222 client.OnGrabObject += ProcessObjectGrab;
3011 client.OnGrabUpdate += ProcessObjectGrabUpdate; 3223 client.OnGrabUpdate += ProcessObjectGrabUpdate;
3012 client.OnDeGrabObject += ProcessObjectDeGrab; 3224 client.OnDeGrabObject += ProcessObjectDeGrab;
3013 client.OnUndo += m_sceneGraph.HandleUndo; 3225 client.OnUndo += m_sceneGraph.HandleUndo;
3014 client.OnRedo += m_sceneGraph.HandleRedo; 3226 client.OnRedo += m_sceneGraph.HandleRedo;
@@ -3068,10 +3280,8 @@ namespace OpenSim.Region.Framework.Scenes
3068 { 3280 {
3069 //client.OnNameFromUUIDRequest += HandleUUIDNameRequest; 3281 //client.OnNameFromUUIDRequest += HandleUUIDNameRequest;
3070 client.OnMoneyTransferRequest += ProcessMoneyTransferRequest; 3282 client.OnMoneyTransferRequest += ProcessMoneyTransferRequest;
3071 client.OnSetStartLocationRequest += SetHomeRezPoint;
3072 client.OnRegionHandleRequest += RegionHandleRequest;
3073 } 3283 }
3074 3284
3075 public virtual void SubscribeToClientNetworkEvents(IClientAPI client) 3285 public virtual void SubscribeToClientNetworkEvents(IClientAPI client)
3076 { 3286 {
3077 client.OnNetworkStatsUpdate += StatsReporter.AddPacketsStats; 3287 client.OnNetworkStatsUpdate += StatsReporter.AddPacketsStats;
@@ -3193,8 +3403,6 @@ namespace OpenSim.Region.Framework.Scenes
3193 { 3403 {
3194 //client.OnNameFromUUIDRequest -= HandleUUIDNameRequest; 3404 //client.OnNameFromUUIDRequest -= HandleUUIDNameRequest;
3195 client.OnMoneyTransferRequest -= ProcessMoneyTransferRequest; 3405 client.OnMoneyTransferRequest -= ProcessMoneyTransferRequest;
3196 client.OnSetStartLocationRequest -= SetHomeRezPoint;
3197 client.OnRegionHandleRequest -= RegionHandleRequest;
3198 } 3406 }
3199 3407
3200 public virtual void UnSubscribeToClientNetworkEvents(IClientAPI client) 3408 public virtual void UnSubscribeToClientNetworkEvents(IClientAPI client)
@@ -3208,17 +3416,18 @@ namespace OpenSim.Region.Framework.Scenes
3208 /// </summary> 3416 /// </summary>
3209 /// <param name="agentId">The avatar's Unique ID</param> 3417 /// <param name="agentId">The avatar's Unique ID</param>
3210 /// <param name="client">The IClientAPI for the client</param> 3418 /// <param name="client">The IClientAPI for the client</param>
3211 public virtual void TeleportClientHome(UUID agentId, IClientAPI client) 3419 public virtual bool TeleportClientHome(UUID agentId, IClientAPI client)
3212 { 3420 {
3213 if (EntityTransferModule != null) 3421 if (EntityTransferModule != null)
3214 { 3422 {
3215 EntityTransferModule.TeleportHome(agentId, client); 3423 return EntityTransferModule.TeleportHome(agentId, client);
3216 } 3424 }
3217 else 3425 else
3218 { 3426 {
3219 m_log.DebugFormat("[SCENE]: Unable to teleport user home: no AgentTransferModule is active"); 3427 m_log.DebugFormat("[SCENE]: Unable to teleport user home: no AgentTransferModule is active");
3220 client.SendTeleportFailed("Unable to perform teleports on this simulator."); 3428 client.SendTeleportFailed("Unable to perform teleports on this simulator.");
3221 } 3429 }
3430 return false;
3222 } 3431 }
3223 3432
3224 /// <summary> 3433 /// <summary>
@@ -3264,8 +3473,8 @@ namespace OpenSim.Region.Framework.Scenes
3264 if (target != null && target2 != null) 3473 if (target != null && target2 != null)
3265 { 3474 {
3266 Vector3 direction = Vector3.Normalize(RayEnd - RayStart); 3475 Vector3 direction = Vector3.Normalize(RayEnd - RayStart);
3267 Vector3 AXOrigin = new Vector3(RayStart.X, RayStart.Y, RayStart.Z); 3476 Vector3 AXOrigin = RayStart;
3268 Vector3 AXdirection = new Vector3(direction.X, direction.Y, direction.Z); 3477 Vector3 AXdirection = direction;
3269 3478
3270 pos = target2.AbsolutePosition; 3479 pos = target2.AbsolutePosition;
3271 //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()); 3480 //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
3286 if (ei.HitTF) 3495 if (ei.HitTF)
3287 { 3496 {
3288 Vector3 scale = target.Scale; 3497 Vector3 scale = target.Scale;
3289 Vector3 scaleComponent = new Vector3(ei.AAfaceNormal.X, ei.AAfaceNormal.Y, ei.AAfaceNormal.Z); 3498 Vector3 scaleComponent = ei.AAfaceNormal;
3290 if (scaleComponent.X != 0) ScaleOffset = scale.X; 3499 if (scaleComponent.X != 0) ScaleOffset = scale.X;
3291 if (scaleComponent.Y != 0) ScaleOffset = scale.Y; 3500 if (scaleComponent.Y != 0) ScaleOffset = scale.Y;
3292 if (scaleComponent.Z != 0) ScaleOffset = scale.Z; 3501 if (scaleComponent.Z != 0) ScaleOffset = scale.Z;
3293 ScaleOffset = Math.Abs(ScaleOffset); 3502 ScaleOffset = Math.Abs(ScaleOffset);
3294 Vector3 intersectionpoint = new Vector3(ei.ipoint.X, ei.ipoint.Y, ei.ipoint.Z); 3503 Vector3 intersectionpoint = ei.ipoint;
3295 Vector3 normal = new Vector3(ei.normal.X, ei.normal.Y, ei.normal.Z); 3504 Vector3 normal = ei.normal;
3296 Vector3 offset = normal * (ScaleOffset / 2f); 3505 Vector3 offset = normal * (ScaleOffset / 2f);
3297 pos = intersectionpoint + offset; 3506 pos = intersectionpoint + offset;
3298 3507
@@ -3312,6 +3521,7 @@ namespace OpenSim.Region.Framework.Scenes
3312 { 3521 {
3313 copy = m_sceneGraph.DuplicateObject(localID, pos, target.GetEffectiveObjectFlags(), AgentID, GroupID, Quaternion.Identity); 3522 copy = m_sceneGraph.DuplicateObject(localID, pos, target.GetEffectiveObjectFlags(), AgentID, GroupID, Quaternion.Identity);
3314 } 3523 }
3524
3315 if (copy != null) 3525 if (copy != null)
3316 EventManager.TriggerObjectAddedToScene(copy); 3526 EventManager.TriggerObjectAddedToScene(copy);
3317 } 3527 }
@@ -3319,24 +3529,7 @@ namespace OpenSim.Region.Framework.Scenes
3319 } 3529 }
3320 3530
3321 /// <summary> 3531 /// <summary>
3322 /// Sets the Home Point. The LoginService uses this to know where to put a user when they log-in 3532 /// Get the avatar appearance for the given client.
3323 /// </summary>
3324 /// <param name="remoteClient"></param>
3325 /// <param name="regionHandle"></param>
3326 /// <param name="position"></param>
3327 /// <param name="lookAt"></param>
3328 /// <param name="flags"></param>
3329 public virtual void SetHomeRezPoint(IClientAPI remoteClient, ulong regionHandle, Vector3 position, Vector3 lookAt, uint flags)
3330 {
3331 if (GridUserService != null && GridUserService.SetHome(remoteClient.AgentId.ToString(), RegionInfo.RegionID, position, lookAt))
3332 // FUBAR ALERT: this needs to be "Home position set." so the viewer saves a home-screenshot.
3333 m_dialogModule.SendAlertToUser(remoteClient, "Home position set.");
3334 else
3335 m_dialogModule.SendAlertToUser(remoteClient, "Set Home request Failed.");
3336 }
3337
3338 /// <summary>
3339 /// Get the avatar apperance for the given client.
3340 /// </summary> 3533 /// </summary>
3341 /// <param name="client"></param> 3534 /// <param name="client"></param>
3342 /// <param name="appearance"></param> 3535 /// <param name="appearance"></param>
@@ -3359,93 +3552,93 @@ namespace OpenSim.Region.Framework.Scenes
3359 } 3552 }
3360 } 3553 }
3361 3554
3362 public override void RemoveClient(UUID agentID, bool closeChildAgents) 3555 /// <summary>
3556 /// Remove the given client from the scene.
3557 /// </summary>
3558 /// <remarks>
3559 /// Only clientstack code should call this directly. All other code should call IncomingCloseAgent() instead
3560 /// to properly operate the state machine and avoid race conditions with other close requests (such as directly
3561 /// from viewers).
3562 /// </remarks>
3563 /// <param name='agentID'>ID of agent to close</param>
3564 /// <param name='closeChildAgents'>
3565 /// Close the neighbour child agents associated with this client.
3566 /// </param>
3567 public void RemoveClient(UUID agentID, bool closeChildAgents)
3363 { 3568 {
3364// CheckHeartbeat(); 3569 AgentCircuitData acd = m_authenticateHandler.GetAgentCircuitData(agentID);
3365 bool isChildAgent = false;
3366 AgentCircuitData acd;
3367 3570
3368 lock (m_removeClientLock) 3571 // Shouldn't be necessary since RemoveClient() is currently only called by IClientAPI.Close() which
3572 // in turn is only called by Scene.IncomingCloseAgent() which checks whether the presence exists or not
3573 // However, will keep for now just in case.
3574 if (acd == null)
3369 { 3575 {
3370 acd = m_authenticateHandler.GetAgentCircuitData(agentID); 3576 m_log.ErrorFormat(
3577 "[SCENE]: No agent circuit found for {0} in {1}, aborting Scene.RemoveClient", agentID, Name);
3371 3578
3372 if (acd == null) 3579 return;
3373 {
3374 m_log.ErrorFormat("[SCENE]: No agent circuit found for {0}, aborting Scene.RemoveClient", agentID);
3375 return;
3376 }
3377 else
3378 {
3379 // We remove the acd up here to avoid later race conditions if two RemoveClient() calls occurred
3380 // simultaneously.
3381 // We also need to remove by agent ID since NPCs will have no circuit code.
3382 m_authenticateHandler.RemoveCircuit(agentID);
3383 }
3384 } 3580 }
3385 3581
3582 // TODO: Can we now remove this lock?
3386 lock (acd) 3583 lock (acd)
3387 { 3584 {
3585 bool isChildAgent = false;
3586
3388 ScenePresence avatar = GetScenePresence(agentID); 3587 ScenePresence avatar = GetScenePresence(agentID);
3389 3588
3589 // Shouldn't be necessary since RemoveClient() is currently only called by IClientAPI.Close() which
3590 // in turn is only called by Scene.IncomingCloseAgent() which checks whether the presence exists or not
3591 // However, will keep for now just in case.
3390 if (avatar == null) 3592 if (avatar == null)
3391 { 3593 {
3392 m_log.WarnFormat( 3594 m_log.ErrorFormat(
3393 "[SCENE]: Called RemoveClient() with agent ID {0} but no such presence is in the scene.", agentID); 3595 "[SCENE]: Called RemoveClient() with agent ID {0} but no such presence is in the scene.", agentID);
3394 3596 m_authenticateHandler.RemoveCircuit(agentID);
3597
3395 return; 3598 return;
3396 } 3599 }
3397 3600
3398 try 3601 try
3399 { 3602 {
3400 isChildAgent = avatar.IsChildAgent; 3603 isChildAgent = avatar.IsChildAgent;
3401 3604
3402 m_log.DebugFormat( 3605 m_log.DebugFormat(
3403 "[SCENE]: Removing {0} agent {1} {2} from {3}", 3606 "[SCENE]: Removing {0} agent {1} {2} from {3}",
3404 (isChildAgent ? "child" : "root"), avatar.Name, agentID, RegionInfo.RegionName); 3607 isChildAgent ? "child" : "root", avatar.Name, agentID, Name);
3405 3608
3406 // Don't do this to root agents, it's not nice for the viewer 3609 // Don't do this to root agents, it's not nice for the viewer
3407 if (closeChildAgents && isChildAgent) 3610 if (closeChildAgents && isChildAgent)
3408 { 3611 {
3409 // Tell a single agent to disconnect from the region. 3612 // Tell a single agent to disconnect from the region.
3410 IEventQueue eq = RequestModuleInterface<IEventQueue>(); 3613 // Let's do this via UDP
3411 if (eq != null) 3614 avatar.ControllingClient.SendShutdownConnectionNotice();
3412 {
3413 eq.DisableSimulator(RegionInfo.RegionHandle, avatar.UUID);
3414 }
3415 else
3416 {
3417 avatar.ControllingClient.SendShutdownConnectionNotice();
3418 }
3419 } 3615 }
3420 3616
3421 // Only applies to root agents. 3617 // Only applies to root agents.
3422 if (avatar.ParentID != 0) 3618 if (avatar.ParentID != 0)
3423 { 3619 {
3424 avatar.StandUp(); 3620 avatar.StandUp();
3425 } 3621 }
3426 3622
3427 m_sceneGraph.removeUserCount(!isChildAgent); 3623 m_sceneGraph.removeUserCount(!isChildAgent);
3428 3624
3429 // TODO: We shouldn't use closeChildAgents here - it's being used by the NPC module to stop 3625 // TODO: We shouldn't use closeChildAgents here - it's being used by the NPC module to stop
3430 // unnecessary operations. This should go away once NPCs have no accompanying IClientAPI 3626 // unnecessary operations. This should go away once NPCs have no accompanying IClientAPI
3431 if (closeChildAgents && CapsModule != null) 3627 if (closeChildAgents && CapsModule != null)
3432 CapsModule.RemoveCaps(agentID); 3628 CapsModule.RemoveCaps(agentID);
3433 3629
3434// // REFACTORING PROBLEM -- well not really a problem, but just to point out that whatever
3435// // this method is doing is HORRIBLE!!!
3436 // Commented pending deletion since this method no longer appears to do anything at all
3437// avatar.Scene.NeedSceneCacheClear(avatar.UUID);
3438
3439 if (closeChildAgents && !isChildAgent) 3630 if (closeChildAgents && !isChildAgent)
3440 { 3631 {
3441 List<ulong> regions = avatar.KnownRegionHandles; 3632 List<ulong> regions = avatar.KnownRegionHandles;
3442 regions.Remove(RegionInfo.RegionHandle); 3633 regions.Remove(RegionInfo.RegionHandle);
3443 m_sceneGridService.SendCloseChildAgentConnections(agentID, regions); 3634
3635 // This ends up being done asynchronously so that a logout isn't held up where there are many present but unresponsive neighbours.
3636 m_sceneGridService.SendCloseChildAgentConnections(agentID, acd.SessionID.ToString(), regions);
3444 } 3637 }
3445 3638
3446 m_eventManager.TriggerClientClosed(agentID, this); 3639 m_eventManager.TriggerClientClosed(agentID, this);
3447 m_eventManager.TriggerOnRemovePresence(agentID); 3640 m_eventManager.TriggerOnRemovePresence(agentID);
3448 3641
3449 if (!isChildAgent) 3642 if (!isChildAgent)
3450 { 3643 {
3451 if (AttachmentsModule != null) 3644 if (AttachmentsModule != null)
@@ -3457,11 +3650,11 @@ namespace OpenSim.Region.Framework.Scenes
3457 delegate(IClientAPI client) 3650 delegate(IClientAPI client)
3458 { 3651 {
3459 //We can safely ignore null reference exceptions. It means the avatar is dead and cleaned up anyway 3652 //We can safely ignore null reference exceptions. It means the avatar is dead and cleaned up anyway
3460 try { client.SendKillObject(avatar.RegionHandle, new List<uint> { avatar.LocalId }); } 3653 try { client.SendKillObject(new List<uint> { avatar.LocalId }); }
3461 catch (NullReferenceException) { } 3654 catch (NullReferenceException) { }
3462 }); 3655 });
3463 } 3656 }
3464 3657
3465 // It's possible for child agents to have transactions if changes are being made cross-border. 3658 // It's possible for child agents to have transactions if changes are being made cross-border.
3466 if (AgentTransactionsModule != null) 3659 if (AgentTransactionsModule != null)
3467 AgentTransactionsModule.RemoveAgentAssetTransactions(agentID); 3660 AgentTransactionsModule.RemoveAgentAssetTransactions(agentID);
@@ -3478,9 +3671,10 @@ namespace OpenSim.Region.Framework.Scenes
3478 // Always clean these structures up so that any failure above doesn't cause them to remain in the 3671 // Always clean these structures up so that any failure above doesn't cause them to remain in the
3479 // scene with possibly bad effects (e.g. continually timing out on unacked packets and triggering 3672 // scene with possibly bad effects (e.g. continually timing out on unacked packets and triggering
3480 // the same cleanup exception continually. 3673 // the same cleanup exception continually.
3674 m_authenticateHandler.RemoveCircuit(agentID);
3481 m_sceneGraph.RemoveScenePresence(agentID); 3675 m_sceneGraph.RemoveScenePresence(agentID);
3482 m_clientManager.Remove(agentID); 3676 m_clientManager.Remove(agentID);
3483 3677
3484 avatar.Close(); 3678 avatar.Close();
3485 } 3679 }
3486 catch (Exception e) 3680 catch (Exception e)
@@ -3537,7 +3731,8 @@ namespace OpenSim.Region.Framework.Scenes
3537 } 3731 }
3538 deleteIDs.Add(localID); 3732 deleteIDs.Add(localID);
3539 } 3733 }
3540 ForEachClient(delegate(IClientAPI client) { client.SendKillObject(m_regionHandle, deleteIDs); }); 3734
3735 ForEachClient(c => c.SendKillObject(deleteIDs));
3541 } 3736 }
3542 3737
3543 #endregion 3738 #endregion
@@ -3549,12 +3744,13 @@ namespace OpenSim.Region.Framework.Scenes
3549 /// </summary> 3744 /// </summary>
3550 /// <param name="agent">CircuitData of the agent who is connecting</param> 3745 /// <param name="agent">CircuitData of the agent who is connecting</param>
3551 /// <param name="teleportFlags"></param> 3746 /// <param name="teleportFlags"></param>
3747 /// <param name="source">Source region (may be null)</param>
3552 /// <param name="reason">Outputs the reason for the false response on this string</param> 3748 /// <param name="reason">Outputs the reason for the false response on this string</param>
3553 /// <returns>True if the region accepts this agent. False if it does not. False will 3749 /// <returns>True if the region accepts this agent. False if it does not. False will
3554 /// also return a reason.</returns> 3750 /// also return a reason.</returns>
3555 public bool NewUserConnection(AgentCircuitData agent, uint teleportFlags, out string reason) 3751 public bool NewUserConnection(AgentCircuitData agent, uint teleportFlags, GridRegion source, out string reason)
3556 { 3752 {
3557 return NewUserConnection(agent, teleportFlags, out reason, true); 3753 return NewUserConnection(agent, teleportFlags, source, out reason, true);
3558 } 3754 }
3559 3755
3560 /// <summary> 3756 /// <summary>
@@ -3573,13 +3769,14 @@ namespace OpenSim.Region.Framework.Scenes
3573 /// is activated later when the viewer sends the initial UseCircuitCodePacket UDP packet (in the case of 3769 /// is activated later when the viewer sends the initial UseCircuitCodePacket UDP packet (in the case of
3574 /// the LLUDP stack). 3770 /// the LLUDP stack).
3575 /// </remarks> 3771 /// </remarks>
3576 /// <param name="agent">CircuitData of the agent who is connecting</param> 3772 /// <param name="acd">CircuitData of the agent who is connecting</param>
3773 /// <param name="source">Source region (may be null)</param>
3577 /// <param name="reason">Outputs the reason for the false response on this string</param> 3774 /// <param name="reason">Outputs the reason for the false response on this string</param>
3578 /// <param name="requirePresenceLookup">True for normal presence. False for NPC 3775 /// <param name="requirePresenceLookup">True for normal presence. False for NPC
3579 /// or other applications where a full grid/Hypergrid presence may not be required.</param> 3776 /// or other applications where a full grid/Hypergrid presence may not be required.</param>
3580 /// <returns>True if the region accepts this agent. False if it does not. False will 3777 /// <returns>True if the region accepts this agent. False if it does not. False will
3581 /// also return a reason.</returns> 3778 /// also return a reason.</returns>
3582 public bool NewUserConnection(AgentCircuitData agent, uint teleportFlags, out string reason, bool requirePresenceLookup) 3779 public bool NewUserConnection(AgentCircuitData acd, uint teleportFlags, GridRegion source, out string reason, bool requirePresenceLookup)
3583 { 3780 {
3584 bool vialogin = ((teleportFlags & (uint)TPFlags.ViaLogin) != 0 || 3781 bool vialogin = ((teleportFlags & (uint)TPFlags.ViaLogin) != 0 ||
3585 (teleportFlags & (uint)TPFlags.ViaHGLogin) != 0); 3782 (teleportFlags & (uint)TPFlags.ViaHGLogin) != 0);
@@ -3596,18 +3793,20 @@ namespace OpenSim.Region.Framework.Scenes
3596 // TeleportFlags.ViaLandmark | TeleportFlags.ViaLocation | TeleportFlags.ViaLandmark | TeleportFlags.Default - Regular Teleport 3793 // TeleportFlags.ViaLandmark | TeleportFlags.ViaLocation | TeleportFlags.ViaLandmark | TeleportFlags.Default - Regular Teleport
3597 3794
3598 // Don't disable this log message - it's too helpful 3795 // Don't disable this log message - it's too helpful
3796 string curViewer = Util.GetViewerName(acd);
3599 m_log.DebugFormat( 3797 m_log.DebugFormat(
3600 "[SCENE]: Region {0} told of incoming {1} agent {2} {3} {4} (circuit code {5}, IP {6}, viewer {7}, teleportflags ({8}), position {9})", 3798 "[SCENE]: Region {0} told of incoming {1} agent {2} {3} {4} (circuit code {5}, IP {6}, viewer {7}, teleportflags ({8}), position {9}. {10}",
3601 RegionInfo.RegionName, 3799 RegionInfo.RegionName,
3602 (agent.child ? "child" : "root"), 3800 (acd.child ? "child" : "root"),
3603 agent.firstname, 3801 acd.firstname,
3604 agent.lastname, 3802 acd.lastname,
3605 agent.AgentID, 3803 acd.AgentID,
3606 agent.circuitcode, 3804 acd.circuitcode,
3607 agent.IPAddress, 3805 acd.IPAddress,
3608 agent.Viewer, 3806 curViewer,
3609 ((TPFlags)teleportFlags).ToString(), 3807 ((TPFlags)teleportFlags).ToString(),
3610 agent.startpos 3808 acd.startpos,
3809 (source == null) ? "" : string.Format("From region {0} ({1}){2}", source.RegionName, source.RegionID, (source.RawServerURI == null) ? "" : " @ " + source.ServerURI)
3611 ); 3810 );
3612 3811
3613 if (!LoginsEnabled) 3812 if (!LoginsEnabled)
@@ -3625,7 +3824,7 @@ namespace OpenSim.Region.Framework.Scenes
3625 { 3824 {
3626 foreach (string viewer in m_AllowedViewers) 3825 foreach (string viewer in m_AllowedViewers)
3627 { 3826 {
3628 if (viewer == agent.Viewer.Substring(0, viewer.Length).Trim().ToLower()) 3827 if (viewer == curViewer.Substring(0, Math.Min(viewer.Length, curViewer.Length)).Trim().ToLower())
3629 { 3828 {
3630 ViewerDenied = false; 3829 ViewerDenied = false;
3631 break; 3830 break;
@@ -3642,7 +3841,7 @@ namespace OpenSim.Region.Framework.Scenes
3642 { 3841 {
3643 foreach (string viewer in m_BannedViewers) 3842 foreach (string viewer in m_BannedViewers)
3644 { 3843 {
3645 if (viewer == agent.Viewer.Substring(0, viewer.Length).Trim().ToLower()) 3844 if (viewer == curViewer.Substring(0, Math.Min(viewer.Length, curViewer.Length)).Trim().ToLower())
3646 { 3845 {
3647 ViewerDenied = true; 3846 ViewerDenied = true;
3648 break; 3847 break;
@@ -3654,81 +3853,178 @@ namespace OpenSim.Region.Framework.Scenes
3654 { 3853 {
3655 m_log.DebugFormat( 3854 m_log.DebugFormat(
3656 "[SCENE]: Access denied for {0} {1} using {2}", 3855 "[SCENE]: Access denied for {0} {1} using {2}",
3657 agent.firstname, agent.lastname, agent.Viewer); 3856 acd.firstname, acd.lastname, curViewer);
3658 reason = "Access denied, your viewer is banned by the region owner"; 3857 reason = "Access denied, your viewer is banned by the region owner";
3659 return false; 3858 return false;
3660 } 3859 }
3661 3860
3662 ILandObject land; 3861 ILandObject land;
3862 ScenePresence sp;
3663 3863
3664 lock (agent) 3864 lock (m_removeClientLock)
3665 { 3865 {
3666 ScenePresence sp = GetScenePresence(agent.AgentID); 3866 sp = GetScenePresence(acd.AgentID);
3667 3867
3668 if (sp != null && !sp.IsChildAgent) 3868 // We need to ensure that we are not already removing the scene presence before we ask it not to be
3869 // closed.
3870 if (sp != null && sp.IsChildAgent
3871 && (sp.LifecycleState == ScenePresenceState.Running
3872 || sp.LifecycleState == ScenePresenceState.PreRemove))
3873 {
3874 m_log.DebugFormat(
3875 "[SCENE]: Reusing existing child scene presence for {0}, state {1} in {2}",
3876 sp.Name, sp.LifecycleState, Name);
3877
3878 // In the case where, for example, an A B C D region layout, an avatar may
3879 // teleport from A -> D, but then -> C before A has asked B to close its old child agent. When C
3880 // renews the lease on the child agent at B, we must make sure that the close from A does not succeed.
3881 //
3882 // XXX: In the end, this should not be necessary if child agents are closed without delay on
3883 // teleport, since realistically, the close request should always be processed before any other
3884 // region tried to re-establish a child agent. This is much simpler since the logic below is
3885 // vulnerable to an issue when a viewer quits a region without sending a proper logout but then
3886 // re-establishes the connection on a relogin. This could wrongly set the DoNotCloseAfterTeleport
3887 // flag when no teleport had taken place (and hence no close was going to come).
3888// if (!acd.ChildrenCapSeeds.ContainsKey(RegionInfo.RegionHandle))
3889// {
3890// m_log.DebugFormat(
3891// "[SCENE]: Setting DoNotCloseAfterTeleport for child scene presence {0} in {1} because source will attempt close.",
3892// sp.Name, Name);
3893//
3894// sp.DoNotCloseAfterTeleport = true;
3895// }
3896// else if (EntityTransferModule.IsInTransit(sp.UUID))
3897
3898 sp.LifecycleState = ScenePresenceState.Running;
3899
3900 if (EntityTransferModule.IsInTransit(sp.UUID))
3901 {
3902 sp.DoNotCloseAfterTeleport = true;
3903
3904 m_log.DebugFormat(
3905 "[SCENE]: Set DoNotCloseAfterTeleport for child scene presence {0} in {1} because this region will attempt end-of-teleport close from a previous close.",
3906 sp.Name, Name);
3907 }
3908 }
3909 }
3910
3911 // Need to poll here in case we are currently deleting an sp. Letting threads run over each other will
3912 // allow unpredictable things to happen.
3913 if (sp != null)
3914 {
3915 const int polls = 10;
3916 const int pollInterval = 1000;
3917 int pollsLeft = polls;
3918
3919 while (sp.LifecycleState == ScenePresenceState.Removing && pollsLeft-- > 0)
3920 Thread.Sleep(pollInterval);
3921
3922 if (sp.LifecycleState == ScenePresenceState.Removing)
3669 { 3923 {
3670 // We have a zombie from a crashed session.
3671 // Or the same user is trying to be root twice here, won't work.
3672 // Kill it.
3673 m_log.WarnFormat( 3924 m_log.WarnFormat(
3674 "[SCENE]: Existing root scene presence detected for {0} {1} in {2} when connecting. Removing existing presence.", 3925 "[SCENE]: Agent {0} in {1} was still being removed after {2}s. Aborting NewUserConnection.",
3675 sp.Name, sp.UUID, RegionInfo.RegionName); 3926 sp.Name, Name, polls * pollInterval / 1000);
3676 3927
3677 sp.ControllingClient.Close(true); 3928 return false;
3678 sp = null; 3929 }
3679 } 3930 else if (polls != pollsLeft)
3680 3931 {
3681 land = LandChannel.GetLandObject(agent.startpos.X, agent.startpos.Y); 3932 m_log.DebugFormat(
3682 3933 "[SCENE]: NewUserConnection for agent {0} in {1} had to wait {2}s for in-progress removal to complete on an old presence.",
3683 //On login test land permisions 3934 sp.Name, Name, polls * pollInterval / 1000);
3935 }
3936 }
3937
3938 // TODO: can we remove this lock?
3939 lock (acd)
3940 {
3941 if (sp != null && !sp.IsChildAgent)
3942 {
3943 // We have a root agent. Is it in transit?
3944 if (!EntityTransferModule.IsInTransit(sp.UUID))
3945 {
3946 // We have a zombie from a crashed session.
3947 // Or the same user is trying to be root twice here, won't work.
3948 // Kill it.
3949 m_log.WarnFormat(
3950 "[SCENE]: Existing root scene presence detected for {0} {1} in {2} when connecting. Removing existing presence.",
3951 sp.Name, sp.UUID, RegionInfo.RegionName);
3952
3953 if (sp.ControllingClient != null)
3954 CloseAgent(sp.UUID, true);
3955
3956 sp = null;
3957 }
3958 //else
3959 // m_log.WarnFormat("[SCENE]: Existing root scene presence for {0} {1} in {2}, but agent is in trasit", sp.Name, sp.UUID, RegionInfo.RegionName);
3960 }
3961
3962 // Optimistic: add or update the circuit data with the new agent circuit data and teleport flags.
3963 // We need the circuit data here for some of the subsequent checks. (groups, for example)
3964 // If the checks fail, we remove the circuit.
3965 acd.teleportFlags = teleportFlags;
3966 m_authenticateHandler.AddNewCircuit(acd.circuitcode, acd);
3967
3968 land = LandChannel.GetLandObject(acd.startpos.X, acd.startpos.Y);
3969
3970 // On login test land permisions
3684 if (vialogin) 3971 if (vialogin)
3685 { 3972 {
3686 if (land != null && !TestLandRestrictions(agent, land, out reason)) 3973 if (land != null && !TestLandRestrictions(acd.AgentID, out reason, ref acd.startpos.X, ref acd.startpos.Y))
3687 { 3974 {
3975 m_authenticateHandler.RemoveCircuit(acd.circuitcode);
3688 return false; 3976 return false;
3689 } 3977 }
3690 } 3978 }
3691 3979
3692 if (sp == null) // We don't have an [child] agent here already 3980 if (sp == null) // We don't have an [child] agent here already
3693 { 3981 {
3694 if (requirePresenceLookup) 3982 if (requirePresenceLookup)
3695 { 3983 {
3696 try 3984 try
3697 { 3985 {
3698 if (!VerifyUserPresence(agent, out reason)) 3986 if (!VerifyUserPresence(acd, out reason))
3987 {
3988 m_authenticateHandler.RemoveCircuit(acd.circuitcode);
3699 return false; 3989 return false;
3990 }
3700 } 3991 }
3701 catch (Exception e) 3992 catch (Exception e)
3702 { 3993 {
3703 m_log.ErrorFormat( 3994 m_log.ErrorFormat(
3704 "[SCENE]: Exception verifying presence {0}{1}", e.Message, e.StackTrace); 3995 "[SCENE]: Exception verifying presence {0}{1}", e.Message, e.StackTrace);
3705 3996
3997 m_authenticateHandler.RemoveCircuit(acd.circuitcode);
3706 return false; 3998 return false;
3707 } 3999 }
3708 } 4000 }
3709 4001
3710 try 4002 try
3711 { 4003 {
3712 if (!AuthorizeUser(agent, out reason)) 4004 if (!AuthorizeUser(acd, (vialogin ? false : SeeIntoRegion), out reason))
4005 {
4006 m_authenticateHandler.RemoveCircuit(acd.circuitcode);
3713 return false; 4007 return false;
4008 }
3714 } 4009 }
3715 catch (Exception e) 4010 catch (Exception e)
3716 { 4011 {
3717 m_log.ErrorFormat( 4012 m_log.ErrorFormat(
3718 "[SCENE]: Exception authorizing user {0}{1}", e.Message, e.StackTrace); 4013 "[SCENE]: Exception authorizing user {0}{1}", e.Message, e.StackTrace);
3719 4014
4015 m_authenticateHandler.RemoveCircuit(acd.circuitcode);
3720 return false; 4016 return false;
3721 } 4017 }
3722 4018
3723 m_log.InfoFormat( 4019 m_log.InfoFormat(
3724 "[SCENE]: Region {0} authenticated and authorized incoming {1} agent {2} {3} {4} (circuit code {5})", 4020 "[SCENE]: Region {0} authenticated and authorized incoming {1} agent {2} {3} {4} (circuit code {5})",
3725 RegionInfo.RegionName, (agent.child ? "child" : "root"), agent.firstname, agent.lastname, 4021 Name, (acd.child ? "child" : "root"), acd.firstname, acd.lastname,
3726 agent.AgentID, agent.circuitcode); 4022 acd.AgentID, acd.circuitcode);
3727 4023
3728 if (CapsModule != null) 4024 if (CapsModule != null)
3729 { 4025 {
3730 CapsModule.SetAgentCapsSeeds(agent); 4026 CapsModule.SetAgentCapsSeeds(acd);
3731 CapsModule.CreateCaps(agent.AgentID); 4027 CapsModule.CreateCaps(acd.AgentID);
3732 } 4028 }
3733 } 4029 }
3734 else 4030 else
@@ -3736,83 +4032,42 @@ namespace OpenSim.Region.Framework.Scenes
3736 // Let the SP know how we got here. This has a lot of interesting 4032 // Let the SP know how we got here. This has a lot of interesting
3737 // uses down the line. 4033 // uses down the line.
3738 sp.TeleportFlags = (TPFlags)teleportFlags; 4034 sp.TeleportFlags = (TPFlags)teleportFlags;
3739 4035
3740 if (sp.IsChildAgent) 4036 if (sp.IsChildAgent)
3741 { 4037 {
3742 m_log.DebugFormat( 4038 m_log.DebugFormat(
3743 "[SCENE]: Adjusting known seeds for existing agent {0} in {1}", 4039 "[SCENE]: Adjusting known seeds for existing agent {0} in {1}",
3744 agent.AgentID, RegionInfo.RegionName); 4040 acd.AgentID, RegionInfo.RegionName);
3745 4041
3746 sp.AdjustKnownSeeds(); 4042 sp.AdjustKnownSeeds();
3747 4043
3748 if (CapsModule != null) 4044 if (CapsModule != null)
3749 CapsModule.SetAgentCapsSeeds(agent); 4045 {
4046 CapsModule.SetAgentCapsSeeds(acd);
4047 CapsModule.CreateCaps(acd.AgentID);
4048 }
3750 } 4049 }
3751 } 4050 }
3752 }
3753 4051
3754 // In all cases, add or update the circuit data with the new agent circuit data and teleport flags 4052 // Try caching an incoming user name much earlier on to see if this helps with an issue
3755 agent.teleportFlags = teleportFlags; 4053 // where HG users are occasionally seen by others as "Unknown User" because their UUIDName
3756 m_authenticateHandler.AddNewCircuit(agent.circuitcode, agent); 4054 // request for the HG avatar appears to trigger before the user name is cached.
4055 CacheUserName(null, acd);
4056 }
3757 4057
3758 if (vialogin) 4058 if (vialogin)
3759 { 4059 {
3760// CleanDroppedAttachments(); 4060// CleanDroppedAttachments();
3761 4061
3762 if (TestBorderCross(agent.startpos, Cardinals.E)) 4062 // Make sure avatar position is in the region (why it wouldn't be is a mystery but do sanity checking)
3763 { 4063 if (acd.startpos.X < 0) acd.startpos.X = 1f;
3764 Border crossedBorder = GetCrossedBorder(agent.startpos, Cardinals.E); 4064 if (acd.startpos.X >= RegionInfo.RegionSizeX) acd.startpos.X = RegionInfo.RegionSizeX - 1f;
3765 agent.startpos.X = crossedBorder.BorderLine.Z - 1; 4065 if (acd.startpos.Y < 0) acd.startpos.Y = 1f;
3766 } 4066 if (acd.startpos.Y >= RegionInfo.RegionSizeY) acd.startpos.Y = RegionInfo.RegionSizeY - 1f;
3767
3768 if (TestBorderCross(agent.startpos, Cardinals.N))
3769 {
3770 Border crossedBorder = GetCrossedBorder(agent.startpos, Cardinals.N);
3771 agent.startpos.Y = crossedBorder.BorderLine.Z - 1;
3772 }
3773 4067
3774 //Mitigate http://opensimulator.org/mantis/view.php?id=3522 4068// m_log.DebugFormat(
3775 // Check if start position is outside of region 4069// "[SCENE]: Found telehub object {0} for new user connection {1} to {2}",
3776 // If it is, check the Z start position also.. if not, leave it alone. 4070// RegionInfo.RegionSettings.TelehubObject, acd.Name, Name);
3777 if (BordersLocked)
3778 {
3779 lock (EastBorders)
3780 {
3781 if (agent.startpos.X > EastBorders[0].BorderLine.Z)
3782 {
3783 m_log.Warn("FIX AGENT POSITION");
3784 agent.startpos.X = EastBorders[0].BorderLine.Z * 0.5f;
3785 if (agent.startpos.Z > 720)
3786 agent.startpos.Z = 720;
3787 }
3788 }
3789 lock (NorthBorders)
3790 {
3791 if (agent.startpos.Y > NorthBorders[0].BorderLine.Z)
3792 {
3793 m_log.Warn("FIX Agent POSITION");
3794 agent.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f;
3795 if (agent.startpos.Z > 720)
3796 agent.startpos.Z = 720;
3797 }
3798 }
3799 } else
3800 {
3801 if (agent.startpos.X > EastBorders[0].BorderLine.Z)
3802 {
3803 m_log.Warn("FIX AGENT POSITION");
3804 agent.startpos.X = EastBorders[0].BorderLine.Z * 0.5f;
3805 if (agent.startpos.Z > 720)
3806 agent.startpos.Z = 720;
3807 }
3808 if (agent.startpos.Y > NorthBorders[0].BorderLine.Z)
3809 {
3810 m_log.Warn("FIX Agent POSITION");
3811 agent.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f;
3812 if (agent.startpos.Z > 720)
3813 agent.startpos.Z = 720;
3814 }
3815 }
3816 4071
3817 // Honor Estate teleport routing via Telehubs excluding ViaHome and GodLike TeleportFlags 4072 // Honor Estate teleport routing via Telehubs excluding ViaHome and GodLike TeleportFlags
3818 if (RegionInfo.RegionSettings.TelehubObject != UUID.Zero && 4073 if (RegionInfo.RegionSettings.TelehubObject != UUID.Zero &&
@@ -3820,26 +4075,49 @@ namespace OpenSim.Region.Framework.Scenes
3820 !viahome && !godlike) 4075 !viahome && !godlike)
3821 { 4076 {
3822 SceneObjectGroup telehub = GetSceneObjectGroup(RegionInfo.RegionSettings.TelehubObject); 4077 SceneObjectGroup telehub = GetSceneObjectGroup(RegionInfo.RegionSettings.TelehubObject);
3823 // Can have multiple SpawnPoints 4078
3824 List<SpawnPoint> spawnpoints = RegionInfo.RegionSettings.SpawnPoints(); 4079 if (telehub != null)
3825 if (spawnpoints.Count > 1)
3826 { 4080 {
3827 // We have multiple SpawnPoints, Route the agent to a random or sequential one 4081 // Can have multiple SpawnPoints
3828 if (SpawnPointRouting == "random") 4082 List<SpawnPoint> spawnpoints = RegionInfo.RegionSettings.SpawnPoints();
3829 agent.startpos = spawnpoints[Util.RandomClass.Next(spawnpoints.Count) - 1].GetLocation( 4083 if (spawnpoints.Count > 1)
3830 telehub.AbsolutePosition, 4084 {
3831 telehub.GroupRotation 4085 // We have multiple SpawnPoints, Route the agent to a random or sequential one
3832 ); 4086 if (SpawnPointRouting == "random")
4087 acd.startpos = spawnpoints[Util.RandomClass.Next(spawnpoints.Count) - 1].GetLocation(
4088 telehub.AbsolutePosition,
4089 telehub.GroupRotation
4090 );
4091 else
4092 acd.startpos = spawnpoints[SpawnPoint()].GetLocation(
4093 telehub.AbsolutePosition,
4094 telehub.GroupRotation
4095 );
4096 }
4097 else if (spawnpoints.Count == 1)
4098 {
4099 // We have a single SpawnPoint and will route the agent to it
4100 acd.startpos = spawnpoints[0].GetLocation(telehub.AbsolutePosition, telehub.GroupRotation);
4101 }
3833 else 4102 else
3834 agent.startpos = spawnpoints[SpawnPoint()].GetLocation( 4103 {
3835 telehub.AbsolutePosition, 4104 m_log.DebugFormat(
3836 telehub.GroupRotation 4105 "[SCENE]: No spawnpoints defined for telehub {0} for {1} in {2}. Continuing.",
3837 ); 4106 RegionInfo.RegionSettings.TelehubObject, acd.Name, Name);
4107 }
3838 } 4108 }
3839 else 4109 else
3840 { 4110 {
3841 // We have a single SpawnPoint and will route the agent to it 4111 m_log.DebugFormat(
3842 agent.startpos = spawnpoints[0].GetLocation(telehub.AbsolutePosition, telehub.GroupRotation); 4112 "[SCENE]: No telehub {0} found to direct {1} in {2}. Continuing.",
4113 RegionInfo.RegionSettings.TelehubObject, acd.Name, Name);
4114 }
4115
4116 // Final permissions check; this time we don't allow changing the position
4117 if (!IsPositionAllowed(acd.AgentID, acd.startpos, ref reason))
4118 {
4119 m_authenticateHandler.RemoveCircuit(acd.circuitcode);
4120 return false;
3843 } 4121 }
3844 4122
3845 return true; 4123 return true;
@@ -3850,7 +4128,14 @@ namespace OpenSim.Region.Framework.Scenes
3850 { 4128 {
3851 if (land.LandData.LandingType == (byte)1 && land.LandData.UserLocation != Vector3.Zero) 4129 if (land.LandData.LandingType == (byte)1 && land.LandData.UserLocation != Vector3.Zero)
3852 { 4130 {
3853 agent.startpos = land.LandData.UserLocation; 4131 acd.startpos = land.LandData.UserLocation;
4132
4133 // Final permissions check; this time we don't allow changing the position
4134 if (!IsPositionAllowed(acd.AgentID, acd.startpos, ref reason))
4135 {
4136 m_authenticateHandler.RemoveCircuit(acd.circuitcode);
4137 return false;
4138 }
3854 } 4139 }
3855 } 4140 }
3856 } 4141 }
@@ -3858,20 +4143,52 @@ namespace OpenSim.Region.Framework.Scenes
3858 return true; 4143 return true;
3859 } 4144 }
3860 4145
3861 private bool TestLandRestrictions(AgentCircuitData agent, ILandObject land, out string reason) 4146 private bool IsPositionAllowed(UUID agentID, Vector3 pos, ref string reason)
3862 { 4147 {
3863 bool banned = land.IsBannedFromLand(agent.AgentID); 4148 ILandObject land = LandChannel.GetLandObject(pos);
3864 bool restricted = land.IsRestrictedFromLand(agent.AgentID); 4149 if (land == null)
4150 return true;
4151
4152 if (land.IsBannedFromLand(agentID) || land.IsRestrictedFromLand(agentID))
4153 {
4154 reason = "You are banned from the region.";
4155 return false;
4156 }
4157
4158 return true;
4159 }
4160
4161 public bool TestLandRestrictions(UUID agentID, out string reason, ref float posX, ref float posY)
4162 {
4163 if (posX < 0)
4164 posX = 0;
4165 else if (posX >= (float)RegionInfo.RegionSizeX)
4166 posX = (float)RegionInfo.RegionSizeX - 0.001f;
4167 if (posY < 0)
4168 posY = 0;
4169 else if (posY >= (float)RegionInfo.RegionSizeY)
4170 posY = (float)RegionInfo.RegionSizeY - 0.001f;
4171
4172 reason = String.Empty;
4173 if (Permissions.IsGod(agentID))
4174 return true;
4175
4176 ILandObject land = LandChannel.GetLandObject(posX, posY);
4177 if (land == null)
4178 return false;
4179
4180 bool banned = land.IsBannedFromLand(agentID);
4181 bool restricted = land.IsRestrictedFromLand(agentID);
3865 4182
3866 if (banned || restricted) 4183 if (banned || restricted)
3867 { 4184 {
3868 ILandObject nearestParcel = GetNearestAllowedParcel(agent.AgentID, agent.startpos.X, agent.startpos.Y); 4185 ILandObject nearestParcel = GetNearestAllowedParcel(agentID, posX, posY);
3869 if (nearestParcel != null) 4186 if (nearestParcel != null)
3870 { 4187 {
3871 //Move agent to nearest allowed 4188 //Move agent to nearest allowed
3872 Vector3 newPosition = GetParcelCenterAtGround(nearestParcel); 4189 Vector3 newPosition = GetParcelCenterAtGround(nearestParcel);
3873 agent.startpos.X = newPosition.X; 4190 posX = newPosition.X;
3874 agent.startpos.Y = newPosition.Y; 4191 posY = newPosition.Y;
3875 } 4192 }
3876 else 4193 else
3877 { 4194 {
@@ -3882,7 +4199,7 @@ namespace OpenSim.Region.Framework.Scenes
3882 else 4199 else
3883 { 4200 {
3884 reason = String.Format("Denied access to private region {0}: You are not on the access list for that region.", 4201 reason = String.Format("Denied access to private region {0}: You are not on the access list for that region.",
3885 RegionInfo.RegionName); 4202 RegionInfo.RegionName);
3886 } 4203 }
3887 return false; 4204 return false;
3888 } 4205 }
@@ -3927,86 +4244,93 @@ namespace OpenSim.Region.Framework.Scenes
3927 /// <param name="reason">outputs the reason to this string</param> 4244 /// <param name="reason">outputs the reason to this string</param>
3928 /// <returns>True if the region accepts this agent. False if it does not. False will 4245 /// <returns>True if the region accepts this agent. False if it does not. False will
3929 /// also return a reason.</returns> 4246 /// also return a reason.</returns>
3930 protected virtual bool AuthorizeUser(AgentCircuitData agent, out string reason) 4247 protected virtual bool AuthorizeUser(AgentCircuitData agent, bool bypassAccessControl, out string reason)
3931 { 4248 {
3932 reason = String.Empty; 4249 reason = String.Empty;
3933 4250
3934 if (!m_strictAccessControl) return true; 4251 if (!m_strictAccessControl) return true;
3935 if (Permissions.IsGod(agent.AgentID)) return true; 4252 if (Permissions.IsGod(agent.AgentID)) return true;
3936 4253
3937 if (AuthorizationService != null) 4254 if (AuthorizationService != null)
3938 { 4255 {
3939 if (!AuthorizationService.IsAuthorizedForRegion( 4256 if (!AuthorizationService.IsAuthorizedForRegion(
3940 agent.AgentID.ToString(), agent.firstname, agent.lastname, RegionInfo.RegionID.ToString(), out reason)) 4257 agent.AgentID.ToString(), agent.firstname, agent.lastname, RegionInfo.RegionID.ToString(), out reason))
3941 { 4258 {
3942 m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because {4}", 4259 m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because: {4}",
3943 agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName, reason); 4260 agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName, reason);
3944
3945 return false;
3946 }
3947 }
3948 4261
3949 if (RegionInfo.EstateSettings != null)
3950 {
3951 if (RegionInfo.EstateSettings.IsBanned(agent.AgentID))
3952 {
3953 m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user is on the banlist",
3954 agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName);
3955 reason = String.Format("Denied access to region {0}: You have been banned from that region.",
3956 RegionInfo.RegionName);
3957 return false; 4262 return false;
3958 } 4263 }
3959 } 4264 }
3960 else
3961 {
3962 m_log.ErrorFormat("[CONNECTION BEGIN]: Estate Settings is null!");
3963 }
3964 4265
3965 List<UUID> agentGroups = new List<UUID>(); 4266 // We only test the things below when we want to cut off
3966 4267 // child agents from being present in the scene for which their root
3967 if (m_groupsModule != null) 4268 // agent isn't allowed. Otherwise, we allow child agents. The test for
4269 // the root is done elsewhere (QueryAccess)
4270 if (!bypassAccessControl)
3968 { 4271 {
3969 GroupMembershipData[] GroupMembership = m_groupsModule.GetMembershipData(agent.AgentID); 4272 if (RegionInfo.EstateSettings != null)
3970
3971 if (GroupMembership != null)
3972 { 4273 {
3973 for (int i = 0; i < GroupMembership.Length; i++) 4274 if (RegionInfo.EstateSettings.IsBanned(agent.AgentID))
3974 agentGroups.Add(GroupMembership[i].GroupID); 4275 {
4276 m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user is on the banlist",
4277 agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName);
4278 reason = String.Format("Denied access to region {0}: You have been banned from that region.",
4279 RegionInfo.RegionName);
4280 return false;
4281 }
3975 } 4282 }
3976 else 4283 else
3977 { 4284 {
3978 m_log.ErrorFormat("[CONNECTION BEGIN]: GroupMembership is null!"); 4285 m_log.ErrorFormat("[CONNECTION BEGIN]: Estate Settings is null!");
3979 } 4286 }
3980 }
3981 4287
3982 bool groupAccess = false; 4288 List<UUID> agentGroups = new List<UUID>();
3983 UUID[] estateGroups = RegionInfo.EstateSettings.EstateGroups;
3984 4289
3985 if (estateGroups != null) 4290 if (m_groupsModule != null)
3986 {
3987 foreach (UUID group in estateGroups)
3988 { 4291 {
3989 if (agentGroups.Contains(group)) 4292 GroupMembershipData[] GroupMembership = m_groupsModule.GetMembershipData(agent.AgentID);
4293
4294 if (GroupMembership != null)
3990 { 4295 {
3991 groupAccess = true; 4296 for (int i = 0; i < GroupMembership.Length; i++)
3992 break; 4297 agentGroups.Add(GroupMembership[i].GroupID);
4298 }
4299 else
4300 {
4301 m_log.ErrorFormat("[CONNECTION BEGIN]: GroupMembership is null!");
3993 } 4302 }
3994 } 4303 }
3995 }
3996 else
3997 {
3998 m_log.ErrorFormat("[CONNECTION BEGIN]: EstateGroups is null!");
3999 }
4000 4304
4001 if (!RegionInfo.EstateSettings.PublicAccess && 4305 bool groupAccess = false;
4002 !RegionInfo.EstateSettings.HasAccess(agent.AgentID) && 4306 UUID[] estateGroups = RegionInfo.EstateSettings.EstateGroups;
4003 !groupAccess) 4307
4004 { 4308 if (estateGroups != null)
4005 m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user does not have access to the estate", 4309 {
4006 agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName); 4310 foreach (UUID group in estateGroups)
4007 reason = String.Format("Denied access to private region {0}: You are not on the access list for that region.", 4311 {
4008 RegionInfo.RegionName); 4312 if (agentGroups.Contains(group))
4009 return false; 4313 {
4314 groupAccess = true;
4315 break;
4316 }
4317 }
4318 }
4319 else
4320 {
4321 m_log.ErrorFormat("[CONNECTION BEGIN]: EstateGroups is null!");
4322 }
4323
4324 if (!RegionInfo.EstateSettings.PublicAccess &&
4325 !RegionInfo.EstateSettings.HasAccess(agent.AgentID) &&
4326 !groupAccess)
4327 {
4328 m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user does not have access to the estate",
4329 agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName);
4330 reason = String.Format("Denied access to private region {0}: You are not on the access list for that region.",
4331 RegionInfo.RegionName);
4332 return false;
4333 }
4010 } 4334 }
4011 4335
4012 // TODO: estate/region settings are not properly hooked up 4336 // TODO: estate/region settings are not properly hooked up
@@ -4096,33 +4420,33 @@ namespace OpenSim.Region.Framework.Scenes
4096// } 4420// }
4097// } 4421// }
4098 4422
4099 /// <summary> 4423// /// <summary>
4100 /// Triggered when an agent crosses into this sim. Also happens on initial login. 4424// /// Triggered when an agent crosses into this sim. Also happens on initial login.
4101 /// </summary> 4425// /// </summary>
4102 /// <param name="agentID"></param> 4426// /// <param name="agentID"></param>
4103 /// <param name="position"></param> 4427// /// <param name="position"></param>
4104 /// <param name="isFlying"></param> 4428// /// <param name="isFlying"></param>
4105 public virtual void AgentCrossing(UUID agentID, Vector3 position, bool isFlying) 4429// public virtual void AgentCrossing(UUID agentID, Vector3 position, bool isFlying)
4106 { 4430// {
4107 ScenePresence presence = GetScenePresence(agentID); 4431// ScenePresence presence = GetScenePresence(agentID);
4108 if (presence != null) 4432// if (presence != null)
4109 { 4433// {
4110 try 4434// try
4111 { 4435// {
4112 presence.MakeRootAgent(position, isFlying); 4436// presence.MakeRootAgent(position, isFlying);
4113 } 4437// }
4114 catch (Exception e) 4438// catch (Exception e)
4115 { 4439// {
4116 m_log.ErrorFormat("[SCENE]: Unable to do agent crossing, exception {0}{1}", e.Message, e.StackTrace); 4440// m_log.ErrorFormat("[SCENE]: Unable to do agent crossing, exception {0}{1}", e.Message, e.StackTrace);
4117 } 4441// }
4118 } 4442// }
4119 else 4443// else
4120 { 4444// {
4121 m_log.ErrorFormat( 4445// m_log.ErrorFormat(
4122 "[SCENE]: Could not find presence for agent {0} crossing into scene {1}", 4446// "[SCENE]: Could not find presence for agent {0} crossing into scene {1}",
4123 agentID, RegionInfo.RegionName); 4447// agentID, RegionInfo.RegionName);
4124 } 4448// }
4125 } 4449// }
4126 4450
4127 /// <summary> 4451 /// <summary>
4128 /// We've got an update about an agent that sees into this region, 4452 /// We've got an update about an agent that sees into this region,
@@ -4131,18 +4455,16 @@ namespace OpenSim.Region.Framework.Scenes
4131 /// <param name="cAgentData">Agent that contains all of the relevant things about an agent. 4455 /// <param name="cAgentData">Agent that contains all of the relevant things about an agent.
4132 /// Appearance, animations, position, etc.</param> 4456 /// Appearance, animations, position, etc.</param>
4133 /// <returns>true if we handled it.</returns> 4457 /// <returns>true if we handled it.</returns>
4134 public virtual bool IncomingChildAgentDataUpdate(AgentData cAgentData) 4458 public virtual bool IncomingUpdateChildAgent(AgentData cAgentData)
4135 { 4459 {
4136 m_log.DebugFormat( 4460 m_log.DebugFormat(
4137 "[SCENE]: Incoming child agent update for {0} in {1}", cAgentData.AgentID, RegionInfo.RegionName); 4461 "[SCENE]: Incoming child agent update for {0} in {1}", cAgentData.AgentID, RegionInfo.RegionName);
4138 4462
4139 // XPTO: if this agent is not allowed here as root, always return false
4140
4141 // TODO: This check should probably be in QueryAccess(). 4463 // TODO: This check should probably be in QueryAccess().
4142 ILandObject nearestParcel = GetNearestAllowedParcel(cAgentData.AgentID, Constants.RegionSize / 2, Constants.RegionSize / 2); 4464 ILandObject nearestParcel = GetNearestAllowedParcel(cAgentData.AgentID, RegionInfo.RegionSizeX / 2, RegionInfo.RegionSizeY / 2);
4143 if (nearestParcel == null) 4465 if (nearestParcel == null)
4144 { 4466 {
4145 m_log.DebugFormat( 4467 m_log.InfoFormat(
4146 "[SCENE]: Denying root agent entry to {0} in {1}: no allowed parcel", 4468 "[SCENE]: Denying root agent entry to {0} in {1}: no allowed parcel",
4147 cAgentData.AgentID, RegionInfo.RegionName); 4469 cAgentData.AgentID, RegionInfo.RegionName);
4148 4470
@@ -4150,13 +4472,44 @@ namespace OpenSim.Region.Framework.Scenes
4150 } 4472 }
4151 4473
4152 // We have to wait until the viewer contacts this region 4474 // We have to wait until the viewer contacts this region
4153 // after receiving the EnableSimulator HTTP Event Queue message. This triggers the viewer to send 4475 // after receiving the EnableSimulator HTTP Event Queue message (for the v1 teleport protocol)
4154 // a UseCircuitCode packet which in turn calls AddNewClient which finally creates the ScenePresence. 4476 // or TeleportFinish (for the v2 teleport protocol). This triggers the viewer to send
4155 ScenePresence childAgentUpdate = WaitGetScenePresence(cAgentData.AgentID); 4477 // a UseCircuitCode packet which in turn calls AddNewAgent which finally creates the ScenePresence.
4478 ScenePresence sp = WaitGetScenePresence(cAgentData.AgentID);
4156 4479
4157 if (childAgentUpdate != null) 4480 if (sp != null)
4158 { 4481 {
4159 childAgentUpdate.ChildAgentDataUpdate(cAgentData); 4482 if (cAgentData.SessionID != sp.ControllingClient.SessionId)
4483 {
4484 m_log.WarnFormat(
4485 "[SCENE]: Attempt to update agent {0} with invalid session id {1} (possibly from simulator in older version; tell them to update).",
4486 sp.UUID, cAgentData.SessionID);
4487
4488 Console.WriteLine(String.Format("[SCENE]: Attempt to update agent {0} ({1}) with invalid session id {2}",
4489 sp.UUID, sp.ControllingClient.SessionId, cAgentData.SessionID));
4490 }
4491
4492 sp.UpdateChildAgent(cAgentData);
4493
4494 int ntimes = 20;
4495 if (cAgentData.SenderWantsToWaitForRoot)
4496 {
4497 while (sp.IsChildAgent && ntimes-- > 0)
4498 Thread.Sleep(1000);
4499
4500 if (sp.IsChildAgent)
4501 m_log.WarnFormat(
4502 "[SCENE]: Found presence {0} {1} unexpectedly still child in {2}",
4503 sp.Name, sp.UUID, Name);
4504 else
4505 m_log.InfoFormat(
4506 "[SCENE]: Found presence {0} {1} as root in {2} after {3} waits",
4507 sp.Name, sp.UUID, Name, 20 - ntimes);
4508
4509 if (sp.IsChildAgent)
4510 return false;
4511 }
4512
4160 return true; 4513 return true;
4161 } 4514 }
4162 4515
@@ -4169,12 +4522,20 @@ namespace OpenSim.Region.Framework.Scenes
4169 /// </summary> 4522 /// </summary>
4170 /// <param name="cAgentData">AgentPosition that contains agent positional data so we can know what to send</param> 4523 /// <param name="cAgentData">AgentPosition that contains agent positional data so we can know what to send</param>
4171 /// <returns>true if we handled it.</returns> 4524 /// <returns>true if we handled it.</returns>
4172 public virtual bool IncomingChildAgentDataUpdate(AgentPosition cAgentData) 4525 public virtual bool IncomingUpdateChildAgent(AgentPosition cAgentData)
4173 { 4526 {
4174 //m_log.Debug(" XXX Scene IncomingChildAgentDataUpdate POSITION in " + RegionInfo.RegionName); 4527// m_log.DebugFormat(
4528// "[SCENE PRESENCE]: IncomingChildAgentDataUpdate POSITION for {0} in {1}, position {2}",
4529// cAgentData.AgentID, Name, cAgentData.Position);
4530
4175 ScenePresence childAgentUpdate = GetScenePresence(cAgentData.AgentID); 4531 ScenePresence childAgentUpdate = GetScenePresence(cAgentData.AgentID);
4176 if (childAgentUpdate != null) 4532 if (childAgentUpdate != null)
4177 { 4533 {
4534// if (childAgentUpdate.ControllingClient.SessionId != cAgentData.SessionID)
4535// // Only warn for now
4536// m_log.WarnFormat("[SCENE]: Attempt at updating position of agent {0} with invalid session id {1}. Neighbor running older version?",
4537// childAgentUpdate.UUID, cAgentData.SessionID);
4538
4178 // I can't imagine *yet* why we would get an update if the agent is a root agent.. 4539 // I can't imagine *yet* why we would get an update if the agent is a root agent..
4179 // however to avoid a race condition crossing borders.. 4540 // however to avoid a race condition crossing borders..
4180 if (childAgentUpdate.IsChildAgent) 4541 if (childAgentUpdate.IsChildAgent)
@@ -4184,7 +4545,7 @@ namespace OpenSim.Region.Framework.Scenes
4184 uint tRegionX = RegionInfo.RegionLocX; 4545 uint tRegionX = RegionInfo.RegionLocX;
4185 uint tRegionY = RegionInfo.RegionLocY; 4546 uint tRegionY = RegionInfo.RegionLocY;
4186 //Send Data to ScenePresence 4547 //Send Data to ScenePresence
4187 childAgentUpdate.ChildAgentDataUpdate(cAgentData, tRegionX, tRegionY, rRegionX, rRegionY); 4548 childAgentUpdate.UpdateChildAgent(cAgentData, tRegionX, tRegionY, rRegionX, rRegionY);
4188 // Not Implemented: 4549 // Not Implemented:
4189 //TODO: Do we need to pass the message on to one of our neighbors? 4550 //TODO: Do we need to pass the message on to one of our neighbors?
4190 } 4551 }
@@ -4202,7 +4563,7 @@ namespace OpenSim.Region.Framework.Scenes
4202 /// <param name='agentID'></param> 4563 /// <param name='agentID'></param>
4203 protected virtual ScenePresence WaitGetScenePresence(UUID agentID) 4564 protected virtual ScenePresence WaitGetScenePresence(UUID agentID)
4204 { 4565 {
4205 int ntimes = 10; 4566 int ntimes = 20;
4206 ScenePresence sp = null; 4567 ScenePresence sp = null;
4207 while ((sp = GetScenePresence(agentID)) == null && (ntimes-- > 0)) 4568 while ((sp = GetScenePresence(agentID)) == null && (ntimes-- > 0))
4208 Thread.Sleep(1000); 4569 Thread.Sleep(1000);
@@ -4211,28 +4572,92 @@ namespace OpenSim.Region.Framework.Scenes
4211 m_log.WarnFormat( 4572 m_log.WarnFormat(
4212 "[SCENE PRESENCE]: Did not find presence with id {0} in {1} before timeout", 4573 "[SCENE PRESENCE]: Did not find presence with id {0} in {1} before timeout",
4213 agentID, RegionInfo.RegionName); 4574 agentID, RegionInfo.RegionName);
4214// else
4215// m_log.DebugFormat(
4216// "[SCENE PRESENCE]: Found presence {0} {1} {2} in {3} after {4} waits",
4217// sp.Name, sp.UUID, sp.IsChildAgent ? "child" : "root", RegionInfo.RegionName, 10 - ntimes);
4218 4575
4219 return sp; 4576 return sp;
4220 } 4577 }
4221 4578
4222 public virtual bool IncomingRetrieveRootAgent(UUID id, out IAgentData agent) 4579 /// <summary>
4580 /// Authenticated close (via network)
4581 /// </summary>
4582 /// <param name="agentID"></param>
4583 /// <param name="force"></param>
4584 /// <param name="auth_token"></param>
4585 /// <returns></returns>
4586 public bool CloseAgent(UUID agentID, bool force, string auth_token)
4223 { 4587 {
4224 agent = null; 4588 //m_log.DebugFormat("[SCENE]: Processing incoming close agent {0} in region {1} with auth_token {2}", agentID, RegionInfo.RegionName, auth_token);
4225 ScenePresence sp = GetScenePresence(id); 4589
4226 if ((sp != null) && (!sp.IsChildAgent)) 4590 // Check that the auth_token is valid
4591 AgentCircuitData acd = AuthenticateHandler.GetAgentCircuitData(agentID);
4592
4593 if (acd == null)
4594 {
4595 m_log.DebugFormat(
4596 "[SCENE]: Request to close agent {0} but no such agent in scene {1}. May have been closed previously.",
4597 agentID, Name);
4598
4599 return false;
4600 }
4601
4602 if (acd.SessionID.ToString() == auth_token)
4603 {
4604 return CloseAgent(agentID, force);
4605 }
4606 else
4227 { 4607 {
4228 sp.IsChildAgent = true; 4608 m_log.WarnFormat(
4229 return sp.CopyAgent(out agent); 4609 "[SCENE]: Request to close agent {0} with invalid authorization token {1} in {2}",
4610 agentID, auth_token, Name);
4230 } 4611 }
4231 4612
4232 return false; 4613 return false;
4233 } 4614 }
4234 4615
4235 /// <summary> 4616 /// <summary>
4617 /// Tell a single client to prepare to close.
4618 /// </summary>
4619 /// <remarks>
4620 /// This should only be called if we may close the client but there will be some delay in so doing. Meant for
4621 /// internal use - other callers should almost certainly called CloseClient().
4622 /// </remarks>
4623 /// <param name="sp"></param>
4624 /// <returns>true if pre-close state notification was successful. false if the agent
4625 /// was not in a state where it could transition to pre-close.</returns>
4626 public bool IncomingPreCloseClient(ScenePresence sp)
4627 {
4628 lock (m_removeClientLock)
4629 {
4630 // We need to avoid a race condition where in, for example, an A B C D region layout, an avatar may
4631 // teleport from A -> D, but then -> C before A has asked B to close its old child agent. We do not
4632 // want to obey this close since C may have renewed the child agent lease on B.
4633 if (sp.DoNotCloseAfterTeleport)
4634 {
4635 m_log.DebugFormat(
4636 "[SCENE]: Not pre-closing {0} agent {1} in {2} since another simulator has re-established the child connection",
4637 sp.IsChildAgent ? "child" : "root", sp.Name, Name);
4638
4639 // Need to reset the flag so that a subsequent close after another teleport can succeed.
4640 sp.DoNotCloseAfterTeleport = false;
4641
4642 return false;
4643 }
4644
4645 if (sp.LifecycleState != ScenePresenceState.Running)
4646 {
4647 m_log.DebugFormat(
4648 "[SCENE]: Called IncomingPreCloseAgent() for {0} in {1} but presence is already in state {2}",
4649 sp.Name, Name, sp.LifecycleState);
4650
4651 return false;
4652 }
4653
4654 sp.LifecycleState = ScenePresenceState.PreRemove;
4655
4656 return true;
4657 }
4658 }
4659
4660 /// <summary>
4236 /// Tell a single agent to disconnect from the region. 4661 /// Tell a single agent to disconnect from the region.
4237 /// </summary> 4662 /// </summary>
4238 /// <param name="agentID"></param> 4663 /// <param name="agentID"></param>
@@ -4240,19 +4665,53 @@ namespace OpenSim.Region.Framework.Scenes
4240 /// Force the agent to close even if it might be in the middle of some other operation. You do not want to 4665 /// Force the agent to close even if it might be in the middle of some other operation. You do not want to
4241 /// force unless you are absolutely sure that the agent is dead and a normal close is not working. 4666 /// force unless you are absolutely sure that the agent is dead and a normal close is not working.
4242 /// </param> 4667 /// </param>
4243 public bool IncomingCloseAgent(UUID agentID, bool force) 4668 public override bool CloseAgent(UUID agentID, bool force)
4244 { 4669 {
4245 //m_log.DebugFormat("[SCENE]: Processing incoming close agent for {0}", agentID); 4670 ScenePresence sp;
4246 4671
4247 ScenePresence presence = m_sceneGraph.GetScenePresence(agentID); 4672 lock (m_removeClientLock)
4248 if (presence != null)
4249 { 4673 {
4250 presence.ControllingClient.Close(force); 4674 sp = GetScenePresence(agentID);
4251 return true; 4675
4676 if (sp == null)
4677 {
4678 m_log.DebugFormat(
4679 "[SCENE]: Called CloseClient() with agent ID {0} but no such presence is in {1}",
4680 agentID, Name);
4681
4682 return false;
4683 }
4684
4685 if (sp.LifecycleState != ScenePresenceState.Running && sp.LifecycleState != ScenePresenceState.PreRemove)
4686 {
4687 m_log.DebugFormat(
4688 "[SCENE]: Called CloseClient() for {0} in {1} but presence is already in state {2}",
4689 sp.Name, Name, sp.LifecycleState);
4690
4691 return false;
4692 }
4693
4694 // We need to avoid a race condition where in, for example, an A B C D region layout, an avatar may
4695 // teleport from A -> D, but then -> C before A has asked B to close its old child agent. We do not
4696 // want to obey this close since C may have renewed the child agent lease on B.
4697 if (sp.DoNotCloseAfterTeleport)
4698 {
4699 m_log.DebugFormat(
4700 "[SCENE]: Not closing {0} agent {1} in {2} since another simulator has re-established the child connection",
4701 sp.IsChildAgent ? "child" : "root", sp.Name, Name);
4702
4703 // Need to reset the flag so that a subsequent close after another teleport can succeed.
4704 sp.DoNotCloseAfterTeleport = false;
4705
4706 return false;
4707 }
4708
4709 sp.LifecycleState = ScenePresenceState.Removing;
4252 } 4710 }
4253 4711
4254 // Agent not here 4712 sp.ControllingClient.Close(force);
4255 return false; 4713
4714 return true;
4256 } 4715 }
4257 4716
4258 /// <summary> 4717 /// <summary>
@@ -4295,44 +4754,6 @@ namespace OpenSim.Region.Framework.Scenes
4295 ScenePresence sp = GetScenePresence(remoteClient.AgentId); 4754 ScenePresence sp = GetScenePresence(remoteClient.AgentId);
4296 if (sp != null) 4755 if (sp != null)
4297 { 4756 {
4298 uint regionX = RegionInfo.RegionLocX;
4299 uint regionY = RegionInfo.RegionLocY;
4300
4301 Utils.LongToUInts(regionHandle, out regionX, out regionY);
4302
4303 int shiftx = (int) regionX - (int) RegionInfo.RegionLocX * (int)Constants.RegionSize;
4304 int shifty = (int) regionY - (int) RegionInfo.RegionLocY * (int)Constants.RegionSize;
4305
4306 position.X += shiftx;
4307 position.Y += shifty;
4308
4309 bool result = false;
4310
4311 if (TestBorderCross(position,Cardinals.N))
4312 result = true;
4313
4314 if (TestBorderCross(position, Cardinals.S))
4315 result = true;
4316
4317 if (TestBorderCross(position, Cardinals.E))
4318 result = true;
4319
4320 if (TestBorderCross(position, Cardinals.W))
4321 result = true;
4322
4323 // bordercross if position is outside of region
4324
4325 if (!result)
4326 {
4327 regionHandle = RegionInfo.RegionHandle;
4328 }
4329 else
4330 {
4331 // not in this region, undo the shift!
4332 position.X -= shiftx;
4333 position.Y -= shifty;
4334 }
4335
4336 if (EntityTransferModule != null) 4757 if (EntityTransferModule != null)
4337 { 4758 {
4338 EntityTransferModule.Teleport(sp, regionHandle, position, lookAt, teleportFlags); 4759 EntityTransferModule.Teleport(sp, regionHandle, position, lookAt, teleportFlags);
@@ -4473,20 +4894,7 @@ namespace OpenSim.Region.Framework.Scenes
4473 4894
4474 #region Script Engine 4895 #region Script Engine
4475 4896
4476 private List<ScriptEngineInterface> ScriptEngines = new List<ScriptEngineInterface>(); 4897 private bool ScriptDanger(SceneObjectPart part, Vector3 pos)
4477 public bool DumpAssetsToFile;
4478
4479 /// <summary>
4480 ///
4481 /// </summary>
4482 /// <param name="scriptEngine"></param>
4483 public void AddScriptEngine(ScriptEngineInterface scriptEngine)
4484 {
4485 ScriptEngines.Add(scriptEngine);
4486 scriptEngine.InitializeEngine(this);
4487 }
4488
4489 private bool ScriptDanger(SceneObjectPart part,Vector3 pos)
4490 { 4898 {
4491 ILandObject parcel = LandChannel.GetLandObject(pos.X, pos.Y); 4899 ILandObject parcel = LandChannel.GetLandObject(pos.X, pos.Y);
4492 if (part != null) 4900 if (part != null)
@@ -4497,35 +4905,24 @@ namespace OpenSim.Region.Framework.Scenes
4497 { 4905 {
4498 return true; 4906 return true;
4499 } 4907 }
4500 else if ((parcel.LandData.Flags & (uint)ParcelFlags.AllowGroupScripts) != 0) 4908 else if ((part.OwnerID == parcel.LandData.OwnerID) || Permissions.IsGod(part.OwnerID))
4501 { 4909 {
4502 if (part.OwnerID == parcel.LandData.OwnerID 4910 return true;
4503 || (parcel.LandData.IsGroupOwned && part.GroupID == parcel.LandData.GroupID) 4911 }
4504 || Permissions.IsGod(part.OwnerID)) 4912 else if (((parcel.LandData.Flags & (uint)ParcelFlags.AllowGroupScripts) != 0)
4505 { 4913 && (parcel.LandData.GroupID != UUID.Zero) && (parcel.LandData.GroupID == part.GroupID))
4506 return true; 4914 {
4507 } 4915 return true;
4508 else
4509 {
4510 return false;
4511 }
4512 } 4916 }
4513 else 4917 else
4514 { 4918 {
4515 if (part.OwnerID == parcel.LandData.OwnerID) 4919 return false;
4516 {
4517 return true;
4518 }
4519 else
4520 {
4521 return false;
4522 }
4523 } 4920 }
4524 } 4921 }
4525 else 4922 else
4526 { 4923 {
4527 4924
4528 if (pos.X > 0f && pos.X < Constants.RegionSize && pos.Y > 0f && pos.Y < Constants.RegionSize) 4925 if (pos.X > 0f && pos.X < RegionInfo.RegionSizeX && pos.Y > 0f && pos.Y < RegionInfo.RegionSizeY)
4529 { 4926 {
4530 // The only time parcel != null when an object is inside a region is when 4927 // The only time parcel != null when an object is inside a region is when
4531 // there is nothing behind the landchannel. IE, no land plugin loaded. 4928 // there is nothing behind the landchannel. IE, no land plugin loaded.
@@ -4854,21 +5251,6 @@ namespace OpenSim.Region.Framework.Scenes
4854 5251
4855 #endregion 5252 #endregion
4856 5253
4857 public void RegionHandleRequest(IClientAPI client, UUID regionID)
4858 {
4859 ulong handle = 0;
4860 if (regionID == RegionInfo.RegionID)
4861 handle = RegionInfo.RegionHandle;
4862 else
4863 {
4864 GridRegion r = GridService.GetRegionByUUID(UUID.Zero, regionID);
4865 if (r != null)
4866 handle = r.RegionHandle;
4867 }
4868
4869 if (handle != 0)
4870 client.SendRegionHandle(regionID, handle);
4871 }
4872 5254
4873// Commented pending deletion since this method no longer appears to do anything at all 5255// Commented pending deletion since this method no longer appears to do anything at all
4874// public bool NeedSceneCacheClear(UUID agentID) 5256// public bool NeedSceneCacheClear(UUID agentID)
@@ -4920,7 +5302,7 @@ namespace OpenSim.Region.Framework.Scenes
4920 // 3 = We have seen a new user enter within the past 4 minutes 5302 // 3 = We have seen a new user enter within the past 4 minutes
4921 // which can be seen as positive confirmation of sim health 5303 // which can be seen as positive confirmation of sim health
4922 // 5304 //
4923 int health=1; // Start at 1, means we're up 5305 int health = 1; // Start at 1, means we're up
4924 5306
4925 if ((Util.EnvironmentTickCountSubtract(m_lastFrameTick)) < 1000) 5307 if ((Util.EnvironmentTickCountSubtract(m_lastFrameTick)) < 1000)
4926 health += 1; 5308 health += 1;
@@ -4967,7 +5349,7 @@ namespace OpenSim.Region.Framework.Scenes
4967 case PhysicsJointType.Ball: 5349 case PhysicsJointType.Ball:
4968 { 5350 {
4969 Vector3 jointAnchor = PhysicsScene.GetJointAnchor(joint); 5351 Vector3 jointAnchor = PhysicsScene.GetJointAnchor(joint);
4970 Vector3 proxyPos = new Vector3(jointAnchor.X, jointAnchor.Y, jointAnchor.Z); 5352 Vector3 proxyPos = jointAnchor;
4971 jointProxyObject.ParentGroup.UpdateGroupPosition(proxyPos); // schedules the entire group for a terse update 5353 jointProxyObject.ParentGroup.UpdateGroupPosition(proxyPos); // schedules the entire group for a terse update
4972 } 5354 }
4973 break; 5355 break;
@@ -4992,7 +5374,7 @@ namespace OpenSim.Region.Framework.Scenes
4992 jointErrorMessage(joint, "joint.TrackedBodyName is null, joint " + joint.ObjectNameInScene); 5374 jointErrorMessage(joint, "joint.TrackedBodyName is null, joint " + joint.ObjectNameInScene);
4993 } 5375 }
4994 5376
4995 Vector3 proxyPos = new Vector3(jointAnchor.X, jointAnchor.Y, jointAnchor.Z); 5377 Vector3 proxyPos = jointAnchor;
4996 Quaternion q = trackedBody.RotationOffset * joint.LocalRotation; 5378 Quaternion q = trackedBody.RotationOffset * joint.LocalRotation;
4997 5379
4998 jointProxyObject.ParentGroup.UpdateGroupPosition(proxyPos); // schedules the entire group for a terse update 5380 jointProxyObject.ParentGroup.UpdateGroupPosition(proxyPos); // schedules the entire group for a terse update
@@ -5081,6 +5463,10 @@ namespace OpenSim.Region.Framework.Scenes
5081 return null; 5463 return null;
5082 } 5464 }
5083 5465
5466 // Get terrain height at the specified <x,y> location.
5467 // Presumes the underlying implementation is a heightmap which is a 1m grid.
5468 // Finds heightmap grid points before and after the point and
5469 // does a linear approximation of the height at this intermediate point.
5084 public float GetGroundHeight(float x, float y) 5470 public float GetGroundHeight(float x, float y)
5085 { 5471 {
5086 if (x < 0) 5472 if (x < 0)
@@ -5093,8 +5479,8 @@ namespace OpenSim.Region.Framework.Scenes
5093 y = Heightmap.Height - 1; 5479 y = Heightmap.Height - 1;
5094 5480
5095 Vector3 p0 = new Vector3(x, y, (float)Heightmap[(int)x, (int)y]); 5481 Vector3 p0 = new Vector3(x, y, (float)Heightmap[(int)x, (int)y]);
5096 Vector3 p1 = new Vector3(p0); 5482 Vector3 p1 = p0;
5097 Vector3 p2 = new Vector3(p0); 5483 Vector3 p2 = p0;
5098 5484
5099 p1.X += 1.0f; 5485 p1.X += 1.0f;
5100 if (p1.X < Heightmap.Width) 5486 if (p1.X < Heightmap.Width)
@@ -5141,9 +5527,14 @@ namespace OpenSim.Region.Framework.Scenes
5141 get { return m_allowScriptCrossings; } 5527 get { return m_allowScriptCrossings; }
5142 } 5528 }
5143 5529
5144 public Vector3? GetNearestAllowedPosition(ScenePresence avatar) 5530 public Vector3 GetNearestAllowedPosition(ScenePresence avatar)
5145 { 5531 {
5146 ILandObject nearestParcel = GetNearestAllowedParcel(avatar.UUID, avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y); 5532 return GetNearestAllowedPosition(avatar, null);
5533 }
5534
5535 public Vector3 GetNearestAllowedPosition(ScenePresence avatar, ILandObject excludeParcel)
5536 {
5537 ILandObject nearestParcel = GetNearestAllowedParcel(avatar.UUID, avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y, excludeParcel);
5147 5538
5148 if (nearestParcel != null) 5539 if (nearestParcel != null)
5149 { 5540 {
@@ -5152,10 +5543,7 @@ namespace OpenSim.Region.Framework.Scenes
5152 Vector3? nearestPoint = GetNearestPointInParcelAlongDirectionFromPoint(avatar.AbsolutePosition, dir, nearestParcel); 5543 Vector3? nearestPoint = GetNearestPointInParcelAlongDirectionFromPoint(avatar.AbsolutePosition, dir, nearestParcel);
5153 if (nearestPoint != null) 5544 if (nearestPoint != null)
5154 { 5545 {
5155// m_log.DebugFormat( 5546 m_log.Debug("Found a sane previous position based on velocity, sending them to: " + nearestPoint.ToString());
5156// "[SCENE]: Found a sane previous position based on velocity for {0}, sending them to {1} in {2}",
5157// avatar.Name, nearestPoint, nearestParcel.LandData.Name);
5158
5159 return nearestPoint.Value; 5547 return nearestPoint.Value;
5160 } 5548 }
5161 5549
@@ -5165,24 +5553,27 @@ namespace OpenSim.Region.Framework.Scenes
5165 nearestPoint = GetNearestPointInParcelAlongDirectionFromPoint(avatar.AbsolutePosition, dir, nearestParcel); 5553 nearestPoint = GetNearestPointInParcelAlongDirectionFromPoint(avatar.AbsolutePosition, dir, nearestParcel);
5166 if (nearestPoint != null) 5554 if (nearestPoint != null)
5167 { 5555 {
5168// m_log.DebugFormat( 5556 m_log.Debug("They had a zero velocity, sending them to: " + nearestPoint.ToString());
5169// "[SCENE]: {0} had a zero velocity, sending them to {1}", avatar.Name, nearestPoint);
5170
5171 return nearestPoint.Value; 5557 return nearestPoint.Value;
5172 } 5558 }
5173 5559
5174 //Ultimate backup if we have no idea where they are 5560 ILandObject dest = LandChannel.GetLandObject(avatar.lastKnownAllowedPosition.X, avatar.lastKnownAllowedPosition.Y);
5175// m_log.DebugFormat( 5561 if (dest != excludeParcel)
5176// "[SCENE]: No idea where {0} is, sending them to {1}", avatar.Name, avatar.lastKnownAllowedPosition); 5562 {
5563 // Ultimate backup if we have no idea where they are and
5564 // the last allowed position was in another parcel
5565 m_log.Debug("Have no idea where they are, sending them to: " + avatar.lastKnownAllowedPosition.ToString());
5566 return avatar.lastKnownAllowedPosition;
5567 }
5177 5568
5178 return avatar.lastKnownAllowedPosition; 5569 // else fall through to region edge
5179 } 5570 }
5180 5571
5181 //Go to the edge, this happens in teleporting to a region with no available parcels 5572 //Go to the edge, this happens in teleporting to a region with no available parcels
5182 Vector3 nearestRegionEdgePoint = GetNearestRegionEdgePosition(avatar); 5573 Vector3 nearestRegionEdgePoint = GetNearestRegionEdgePosition(avatar);
5183 5574
5184 //Debug.WriteLine("They are really in a place they don't belong, sending them to: " + nearestRegionEdgePoint.ToString()); 5575 //m_log.Debug("They are really in a place they don't belong, sending them to: " + nearestRegionEdgePoint.ToString());
5185 5576
5186 return nearestRegionEdgePoint; 5577 return nearestRegionEdgePoint;
5187 } 5578 }
5188 5579
@@ -5196,7 +5587,7 @@ namespace OpenSim.Region.Framework.Scenes
5196 { 5587 {
5197 Vector3 unitDirection = Vector3.Normalize(direction); 5588 Vector3 unitDirection = Vector3.Normalize(direction);
5198 //Making distance to search go through some sane limit of distance 5589 //Making distance to search go through some sane limit of distance
5199 for (float distance = 0; distance < Constants.RegionSize * 2; distance += .5f) 5590 for (float distance = 0; distance < Math.Max(RegionInfo.RegionSizeX, RegionInfo.RegionSizeY) * 2; distance += .5f)
5200 { 5591 {
5201 Vector3 testPos = Vector3.Add(pos, Vector3.Multiply(unitDirection, distance)); 5592 Vector3 testPos = Vector3.Add(pos, Vector3.Multiply(unitDirection, distance));
5202 if (parcel.ContainsPoint((int)testPos.X, (int)testPos.Y)) 5593 if (parcel.ContainsPoint((int)testPos.X, (int)testPos.Y))
@@ -5209,13 +5600,18 @@ namespace OpenSim.Region.Framework.Scenes
5209 5600
5210 public ILandObject GetNearestAllowedParcel(UUID avatarId, float x, float y) 5601 public ILandObject GetNearestAllowedParcel(UUID avatarId, float x, float y)
5211 { 5602 {
5603 return GetNearestAllowedParcel(avatarId, x, y, null);
5604 }
5605
5606 public ILandObject GetNearestAllowedParcel(UUID avatarId, float x, float y, ILandObject excludeParcel)
5607 {
5212 List<ILandObject> all = AllParcels(); 5608 List<ILandObject> all = AllParcels();
5213 float minParcelDistance = float.MaxValue; 5609 float minParcelDistance = float.MaxValue;
5214 ILandObject nearestParcel = null; 5610 ILandObject nearestParcel = null;
5215 5611
5216 foreach (var parcel in all) 5612 foreach (var parcel in all)
5217 { 5613 {
5218 if (!parcel.IsEitherBannedOrRestricted(avatarId)) 5614 if (!parcel.IsEitherBannedOrRestricted(avatarId) && parcel != excludeParcel)
5219 { 5615 {
5220 float parcelDistance = GetParcelDistancefromPoint(parcel, x, y); 5616 float parcelDistance = GetParcelDistancefromPoint(parcel, x, y);
5221 if (parcelDistance < minParcelDistance) 5617 if (parcelDistance < minParcelDistance)
@@ -5245,9 +5641,9 @@ namespace OpenSim.Region.Framework.Scenes
5245 int count = 0; 5641 int count = 0;
5246 int avgx = 0; 5642 int avgx = 0;
5247 int avgy = 0; 5643 int avgy = 0;
5248 for (int x = 0; x < Constants.RegionSize; x++) 5644 for (int x = 0; x < RegionInfo.RegionSizeX; x++)
5249 { 5645 {
5250 for (int y = 0; y < Constants.RegionSize; y++) 5646 for (int y = 0; y < RegionInfo.RegionSizeY; y++)
5251 { 5647 {
5252 //Just keep a running average as we check if all the points are inside or not 5648 //Just keep a running average as we check if all the points are inside or not
5253 if (parcel.ContainsPoint(x, y)) 5649 if (parcel.ContainsPoint(x, y))
@@ -5271,31 +5667,33 @@ namespace OpenSim.Region.Framework.Scenes
5271 5667
5272 private Vector3 GetNearestRegionEdgePosition(ScenePresence avatar) 5668 private Vector3 GetNearestRegionEdgePosition(ScenePresence avatar)
5273 { 5669 {
5274 float xdistance = avatar.AbsolutePosition.X < Constants.RegionSize / 2 ? avatar.AbsolutePosition.X : Constants.RegionSize - avatar.AbsolutePosition.X; 5670 float xdistance = avatar.AbsolutePosition.X < RegionInfo.RegionSizeX / 2
5275 float ydistance = avatar.AbsolutePosition.Y < Constants.RegionSize / 2 ? avatar.AbsolutePosition.Y : Constants.RegionSize - avatar.AbsolutePosition.Y; 5671 ? avatar.AbsolutePosition.X : RegionInfo.RegionSizeX - avatar.AbsolutePosition.X;
5672 float ydistance = avatar.AbsolutePosition.Y < RegionInfo.RegionSizeY / 2
5673 ? avatar.AbsolutePosition.Y : RegionInfo.RegionSizeY - avatar.AbsolutePosition.Y;
5276 5674
5277 //find out what vertical edge to go to 5675 //find out what vertical edge to go to
5278 if (xdistance < ydistance) 5676 if (xdistance < ydistance)
5279 { 5677 {
5280 if (avatar.AbsolutePosition.X < Constants.RegionSize / 2) 5678 if (avatar.AbsolutePosition.X < RegionInfo.RegionSizeX / 2)
5281 { 5679 {
5282 return GetPositionAtAvatarHeightOrGroundHeight(avatar, 0.0f, avatar.AbsolutePosition.Y); 5680 return GetPositionAtAvatarHeightOrGroundHeight(avatar, 0.0f, avatar.AbsolutePosition.Y);
5283 } 5681 }
5284 else 5682 else
5285 { 5683 {
5286 return GetPositionAtAvatarHeightOrGroundHeight(avatar, Constants.RegionSize, avatar.AbsolutePosition.Y); 5684 return GetPositionAtAvatarHeightOrGroundHeight(avatar, RegionInfo.RegionSizeY, avatar.AbsolutePosition.Y);
5287 } 5685 }
5288 } 5686 }
5289 //find out what horizontal edge to go to 5687 //find out what horizontal edge to go to
5290 else 5688 else
5291 { 5689 {
5292 if (avatar.AbsolutePosition.Y < Constants.RegionSize / 2) 5690 if (avatar.AbsolutePosition.Y < RegionInfo.RegionSizeY / 2)
5293 { 5691 {
5294 return GetPositionAtAvatarHeightOrGroundHeight(avatar, avatar.AbsolutePosition.X, 0.0f); 5692 return GetPositionAtAvatarHeightOrGroundHeight(avatar, avatar.AbsolutePosition.X, 0.0f);
5295 } 5693 }
5296 else 5694 else
5297 { 5695 {
5298 return GetPositionAtAvatarHeightOrGroundHeight(avatar, avatar.AbsolutePosition.X, Constants.RegionSize); 5696 return GetPositionAtAvatarHeightOrGroundHeight(avatar, avatar.AbsolutePosition.X, RegionInfo.RegionSizeY);
5299 } 5697 }
5300 } 5698 }
5301 } 5699 }
@@ -5336,33 +5734,7 @@ namespace OpenSim.Region.Framework.Scenes
5336 5734
5337 public void TriggerEstateSunUpdate() 5735 public void TriggerEstateSunUpdate()
5338 { 5736 {
5339 float sun; 5737 EventManager.TriggerEstateToolsSunUpdate(RegionInfo.RegionHandle);
5340 if (RegionInfo.RegionSettings.UseEstateSun)
5341 {
5342 sun = (float)RegionInfo.EstateSettings.SunPosition;
5343 if (RegionInfo.EstateSettings.UseGlobalTime)
5344 {
5345 sun = EventManager.GetCurrentTimeAsSunLindenHour() - 6.0f;
5346 }
5347
5348 //
5349 EventManager.TriggerEstateToolsSunUpdate(
5350 RegionInfo.RegionHandle,
5351 RegionInfo.EstateSettings.FixedSun,
5352 RegionInfo.RegionSettings.UseEstateSun,
5353 sun);
5354 }
5355 else
5356 {
5357 // Use the Sun Position from the Region Settings
5358 sun = (float)RegionInfo.RegionSettings.SunPosition - 6.0f;
5359
5360 EventManager.TriggerEstateToolsSunUpdate(
5361 RegionInfo.RegionHandle,
5362 RegionInfo.RegionSettings.FixedSun,
5363 RegionInfo.RegionSettings.UseEstateSun,
5364 sun);
5365 }
5366 } 5738 }
5367 5739
5368 private void HandleReloadEstate(string module, string[] cmd) 5740 private void HandleReloadEstate(string module, string[] cmd)
@@ -5387,15 +5759,15 @@ namespace OpenSim.Region.Framework.Scenes
5387 /// <param name="maxZ"></param> 5759 /// <param name="maxZ"></param>
5388 /// <returns></returns> 5760 /// <returns></returns>
5389 public static Vector3[] GetCombinedBoundingBox( 5761 public static Vector3[] GetCombinedBoundingBox(
5390 List<SceneObjectGroup> objects, 5762 List<SceneObjectGroup> objects,
5391 out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ) 5763 out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ)
5392 { 5764 {
5393 minX = 256; 5765 minX = float.MaxValue;
5394 maxX = -256; 5766 maxX = float.MinValue;
5395 minY = 256; 5767 minY = float.MaxValue;
5396 maxY = -256; 5768 maxY = float.MinValue;
5397 minZ = 8192; 5769 minZ = float.MaxValue;
5398 maxZ = -256; 5770 maxZ = float.MinValue;
5399 5771
5400 List<Vector3> offsets = new List<Vector3>(); 5772 List<Vector3> offsets = new List<Vector3>();
5401 5773
@@ -5406,7 +5778,7 @@ namespace OpenSim.Region.Framework.Scenes
5406 Vector3 vec = g.AbsolutePosition; 5778 Vector3 vec = g.AbsolutePosition;
5407 5779
5408 g.GetAxisAlignedBoundingBoxRaw(out ominX, out omaxX, out ominY, out omaxY, out ominZ, out omaxZ); 5780 g.GetAxisAlignedBoundingBoxRaw(out ominX, out omaxX, out ominY, out omaxY, out ominZ, out omaxZ);
5409 5781
5410// m_log.DebugFormat( 5782// m_log.DebugFormat(
5411// "[SCENE]: For {0} found AxisAlignedBoundingBoxRaw {1}, {2}", 5783// "[SCENE]: For {0} found AxisAlignedBoundingBoxRaw {1}, {2}",
5412// g.Name, new Vector3(ominX, ominY, ominZ), new Vector3(omaxX, omaxY, omaxZ)); 5784// g.Name, new Vector3(ominX, ominY, ominZ), new Vector3(omaxX, omaxY, omaxZ));
@@ -5465,7 +5837,7 @@ namespace OpenSim.Region.Framework.Scenes
5465 // so that all simulators can retrieve it 5837 // so that all simulators can retrieve it
5466 string error = GridService.RegisterRegion(RegionInfo.ScopeID, new GridRegion(RegionInfo)); 5838 string error = GridService.RegisterRegion(RegionInfo.ScopeID, new GridRegion(RegionInfo));
5467 if (error != string.Empty) 5839 if (error != string.Empty)
5468 throw new Exception(error); 5840 throw new Exception(error);
5469 } 5841 }
5470 5842
5471 /// <summary> 5843 /// <summary>
@@ -5479,22 +5851,23 @@ namespace OpenSim.Region.Framework.Scenes
5479 /// or corssing the broder walking, but will NOT prevent 5851 /// or corssing the broder walking, but will NOT prevent
5480 /// child agent creation, thereby emulating the SL behavior. 5852 /// child agent creation, thereby emulating the SL behavior.
5481 /// </remarks> 5853 /// </remarks>
5482 /// <param name='agentID'></param> 5854 /// <param name='agentID'>The visitor's User ID</param>
5855 /// <param name="agentHomeURI">The visitor's Home URI (may be null)</param>
5483 /// <param name='position'></param> 5856 /// <param name='position'></param>
5484 /// <param name='reason'></param> 5857 /// <param name='reason'></param>
5485 /// <returns></returns> 5858 /// <returns></returns>
5486 public bool QueryAccess(UUID agentID, Vector3 position, out string reason) 5859 public bool QueryAccess(UUID agentID, string agentHomeURI, bool viaTeleport, Vector3 position, List<UUID> features, out string reason)
5487 { 5860 {
5488 if (EntityTransferModule.IsInTransit(agentID)) 5861 reason = string.Empty;
5489 {
5490 reason = "Agent is still in transit from this region";
5491 5862
5492 m_log.WarnFormat( 5863 if (Permissions.IsGod(agentID))
5493 "[SCENE]: Denying agent {0} entry into {1} since region still has them registered as in transit", 5864 {
5494 agentID, RegionInfo.RegionName); 5865 reason = String.Empty;
5866 return true;
5867 }
5495 5868
5869 if (!AllowAvatarCrossing && !viaTeleport)
5496 return false; 5870 return false;
5497 }
5498 5871
5499 // FIXME: Root agent count is currently known to be inaccurate. This forces a recount before we check. 5872 // FIXME: Root agent count is currently known to be inaccurate. This forces a recount before we check.
5500 // However, the long term fix is to make sure root agent count is always accurate. 5873 // However, the long term fix is to make sure root agent count is always accurate.
@@ -5516,7 +5889,43 @@ namespace OpenSim.Region.Framework.Scenes
5516 } 5889 }
5517 } 5890 }
5518 5891
5519 if (position == Vector3.Zero) // Teleport 5892 ScenePresence presence = GetScenePresence(agentID);
5893 IClientAPI client = null;
5894 AgentCircuitData aCircuit = null;
5895
5896 if (presence != null)
5897 {
5898 client = presence.ControllingClient;
5899 if (client != null)
5900 aCircuit = client.RequestClientInfo();
5901 }
5902
5903 // We may be called before there is a presence or a client.
5904 // Fake AgentCircuitData to keep IAuthorizationModule smiling
5905 if (client == null)
5906 {
5907 aCircuit = new AgentCircuitData();
5908 aCircuit.AgentID = agentID;
5909 aCircuit.firstname = String.Empty;
5910 aCircuit.lastname = String.Empty;
5911 }
5912
5913 try
5914 {
5915 if (!AuthorizeUser(aCircuit, false, out reason))
5916 {
5917 //m_log.DebugFormat("[SCENE]: Denying access for {0}", agentID);
5918 return false;
5919 }
5920 }
5921 catch (Exception e)
5922 {
5923 m_log.DebugFormat("[SCENE]: Exception authorizing agent: {0} " + e.StackTrace, e.Message);
5924 reason = "Error authorizing agent: " + e.Message;
5925 return false;
5926 }
5927
5928 if (viaTeleport)
5520 { 5929 {
5521 if (!RegionInfo.EstateSettings.AllowDirectTeleport) 5930 if (!RegionInfo.EstateSettings.AllowDirectTeleport)
5522 { 5931 {
@@ -5539,11 +5948,47 @@ namespace OpenSim.Region.Framework.Scenes
5539 5948
5540 if (banned) 5949 if (banned)
5541 { 5950 {
5542 reason = "No suitable landing point found"; 5951 if (Permissions.IsAdministrator(agentID) == false || Permissions.IsGridGod(agentID) == false)
5543 return false; 5952 {
5953 reason = "No suitable landing point found";
5954 return false;
5955 }
5956 reason = "Administrative access only";
5957 return true;
5544 } 5958 }
5545 } 5959 }
5546 } 5960 }
5961
5962 float posX = 128.0f;
5963 float posY = 128.0f;
5964
5965 if (!TestLandRestrictions(agentID, out reason, ref posX, ref posY))
5966 {
5967 // m_log.DebugFormat("[SCENE]: Denying {0} because they are banned on all parcels", agentID);
5968 reason = "You are banned from the region on all parcels";
5969 return false;
5970 }
5971 }
5972 else // Walking
5973 {
5974 ILandObject land = LandChannel.GetLandObject(position.X, position.Y);
5975 if (land == null)
5976 {
5977 reason = "No parcel found";
5978 return false;
5979 }
5980
5981 bool banned = land.IsBannedFromLand(agentID);
5982 bool restricted = land.IsRestrictedFromLand(agentID);
5983
5984 if (banned || restricted)
5985 {
5986 if (banned)
5987 reason = "You are banned from the parcel";
5988 else
5989 reason = "The parcel is restricted";
5990 return false;
5991 }
5547 } 5992 }
5548 5993
5549 reason = String.Empty; 5994 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
44 { 44 {
45 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 45 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
46 46
47#pragma warning disable 414
48 private static readonly string LogHeader = "[SCENE]";
49#pragma warning restore 414
50
47 #region Events 51 #region Events
48 52
49 public event restart OnRestart; 53 public event restart OnRestart;
@@ -78,6 +82,13 @@ namespace OpenSim.Region.Framework.Scenes
78 /// </value> 82 /// </value>
79 protected Dictionary<Type, List<object>> ModuleInterfaces = new Dictionary<Type, List<object>>(); 83 protected Dictionary<Type, List<object>> ModuleInterfaces = new Dictionary<Type, List<object>>();
80 84
85 /// <summary>
86 /// These two objects hold the information about any formats used
87 /// by modules that hold agent specific data.
88 /// </summary>
89 protected List<UUID> FormatsOffered = new List<UUID>();
90 protected Dictionary<object, List<UUID>> FormatsWanted = new Dictionary<object, List<UUID>>();
91
81 protected Dictionary<string, object> ModuleAPIMethods = new Dictionary<string, object>(); 92 protected Dictionary<string, object> ModuleAPIMethods = new Dictionary<string, object>();
82 93
83 /// <value> 94 /// <value>
@@ -141,10 +152,6 @@ namespace OpenSim.Region.Framework.Scenes
141 get { return 1.0f; } 152 get { return 1.0f; }
142 } 153 }
143 154
144 protected ulong m_regionHandle;
145 protected string m_regionName;
146 protected RegionInfo m_regInfo;
147
148 public ITerrainChannel Heightmap; 155 public ITerrainChannel Heightmap;
149 156
150 /// <value> 157 /// <value>
@@ -192,7 +199,8 @@ namespace OpenSim.Region.Framework.Scenes
192 /// Number of frames to update. Exits on shutdown even if there are frames remaining. 199 /// Number of frames to update. Exits on shutdown even if there are frames remaining.
193 /// If -1 then updates until shutdown. 200 /// If -1 then updates until shutdown.
194 /// </param> 201 /// </param>
195 public abstract void Update(int frames); 202 /// <returns>true if update completed within minimum frame time, false otherwise.</returns>
203 public abstract bool Update(int frames);
196 204
197 #endregion 205 #endregion
198 206
@@ -209,15 +217,21 @@ namespace OpenSim.Region.Framework.Scenes
209 /// <param name="RemoteClient">Client to send to</param> 217 /// <param name="RemoteClient">Client to send to</param>
210 public virtual void SendLayerData(IClientAPI RemoteClient) 218 public virtual void SendLayerData(IClientAPI RemoteClient)
211 { 219 {
212 RemoteClient.SendLayerData(Heightmap.GetFloatsSerialised()); 220 // RemoteClient.SendLayerData(Heightmap.GetFloatsSerialised());
221 ITerrainModule terrModule = RequestModuleInterface<ITerrainModule>();
222 if (terrModule != null)
223 {
224 terrModule.PushTerrain(RemoteClient);
225 }
213 } 226 }
214 227
215 #endregion 228 #endregion
216 229
217 #region Add/Remove Agent/Avatar 230 #region Add/Remove Agent/Avatar
218 231
219 public abstract ISceneAgent AddNewClient(IClientAPI client, PresenceType type); 232 public abstract ISceneAgent AddNewAgent(IClientAPI client, PresenceType type);
220 public abstract void RemoveClient(UUID agentID, bool closeChildAgents); 233
234 public abstract bool CloseAgent(UUID agentID, bool force);
221 235
222 public bool TryGetScenePresence(UUID agentID, out object scenePresence) 236 public bool TryGetScenePresence(UUID agentID, out object scenePresence)
223 { 237 {
@@ -360,6 +374,38 @@ namespace OpenSim.Region.Framework.Scenes
360 return m_moduleCommanders; 374 return m_moduleCommanders;
361 } 375 }
362 376
377 public List<UUID> GetFormatsOffered()
378 {
379 List<UUID> ret = new List<UUID>(FormatsOffered);
380
381 return ret;
382 }
383
384 protected void CheckAndAddAgentDataFormats(object mod)
385 {
386 if (!(mod is IAgentStatefulModule))
387 return;
388
389 IAgentStatefulModule m = (IAgentStatefulModule)mod;
390
391 List<UUID> renderFormats = m.GetRenderStateFormats();
392 List<UUID> acceptFormats = m.GetAcceptStateFormats();
393
394 foreach (UUID render in renderFormats)
395 {
396 if (!(FormatsOffered.Contains(render)))
397 FormatsOffered.Add(render);
398 }
399
400 if (acceptFormats.Count == 0)
401 return;
402
403 if (FormatsWanted.ContainsKey(mod))
404 return;
405
406 FormatsWanted[mod] = acceptFormats;
407 }
408
363 /// <summary> 409 /// <summary>
364 /// Register an interface to a region module. This allows module methods to be called directly as 410 /// Register an interface to a region module. This allows module methods to be called directly as
365 /// well as via events. If there is already a module registered for this interface, it is not replaced 411 /// well as via events. If there is already a module registered for this interface, it is not replaced
@@ -382,6 +428,8 @@ namespace OpenSim.Region.Framework.Scenes
382 428
383 l.Add(mod); 429 l.Add(mod);
384 430
431 CheckAndAddAgentDataFormats(mod);
432
385 if (mod is IEntityCreator) 433 if (mod is IEntityCreator)
386 { 434 {
387 IEntityCreator entityCreator = (IEntityCreator)mod; 435 IEntityCreator entityCreator = (IEntityCreator)mod;
@@ -394,6 +442,14 @@ namespace OpenSim.Region.Framework.Scenes
394 442
395 public void UnregisterModuleInterface<M>(M mod) 443 public void UnregisterModuleInterface<M>(M mod)
396 { 444 {
445 // We can't unregister agent stateful modules because
446 // that would require much more data to be held about formats
447 // and would make that code slower and less efficient.
448 // No known modules are unregistered anyway, ever, unless
449 // the simulator shuts down anyway.
450 if (mod is IAgentStatefulModule)
451 return;
452
397 List<Object> l; 453 List<Object> l;
398 if (ModuleInterfaces.TryGetValue(typeof(M), out l)) 454 if (ModuleInterfaces.TryGetValue(typeof(M), out l))
399 { 455 {
@@ -424,6 +480,8 @@ namespace OpenSim.Region.Framework.Scenes
424 480
425 l.Add(mod); 481 l.Add(mod);
426 482
483 CheckAndAddAgentDataFormats(mod);
484
427 if (mod is IEntityCreator) 485 if (mod is IEntityCreator)
428 { 486 {
429 IEntityCreator entityCreator = (IEntityCreator)mod; 487 IEntityCreator entityCreator = (IEntityCreator)mod;
@@ -561,6 +619,10 @@ namespace OpenSim.Region.Framework.Scenes
561 get { return false; } 619 get { return false; }
562 } 620 }
563 621
622 public virtual void Start()
623 {
624 }
625
564 public void Restart() 626 public void Restart()
565 { 627 {
566 // This has to be here to fire the event 628 // This has to be here to fire the event
diff --git a/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs b/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs
index 305f8a4..b9526da 100644
--- a/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs
@@ -35,7 +35,6 @@ using OpenMetaverse.StructuredData;
35using log4net; 35using log4net;
36using OpenSim.Framework; 36using OpenSim.Framework;
37using OpenSim.Framework.Client; 37using OpenSim.Framework.Client;
38using OpenSim.Framework.Communications;
39using OpenSim.Framework.Capabilities; 38using OpenSim.Framework.Capabilities;
40using OpenSim.Region.Framework.Interfaces; 39using OpenSim.Region.Framework.Interfaces;
41using OpenSim.Services.Interfaces; 40using OpenSim.Services.Interfaces;
@@ -52,6 +51,7 @@ namespace OpenSim.Region.Framework.Scenes
52 public class SceneCommunicationService //one instance per region 51 public class SceneCommunicationService //one instance per region
53 { 52 {
54 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 53 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
54 private static string LogHeader = "[SCENE COMMUNICATION SERVICE]";
55 55
56 protected RegionInfo m_regionInfo; 56 protected RegionInfo m_regionInfo;
57 protected Scene m_scene; 57 protected Scene m_scene;
@@ -84,15 +84,12 @@ namespace OpenSim.Region.Framework.Scenes
84 if (neighbourService != null) 84 if (neighbourService != null)
85 neighbour = neighbourService.HelloNeighbour(regionhandle, region); 85 neighbour = neighbourService.HelloNeighbour(regionhandle, region);
86 else 86 else
87 m_log.DebugFormat( 87 m_log.DebugFormat( "{0} neighbour service provided for region {0} to inform neigbhours of status", LogHeader, m_scene.Name);
88 "[SCENE COMMUNICATION SERVICE]: No neighbour service provided for region {0} to inform neigbhours of status",
89 m_scene.Name);
90 88
91 if (neighbour != null) 89 if (neighbour != null)
92 { 90 {
93 m_log.DebugFormat( 91 m_log.DebugFormat( "{0} Region {1} successfully informed neighbour {2} at {3}-{4} that it is up",
94 "[SCENE COMMUNICATION SERVICE]: Region {0} successfully informed neighbour {1} at {2}-{3} that it is up", 92 LogHeader, m_scene.Name, neighbour.RegionName, Util.WorldToRegionLoc(x), Util.WorldToRegionLoc(y));
95 m_scene.Name, neighbour.RegionName, x / Constants.RegionSize, y / Constants.RegionSize);
96 93
97 m_scene.EventManager.TriggerOnRegionUp(neighbour); 94 m_scene.EventManager.TriggerOnRegionUp(neighbour);
98 } 95 }
@@ -100,7 +97,7 @@ namespace OpenSim.Region.Framework.Scenes
100 { 97 {
101 m_log.WarnFormat( 98 m_log.WarnFormat(
102 "[SCENE COMMUNICATION SERVICE]: Region {0} failed to inform neighbour at {1}-{2} that it is up.", 99 "[SCENE COMMUNICATION SERVICE]: Region {0} failed to inform neighbour at {1}-{2} that it is up.",
103 m_scene.Name, x / Constants.RegionSize, y / Constants.RegionSize); 100 m_scene.Name, Util.WorldToRegionLoc(x), Util.WorldToRegionLoc(y));
104 } 101 }
105 } 102 }
106 103
@@ -111,12 +108,35 @@ namespace OpenSim.Region.Framework.Scenes
111 List<GridRegion> neighbours 108 List<GridRegion> neighbours
112 = m_scene.GridService.GetNeighbours(m_scene.RegionInfo.ScopeID, m_scene.RegionInfo.RegionID); 109 = m_scene.GridService.GetNeighbours(m_scene.RegionInfo.ScopeID, m_scene.RegionInfo.RegionID);
113 110
114 m_log.DebugFormat( 111 List<GridRegion> onlineNeighbours = new List<GridRegion>();
115 "[SCENE COMMUNICATION SERVICE]: Informing {0} neighbours that region {1} is up",
116 neighbours.Count, m_scene.Name);
117 112
118 foreach (GridRegion n in neighbours) 113 foreach (GridRegion n in neighbours)
119 { 114 {
115 OpenSim.Framework.RegionFlags? regionFlags = n.RegionFlags;
116
117// m_log.DebugFormat(
118// "{0}: Region flags for {1} as seen by {2} are {3}",
119// LogHeader, n.RegionName, m_scene.Name, regionFlags != null ? regionFlags.ToString() : "not present");
120
121 // Robust services before 2015-01-14 do not return the regionFlags information. In this case, we could
122 // make a separate RegionFlags call but this would involve a network call for each neighbour.
123 if (regionFlags != null)
124 {
125 if ((regionFlags & OpenSim.Framework.RegionFlags.RegionOnline) != 0)
126 onlineNeighbours.Add(n);
127 }
128 else
129 {
130 onlineNeighbours.Add(n);
131 }
132 }
133
134 m_log.DebugFormat(
135 "{0} Informing {1} neighbours that region {2} is up",
136 LogHeader, onlineNeighbours.Count, m_scene.Name);
137
138 foreach (GridRegion n in onlineNeighbours)
139 {
120 InformNeighbourThatRegionUpDelegate d = InformNeighboursThatRegionIsUpAsync; 140 InformNeighbourThatRegionUpDelegate d = InformNeighboursThatRegionIsUpAsync;
121 d.BeginInvoke(neighbourService, region, n.RegionHandle, 141 d.BeginInvoke(neighbourService, region, n.RegionHandle,
122 InformNeighborsThatRegionisUpCompleted, 142 InformNeighborsThatRegionisUpCompleted,
@@ -154,6 +174,10 @@ namespace OpenSim.Region.Framework.Scenes
154 174
155 public void SendChildAgentDataUpdate(AgentPosition cAgentData, ScenePresence presence) 175 public void SendChildAgentDataUpdate(AgentPosition cAgentData, ScenePresence presence)
156 { 176 {
177// m_log.DebugFormat(
178// "[SCENE COMMUNICATION SERVICE]: Sending child agent position updates for {0} in {1}",
179// presence.Name, m_scene.Name);
180
157 // This assumes that we know what our neighbors are. 181 // This assumes that we know what our neighbors are.
158 try 182 try
159 { 183 {
@@ -166,7 +190,7 @@ namespace OpenSim.Region.Framework.Scenes
166 // we only want to send one update to each simulator; the simulator will 190 // we only want to send one update to each simulator; the simulator will
167 // hand it off to the regions where a child agent exists, this does assume 191 // hand it off to the regions where a child agent exists, this does assume
168 // that the region position is cached or performance will degrade 192 // that the region position is cached or performance will degrade
169 Utils.LongToUInts(regionHandle, out x, out y); 193 Util.RegionHandleToWorldLoc(regionHandle, out x, out y);
170 GridRegion dest = m_scene.GridService.GetRegionByPosition(UUID.Zero, (int)x, (int)y); 194 GridRegion dest = m_scene.GridService.GetRegionByPosition(UUID.Zero, (int)x, (int)y);
171 if (dest == null) 195 if (dest == null)
172 continue; 196 continue;
@@ -197,20 +221,20 @@ namespace OpenSim.Region.Framework.Scenes
197 /// <summary> 221 /// <summary>
198 /// Closes a child agent on a given region 222 /// Closes a child agent on a given region
199 /// </summary> 223 /// </summary>
200 protected void SendCloseChildAgent(UUID agentID, ulong regionHandle) 224 protected void SendCloseChildAgent(UUID agentID, ulong regionHandle, string auth_token)
201 { 225 {
202 // let's do our best, but there's not much we can do if the neighbour doesn't accept. 226 // let's do our best, but there's not much we can do if the neighbour doesn't accept.
203 227
204 //m_commsProvider.InterRegion.TellRegionToCloseChildConnection(regionHandle, agentID); 228 //m_commsProvider.InterRegion.TellRegionToCloseChildConnection(regionHandle, agentID);
205 uint x = 0, y = 0; 229 uint x = 0, y = 0;
206 Utils.LongToUInts(regionHandle, out x, out y); 230 Util.RegionHandleToWorldLoc(regionHandle, out x, out y);
207 231
208 GridRegion destination = m_scene.GridService.GetRegionByPosition(m_regionInfo.ScopeID, (int)x, (int)y); 232 GridRegion destination = m_scene.GridService.GetRegionByPosition(m_regionInfo.ScopeID, (int)x, (int)y);
209 233
210 m_log.DebugFormat( 234 m_log.DebugFormat(
211 "[SCENE COMMUNICATION SERVICE]: Sending close agent ID {0} to {1}", agentID, destination.RegionName); 235 "[SCENE COMMUNICATION SERVICE]: Sending close agent ID {0} to {1}", agentID, destination.RegionName);
212 236
213 m_scene.SimulationService.CloseAgent(destination, agentID); 237 m_scene.SimulationService.CloseAgent(destination, agentID, auth_token);
214 } 238 }
215 239
216 /// <summary> 240 /// <summary>
@@ -219,11 +243,17 @@ namespace OpenSim.Region.Framework.Scenes
219 /// </summary> 243 /// </summary>
220 /// <param name="agentID"></param> 244 /// <param name="agentID"></param>
221 /// <param name="regionslst"></param> 245 /// <param name="regionslst"></param>
222 public void SendCloseChildAgentConnections(UUID agentID, List<ulong> regionslst) 246 public void SendCloseChildAgentConnections(UUID agentID, string auth_code, List<ulong> regionslst)
223 { 247 {
224 foreach (ulong handle in regionslst) 248 foreach (ulong handle in regionslst)
225 { 249 {
226 SendCloseChildAgent(agentID, handle); 250 // We must take a copy here since handle is acts like a reference when used in an iterator.
251 // This leads to race conditions if directly passed to SendCloseChildAgent with more than one neighbour region.
252 ulong handleCopy = handle;
253 Util.FireAndForget(
254 o => SendCloseChildAgent(agentID, handleCopy, auth_code),
255 null,
256 "SceneCommunicationService.SendCloseChildAgentConnections");
227 } 257 }
228 } 258 }
229 259
diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
index a4383fd..e0080f2 100644..100755
--- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
@@ -34,7 +34,7 @@ using OpenMetaverse.Packets;
34using log4net; 34using log4net;
35using OpenSim.Framework; 35using OpenSim.Framework;
36using OpenSim.Region.Framework.Scenes.Types; 36using OpenSim.Region.Framework.Scenes.Types;
37using OpenSim.Region.Physics.Manager; 37using OpenSim.Region.PhysicsModules.SharedBase;
38using OpenSim.Region.Framework.Interfaces; 38using OpenSim.Region.Framework.Interfaces;
39 39
40namespace OpenSim.Region.Framework.Scenes 40namespace OpenSim.Region.Framework.Scenes
@@ -67,7 +67,9 @@ namespace OpenSim.Region.Framework.Scenes
67 protected Scene m_parentScene; 67 protected Scene m_parentScene;
68 protected Dictionary<UUID, SceneObjectGroup> m_updateList = new Dictionary<UUID, SceneObjectGroup>(); 68 protected Dictionary<UUID, SceneObjectGroup> m_updateList = new Dictionary<UUID, SceneObjectGroup>();
69 protected int m_numRootAgents = 0; 69 protected int m_numRootAgents = 0;
70 protected int m_numTotalPrim = 0;
70 protected int m_numPrim = 0; 71 protected int m_numPrim = 0;
72 protected int m_numMesh = 0;
71 protected int m_numChildAgents = 0; 73 protected int m_numChildAgents = 0;
72 protected int m_physicalPrim = 0; 74 protected int m_physicalPrim = 0;
73 75
@@ -109,7 +111,12 @@ namespace OpenSim.Region.Framework.Scenes
109 111
110 public PhysicsScene PhysicsScene 112 public PhysicsScene PhysicsScene
111 { 113 {
112 get { return _PhyScene; } 114 get
115 {
116 if (_PhyScene == null)
117 _PhyScene = m_parentScene.RequestModuleInterface<PhysicsScene>();
118 return _PhyScene;
119 }
113 set 120 set
114 { 121 {
115 // If we're not doing the initial set 122 // If we're not doing the initial set
@@ -155,9 +162,9 @@ namespace OpenSim.Region.Framework.Scenes
155 162
156 // PhysX does this (runs in the background). 163 // PhysX does this (runs in the background).
157 164
158 if (_PhyScene.IsThreaded) 165 if (PhysicsScene.IsThreaded)
159 { 166 {
160 _PhyScene.GetResults(); 167 PhysicsScene.GetResults();
161 } 168 }
162 } 169 }
163 170
@@ -197,7 +204,7 @@ namespace OpenSim.Region.Framework.Scenes
197 // position). 204 // position).
198 // 205 //
199 // Therefore, JointMoved and JointDeactivated events will be fired as a result of the following Simulate(). 206 // Therefore, JointMoved and JointDeactivated events will be fired as a result of the following Simulate().
200 return _PhyScene.Simulate((float)elapsed); 207 return PhysicsScene.Simulate((float)elapsed);
201 } 208 }
202 209
203 protected internal void UpdateScenePresenceMovement() 210 protected internal void UpdateScenePresenceMovement()
@@ -368,7 +375,8 @@ namespace OpenSim.Region.Framework.Scenes
368 375
369 SceneObjectPart[] parts = sceneObject.Parts; 376 SceneObjectPart[] parts = sceneObject.Parts;
370 377
371 // Clamp child prim sizes and add child prims to the m_numPrim count 378 // Clamp the sizes (scales) of the child prims and add the child prims to the count of all primitives
379 // (meshes and geometric primitives) in the scene; add child prims to m_numTotalPrim count
372 if (m_parentScene.m_clampPrimSize) 380 if (m_parentScene.m_clampPrimSize)
373 { 381 {
374 foreach (SceneObjectPart part in parts) 382 foreach (SceneObjectPart part in parts)
@@ -382,7 +390,19 @@ namespace OpenSim.Region.Framework.Scenes
382 part.Shape.Scale = scale; 390 part.Shape.Scale = scale;
383 } 391 }
384 } 392 }
385 m_numPrim += parts.Length; 393 m_numTotalPrim += parts.Length;
394
395 // Go through all parts (geometric primitives and meshes) of this Scene Object
396 foreach (SceneObjectPart part in parts)
397 {
398 // Keep track of the total number of meshes or geometric primitives now in the scene;
399 // determine which object this is based on its primitive type: sculpted (sculpt) prim refers to
400 // a mesh and all other prims (i.e. box, sphere, etc) are geometric primitives
401 if (part.GetPrimType() == PrimType.SCULPT)
402 m_numMesh++;
403 else
404 m_numPrim++;
405 }
386 406
387 sceneObject.AttachToScene(m_parentScene); 407 sceneObject.AttachToScene(m_parentScene);
388 408
@@ -437,7 +457,21 @@ namespace OpenSim.Region.Framework.Scenes
437 457
438 if (!resultOfObjectLinked) 458 if (!resultOfObjectLinked)
439 { 459 {
440 m_numPrim -= grp.PrimCount; 460 // Decrement the total number of primitives (meshes and geometric primitives)
461 // that are part of the Scene Object being removed
462 m_numTotalPrim -= grp.PrimCount;
463
464 // Go through all parts (primitives and meshes) of this Scene Object
465 foreach (SceneObjectPart part in grp.Parts)
466 {
467 // Keep track of the total number of meshes or geometric primitives left in the scene;
468 // determine which object this is based on its primitive type: sculpted (sculpt) prim refers to
469 // a mesh and all other prims (i.e. box, sphere, etc) are geometric primitives
470 if (part.GetPrimType() == PrimType.SCULPT)
471 m_numMesh--;
472 else
473 m_numPrim--;
474 }
441 475
442 if ((grp.RootPart.Flags & PrimFlags.Physics) == PrimFlags.Physics) 476 if ((grp.RootPart.Flags & PrimFlags.Physics) == PrimFlags.Physics)
443 RemovePhysicalPrim(grp.PrimCount); 477 RemovePhysicalPrim(grp.PrimCount);
@@ -519,12 +553,12 @@ namespace OpenSim.Region.Framework.Scenes
519 553
520 protected internal void AddPhysicalPrim(int number) 554 protected internal void AddPhysicalPrim(int number)
521 { 555 {
522 m_physicalPrim++; 556 m_physicalPrim += number;
523 } 557 }
524 558
525 protected internal void RemovePhysicalPrim(int number) 559 protected internal void RemovePhysicalPrim(int number)
526 { 560 {
527 m_physicalPrim--; 561 m_physicalPrim -= number;
528 } 562 }
529 563
530 protected internal void AddToScriptLPS(int number) 564 protected internal void AddToScriptLPS(int number)
@@ -561,39 +595,15 @@ namespace OpenSim.Region.Framework.Scenes
561 protected internal ScenePresence CreateAndAddChildScenePresence( 595 protected internal ScenePresence CreateAndAddChildScenePresence(
562 IClientAPI client, AvatarAppearance appearance, PresenceType type) 596 IClientAPI client, AvatarAppearance appearance, PresenceType type)
563 { 597 {
564 ScenePresence newAvatar = null;
565
566 // ScenePresence always defaults to child agent 598 // ScenePresence always defaults to child agent
567 newAvatar = new ScenePresence(client, m_parentScene, appearance, type); 599 ScenePresence presence = new ScenePresence(client, m_parentScene, appearance, type);
568
569 AddScenePresence(newAvatar);
570
571 return newAvatar;
572 }
573
574 /// <summary>
575 /// Add a presence to the scene
576 /// </summary>
577 /// <param name="presence"></param>
578 protected internal void AddScenePresence(ScenePresence presence)
579 {
580 // Always a child when added to the scene
581 bool child = presence.IsChildAgent;
582
583 if (child)
584 {
585 m_numChildAgents++;
586 }
587 else
588 {
589 m_numRootAgents++;
590 presence.AddToPhysicalScene(false);
591 }
592 600
593 Entities[presence.UUID] = presence; 601 Entities[presence.UUID] = presence;
594 602
595 lock (m_presenceLock) 603 lock (m_presenceLock)
596 { 604 {
605 m_numChildAgents++;
606
597 Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap); 607 Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap);
598 List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray); 608 List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray);
599 609
@@ -604,7 +614,7 @@ namespace OpenSim.Region.Framework.Scenes
604 } 614 }
605 else 615 else
606 { 616 {
607 // Remember the old presene reference from the dictionary 617 // Remember the old presence reference from the dictionary
608 ScenePresence oldref = newmap[presence.UUID]; 618 ScenePresence oldref = newmap[presence.UUID];
609 // Replace the presence reference in the dictionary with the new value 619 // Replace the presence reference in the dictionary with the new value
610 newmap[presence.UUID] = presence; 620 newmap[presence.UUID] = presence;
@@ -616,6 +626,8 @@ namespace OpenSim.Region.Framework.Scenes
616 m_scenePresenceMap = newmap; 626 m_scenePresenceMap = newmap;
617 m_scenePresenceArray = newlist; 627 m_scenePresenceArray = newlist;
618 } 628 }
629
630 return presence;
619 } 631 }
620 632
621 /// <summary> 633 /// <summary>
@@ -709,9 +721,19 @@ namespace OpenSim.Region.Framework.Scenes
709 721
710 public int GetTotalObjectsCount() 722 public int GetTotalObjectsCount()
711 { 723 {
724 return m_numTotalPrim;
725 }
726
727 public int GetTotalPrimObjectsCount()
728 {
712 return m_numPrim; 729 return m_numPrim;
713 } 730 }
714 731
732 public int GetTotalMeshObjectsCount()
733 {
734 return m_numMesh;
735 }
736
715 public int GetActiveObjectsCount() 737 public int GetActiveObjectsCount()
716 { 738 {
717 return m_physicalPrim; 739 return m_physicalPrim;
@@ -794,7 +816,8 @@ namespace OpenSim.Region.Framework.Scenes
794 List<ScenePresence> presences = GetScenePresences(); 816 List<ScenePresence> presences = GetScenePresences();
795 foreach (ScenePresence presence in presences) 817 foreach (ScenePresence presence in presences)
796 { 818 {
797 if (presence.Firstname == firstName && presence.Lastname == lastName) 819 if (string.Equals(presence.Firstname, firstName, StringComparison.CurrentCultureIgnoreCase)
820 && string.Equals(presence.Lastname, lastName, StringComparison.CurrentCultureIgnoreCase))
798 return presence; 821 return presence;
799 } 822 }
800 return null; 823 return null;
@@ -1348,12 +1371,23 @@ namespace OpenSim.Region.Framework.Scenes
1348 /// <summary> 1371 /// <summary>
1349 /// Update the position of the given group. 1372 /// Update the position of the given group.
1350 /// </summary> 1373 /// </summary>
1351 /// <param name="localID"></param> 1374 /// <param name="localId"></param>
1352 /// <param name="pos"></param> 1375 /// <param name="pos"></param>
1353 /// <param name="remoteClient"></param> 1376 /// <param name="remoteClient"></param>
1354 public void UpdatePrimGroupPosition(uint localID, Vector3 pos, IClientAPI remoteClient) 1377 public void UpdatePrimGroupPosition(uint localId, Vector3 pos, IClientAPI remoteClient)
1355 { 1378 {
1356 SceneObjectGroup group = GetGroupByPrim(localID); 1379 UpdatePrimGroupPosition(localId, pos, remoteClient.AgentId);
1380 }
1381
1382 /// <summary>
1383 /// Update the position of the given group.
1384 /// </summary>
1385 /// <param name="localId"></param>
1386 /// <param name="pos"></param>
1387 /// <param name="updatingAgentId"></param>
1388 public void UpdatePrimGroupPosition(uint localId, Vector3 pos, UUID updatingAgentId)
1389 {
1390 SceneObjectGroup group = GetGroupByPrim(localId);
1357 1391
1358 if (group != null) 1392 if (group != null)
1359 { 1393 {
@@ -1364,7 +1398,7 @@ namespace OpenSim.Region.Framework.Scenes
1364 } 1398 }
1365 else 1399 else
1366 { 1400 {
1367 if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId) 1401 if (m_parentScene.Permissions.CanMoveObject(group.UUID, updatingAgentId)
1368 && m_parentScene.Permissions.CanObjectEntry(group.UUID, false, pos)) 1402 && m_parentScene.Permissions.CanObjectEntry(group.UUID, false, pos))
1369 { 1403 {
1370 group.UpdateGroupPosition(pos); 1404 group.UpdateGroupPosition(pos);
@@ -1408,7 +1442,7 @@ namespace OpenSim.Region.Framework.Scenes
1408 /// <param name="SetPhantom"></param> 1442 /// <param name="SetPhantom"></param>
1409 /// <param name="remoteClient"></param> 1443 /// <param name="remoteClient"></param>
1410 protected internal void UpdatePrimFlags( 1444 protected internal void UpdatePrimFlags(
1411 uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, IClientAPI remoteClient) 1445 uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, ExtraPhysicsData PhysData, IClientAPI remoteClient)
1412 { 1446 {
1413 SceneObjectGroup group = GetGroupByPrim(localID); 1447 SceneObjectGroup group = GetGroupByPrim(localID);
1414 if (group != null) 1448 if (group != null)
@@ -1416,7 +1450,28 @@ namespace OpenSim.Region.Framework.Scenes
1416 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId)) 1450 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1417 { 1451 {
1418 // VolumeDetect can't be set via UI and will always be off when a change is made there 1452 // VolumeDetect can't be set via UI and will always be off when a change is made there
1419 group.UpdatePrimFlags(localID, UsePhysics, SetTemporary, SetPhantom, false); 1453 // now only change volume dtc if phantom off
1454
1455 if (PhysData.PhysShapeType == PhysShapeType.invalid) // check for extraPhysics data
1456 {
1457 bool vdtc;
1458 if (SetPhantom) // if phantom keep volumedtc
1459 vdtc = group.RootPart.VolumeDetectActive;
1460 else // else turn it off
1461 vdtc = false;
1462
1463 group.UpdatePrimFlags(localID, UsePhysics, SetTemporary, SetPhantom, vdtc);
1464 }
1465 else
1466 {
1467 SceneObjectPart part = GetSceneObjectPart(localID);
1468 if (part != null)
1469 {
1470 part.UpdateExtraPhysics(PhysData);
1471 if (part.UpdatePhysRequired)
1472 remoteClient.SendPartPhysicsProprieties(part);
1473 }
1474 }
1420 } 1475 }
1421 } 1476 }
1422 } 1477 }
@@ -1435,8 +1490,9 @@ namespace OpenSim.Region.Framework.Scenes
1435 { 1490 {
1436 if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId))// && PermissionsMngr.) 1491 if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId))// && PermissionsMngr.)
1437 { 1492 {
1438 group.GrabMovement(offset, pos, remoteClient); 1493 group.GrabMovement(objectID, offset, pos, remoteClient);
1439 } 1494 }
1495
1440 // This is outside the above permissions condition 1496 // This is outside the above permissions condition
1441 // so that if the object is locked the client moving the object 1497 // so that if the object is locked the client moving the object
1442 // get's it's position on the simulator even if it was the same as before 1498 // get's it's position on the simulator even if it was the same as before
@@ -1624,6 +1680,12 @@ namespace OpenSim.Region.Framework.Scenes
1624 /// <param name="childPrims"></param> 1680 /// <param name="childPrims"></param>
1625 protected internal void LinkObjects(SceneObjectPart root, List<SceneObjectPart> children) 1681 protected internal void LinkObjects(SceneObjectPart root, List<SceneObjectPart> children)
1626 { 1682 {
1683 if (root.KeyframeMotion != null)
1684 {
1685 root.KeyframeMotion.Stop();
1686 root.KeyframeMotion = null;
1687 }
1688
1627 SceneObjectGroup parentGroup = root.ParentGroup; 1689 SceneObjectGroup parentGroup = root.ParentGroup;
1628 if (parentGroup == null) return; 1690 if (parentGroup == null) return;
1629 1691
@@ -1701,6 +1763,11 @@ namespace OpenSim.Region.Framework.Scenes
1701 { 1763 {
1702 if (part != null) 1764 if (part != null)
1703 { 1765 {
1766 if (part.KeyframeMotion != null)
1767 {
1768 part.KeyframeMotion.Stop();
1769 part.KeyframeMotion = null;
1770 }
1704 if (part.ParentGroup.PrimCount != 1) // Skip single 1771 if (part.ParentGroup.PrimCount != 1) // Skip single
1705 { 1772 {
1706 if (part.LinkNum < 2) // Root 1773 if (part.LinkNum < 2) // Root
@@ -1884,7 +1951,7 @@ namespace OpenSim.Region.Framework.Scenes
1884 if (original == null) 1951 if (original == null)
1885 { 1952 {
1886 m_log.WarnFormat( 1953 m_log.WarnFormat(
1887 "[SCENEGRAPH]: Attempt to duplicate nonexistant prim id {0} by {1}", originalPrimID, AgentID); 1954 "[SCENEGRAPH]: Attempt to duplicate nonexistent prim id {0} by {1}", originalPrimID, AgentID);
1888 1955
1889 return null; 1956 return null;
1890 } 1957 }
@@ -1947,7 +2014,19 @@ namespace OpenSim.Region.Framework.Scenes
1947 // think it's selected, so it will never send a deselect... 2014 // think it's selected, so it will never send a deselect...
1948 copy.IsSelected = false; 2015 copy.IsSelected = false;
1949 2016
1950 m_numPrim += copy.Parts.Length; 2017 m_numTotalPrim += copy.Parts.Length;
2018
2019 // Go through all parts (primitives and meshes) of this Scene Object
2020 foreach (SceneObjectPart part in copy.Parts)
2021 {
2022 // Keep track of the total number of meshes or geometric primitives now in the scene;
2023 // determine which object this is based on its primitive type: sculpted (sculpt) prim refers to
2024 // a mesh and all other prims (i.e. box, sphere, etc) are geometric primitives
2025 if (part.GetPrimType() == PrimType.SCULPT)
2026 m_numMesh++;
2027 else
2028 m_numPrim++;
2029 }
1951 2030
1952 if (rot != Quaternion.Identity) 2031 if (rot != Quaternion.Identity)
1953 { 2032 {
diff --git a/OpenSim/Region/Framework/Scenes/SceneManager.cs b/OpenSim/Region/Framework/Scenes/SceneManager.cs
index 1e2e973..28f7896 100644
--- a/OpenSim/Region/Framework/Scenes/SceneManager.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneManager.cs
@@ -331,35 +331,30 @@ namespace OpenSim.Region.Framework.Scenes
331 331
332 public void SendCommandToPluginModules(string[] cmdparams) 332 public void SendCommandToPluginModules(string[] cmdparams)
333 { 333 {
334 ForEachCurrentScene(delegate(Scene scene) { scene.SendCommandToPlugins(cmdparams); }); 334 ForEachSelectedScene(delegate(Scene scene) { scene.SendCommandToPlugins(cmdparams); });
335 } 335 }
336 336
337 public void SetBypassPermissionsOnCurrentScene(bool bypassPermissions) 337 public void SetBypassPermissionsOnCurrentScene(bool bypassPermissions)
338 { 338 {
339 ForEachCurrentScene(delegate(Scene scene) { scene.Permissions.SetBypassPermissions(bypassPermissions); }); 339 ForEachSelectedScene(delegate(Scene scene) { scene.Permissions.SetBypassPermissions(bypassPermissions); });
340 } 340 }
341 341
342 private void ForEachCurrentScene(Action<Scene> func) 342 public void ForEachSelectedScene(Action<Scene> func)
343 { 343 {
344 if (CurrentScene == null) 344 if (CurrentScene == null)
345 { 345 ForEachScene(func);
346 lock (m_localScenes)
347 m_localScenes.ForEach(func);
348 }
349 else 346 else
350 {
351 func(CurrentScene); 347 func(CurrentScene);
352 }
353 } 348 }
354 349
355 public void RestartCurrentScene() 350 public void RestartCurrentScene()
356 { 351 {
357 ForEachCurrentScene(delegate(Scene scene) { scene.RestartNow(); }); 352 ForEachSelectedScene(delegate(Scene scene) { scene.RestartNow(); });
358 } 353 }
359 354
360 public void BackupCurrentScene() 355 public void BackupCurrentScene()
361 { 356 {
362 ForEachCurrentScene(delegate(Scene scene) { scene.Backup(true); }); 357 ForEachSelectedScene(delegate(Scene scene) { scene.Backup(true); });
363 } 358 }
364 359
365 public bool TrySetCurrentScene(string regionName) 360 public bool TrySetCurrentScene(string regionName)
@@ -482,34 +477,11 @@ namespace OpenSim.Region.Framework.Scenes
482 return false; 477 return false;
483 } 478 }
484 479
485 /// <summary>
486 /// Set the debug packet level on each current scene. This level governs which packets are printed out to the
487 /// console.
488 /// </summary>
489 /// <param name="newDebug"></param>
490 /// <param name="name">Name of avatar to debug</param>
491 public void SetDebugPacketLevelOnCurrentScene(int newDebug, string name)
492 {
493 ForEachCurrentScene(scene =>
494 scene.ForEachScenePresence(sp =>
495 {
496 if (name == null || sp.Name == name)
497 {
498 m_log.DebugFormat(
499 "Packet debug for {0} ({1}) set to {2}",
500 sp.Name, sp.IsChildAgent ? "child" : "root", newDebug);
501
502 sp.ControllingClient.DebugPacketLevel = newDebug;
503 }
504 })
505 );
506 }
507
508 public List<ScenePresence> GetCurrentSceneAvatars() 480 public List<ScenePresence> GetCurrentSceneAvatars()
509 { 481 {
510 List<ScenePresence> avatars = new List<ScenePresence>(); 482 List<ScenePresence> avatars = new List<ScenePresence>();
511 483
512 ForEachCurrentScene( 484 ForEachSelectedScene(
513 delegate(Scene scene) 485 delegate(Scene scene)
514 { 486 {
515 scene.ForEachRootScenePresence(delegate(ScenePresence scenePresence) 487 scene.ForEachRootScenePresence(delegate(ScenePresence scenePresence)
@@ -526,7 +498,7 @@ namespace OpenSim.Region.Framework.Scenes
526 { 498 {
527 List<ScenePresence> presences = new List<ScenePresence>(); 499 List<ScenePresence> presences = new List<ScenePresence>();
528 500
529 ForEachCurrentScene(delegate(Scene scene) 501 ForEachSelectedScene(delegate(Scene scene)
530 { 502 {
531 scene.ForEachScenePresence(delegate(ScenePresence sp) 503 scene.ForEachScenePresence(delegate(ScenePresence sp)
532 { 504 {
@@ -555,12 +527,12 @@ namespace OpenSim.Region.Framework.Scenes
555 527
556 public void ForceCurrentSceneClientUpdate() 528 public void ForceCurrentSceneClientUpdate()
557 { 529 {
558 ForEachCurrentScene(delegate(Scene scene) { scene.ForceClientUpdate(); }); 530 ForEachSelectedScene(delegate(Scene scene) { scene.ForceClientUpdate(); });
559 } 531 }
560 532
561 public void HandleEditCommandOnCurrentScene(string[] cmdparams) 533 public void HandleEditCommandOnCurrentScene(string[] cmdparams)
562 { 534 {
563 ForEachCurrentScene(delegate(Scene scene) { scene.HandleEditCommand(cmdparams); }); 535 ForEachSelectedScene(delegate(Scene scene) { scene.HandleEditCommand(cmdparams); });
564 } 536 }
565 537
566 public bool TryGetScenePresence(UUID avatarId, out ScenePresence avatar) 538 public bool TryGetScenePresence(UUID avatarId, out ScenePresence avatar)
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs
index ddf5da0..81cef5b 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs
@@ -34,6 +34,7 @@ using OpenSim.Framework;
34using OpenSim.Region.Framework.Interfaces; 34using OpenSim.Region.Framework.Interfaces;
35using System.Collections.Generic; 35using System.Collections.Generic;
36using System.Xml; 36using System.Xml;
37using PermissionMask = OpenSim.Framework.PermissionMask;
37 38
38namespace OpenSim.Region.Framework.Scenes 39namespace OpenSim.Region.Framework.Scenes
39{ 40{
@@ -66,6 +67,12 @@ namespace OpenSim.Region.Framework.Scenes
66 { 67 {
67 int scriptsStarted = 0; 68 int scriptsStarted = 0;
68 69
70 if (m_scene == null)
71 {
72 m_log.DebugFormat("[PRIM INVENTORY]: m_scene is null. Unable to create script instances");
73 return 0;
74 }
75
69 // Don't start scripts if they're turned off in the region! 76 // Don't start scripts if they're turned off in the region!
70 if (!m_scene.RegionInfo.RegionSettings.DisableScripts) 77 if (!m_scene.RegionInfo.RegionSettings.DisableScripts)
71 { 78 {
@@ -258,6 +265,7 @@ namespace OpenSim.Region.Framework.Scenes
258 for (int i = 0; i < parts.Length; i++) 265 for (int i = 0; i < parts.Length; i++)
259 { 266 {
260 SceneObjectPart part = parts[i]; 267 SceneObjectPart part = parts[i];
268// m_log.DebugFormat("[SCENE OBJECT GROUP INVENTORY]: Effective perms of {0} are {1}", part.Name, (OpenMetaverse.PermissionMask)part.OwnerMask);
261 ownerMask &= part.OwnerMask; 269 ownerMask &= part.OwnerMask;
262 perms &= part.Inventory.MaskEffectivePermissions(); 270 perms &= part.Inventory.MaskEffectivePermissions();
263 } 271 }
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 15795e5..d08237e 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -38,8 +38,10 @@ using OpenMetaverse;
38using OpenMetaverse.Packets; 38using OpenMetaverse.Packets;
39using OpenSim.Framework; 39using OpenSim.Framework;
40using OpenSim.Region.Framework.Interfaces; 40using OpenSim.Region.Framework.Interfaces;
41using OpenSim.Region.Physics.Manager; 41using OpenSim.Region.PhysicsModules.SharedBase;
42using OpenSim.Region.Framework.Scenes.Serialization; 42using OpenSim.Region.Framework.Scenes.Serialization;
43using PermissionMask = OpenSim.Framework.PermissionMask;
44using OpenSim.Services.Interfaces;
43 45
44namespace OpenSim.Region.Framework.Scenes 46namespace OpenSim.Region.Framework.Scenes
45{ 47{
@@ -74,6 +76,7 @@ namespace OpenSim.Region.Framework.Scenes
74 touch = 8, 76 touch = 8,
75 touch_end = 536870912, 77 touch_end = 536870912,
76 touch_start = 2097152, 78 touch_start = 2097152,
79 transaction_result = 33554432,
77 object_rez = 4194304 80 object_rez = 4194304
78 } 81 }
79 82
@@ -108,6 +111,9 @@ namespace OpenSim.Region.Framework.Scenes
108 STATUS_ROTATE_Z = 0x008, 111 STATUS_ROTATE_Z = 0x008,
109 } 112 }
110 113
114 // This flag has the same purpose as InventoryItemFlags.ObjectSlamPerm
115 public static readonly uint SLAM = 16;
116
111 // private PrimCountTaintedDelegate handlerPrimCountTainted = null; 117 // private PrimCountTaintedDelegate handlerPrimCountTainted = null;
112 118
113 /// <summary> 119 /// <summary>
@@ -145,12 +151,27 @@ namespace OpenSim.Region.Framework.Scenes
145 151
146 get { return m_hasGroupChanged; } 152 get { return m_hasGroupChanged; }
147 } 153 }
154
155 private bool m_groupContainsForeignPrims = false;
148 156
149 /// <summary> 157 /// <summary>
150 /// Has the group changed due to an unlink operation? We record this in order to optimize deletion, since 158 /// Whether the group contains prims that came from a different group. This happens when
151 /// an unlinked group currently has to be persisted to the database before we can perform an unlink operation. 159 /// linking or delinking groups. The implication is that until the group is persisted,
160 /// the prims in the database still use the old SceneGroupID. That's a problem if the group
161 /// is deleted, because we delete groups by searching for prims by their SceneGroupID.
152 /// </summary> 162 /// </summary>
153 public bool HasGroupChangedDueToDelink { get; private set; } 163 public bool GroupContainsForeignPrims
164 {
165 private set
166 {
167 m_groupContainsForeignPrims = value;
168 if (m_groupContainsForeignPrims)
169 HasGroupChanged = true;
170 }
171
172 get { return m_groupContainsForeignPrims; }
173 }
174
154 175
155 private bool isTimeToPersist() 176 private bool isTimeToPersist()
156 { 177 {
@@ -267,7 +288,10 @@ namespace OpenSim.Region.Framework.Scenes
267 private Vector3 lastPhysGroupPos; 288 private Vector3 lastPhysGroupPos;
268 private Quaternion lastPhysGroupRot; 289 private Quaternion lastPhysGroupRot;
269 290
270 private bool m_isBackedUp; 291 /// <summary>
292 /// Is this entity set to be saved in persistent storage?
293 /// </summary>
294 public bool Backup { get; private set; }
271 295
272 protected MapAndArray<UUID, SceneObjectPart> m_parts = new MapAndArray<UUID, SceneObjectPart>(); 296 protected MapAndArray<UUID, SceneObjectPart> m_parts = new MapAndArray<UUID, SceneObjectPart>();
273 297
@@ -329,7 +353,7 @@ namespace OpenSim.Region.Framework.Scenes
329 { 353 {
330 get 354 get
331 { 355 {
332 Vector3 minScale = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionSize); 356 Vector3 minScale = new Vector3(Constants.MaximumRegionSize, Constants.MaximumRegionSize, Constants.MaximumRegionSize);
333 Vector3 maxScale = Vector3.Zero; 357 Vector3 maxScale = Vector3.Zero;
334 Vector3 finalScale = new Vector3(0.5f, 0.5f, 0.5f); 358 Vector3 finalScale = new Vector3(0.5f, 0.5f, 0.5f);
335 359
@@ -424,9 +448,16 @@ namespace OpenSim.Region.Framework.Scenes
424 /// <returns></returns> 448 /// <returns></returns>
425 public bool IsAttachmentCheckFull() 449 public bool IsAttachmentCheckFull()
426 { 450 {
427 return (IsAttachment || (m_rootPart.Shape.PCode == 9 && m_rootPart.Shape.State != 0)); 451 return (IsAttachment ||
452 (m_rootPart.Shape.PCode == (byte)PCodeEnum.Primitive && m_rootPart.Shape.State != 0));
428 } 453 }
429 454
455 private struct avtocrossInfo
456 {
457 public ScenePresence av;
458 public uint ParentID;
459 }
460
430 /// <summary> 461 /// <summary>
431 /// The absolute position of this scene object in the scene 462 /// The absolute position of this scene object in the scene
432 /// </summary> 463 /// </summary>
@@ -440,24 +471,140 @@ namespace OpenSim.Region.Framework.Scenes
440 if (Scene != null) 471 if (Scene != null)
441 { 472 {
442 if ( 473 if (
443 // (Scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E) 474 !Scene.PositionIsInCurrentRegion(val)
444 // || Scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W) 475 && !IsAttachmentCheckFull()
445 // || Scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N) 476 && (!Scene.LoadingPrims)
446 // || Scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S)) 477 )
447 // Experimental change for better border crossings.
448 // The commented out original lines above would, it seems, trigger
449 // a border crossing a little early or late depending on which
450 // direction the object was moving.
451 (Scene.TestBorderCross(val, Cardinals.E)
452 || Scene.TestBorderCross(val, Cardinals.W)
453 || Scene.TestBorderCross(val, Cardinals.N)
454 || Scene.TestBorderCross(val, Cardinals.S))
455 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims))
456 { 478 {
457 m_scene.CrossPrimGroupIntoNewRegion(val, this, true); 479 IEntityTransferModule entityTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>();
480 EntityTransferContext ctx = new EntityTransferContext();
481 Vector3 newpos = Vector3.Zero;
482 string failureReason = String.Empty;
483 OpenSim.Services.Interfaces.GridRegion destination = null;
484
485 if (m_rootPart.KeyframeMotion != null)
486 m_rootPart.KeyframeMotion.StartCrossingCheck();
487
488 bool canCross = true;
489 foreach (ScenePresence av in GetSittingAvatars())
490 {
491 // We need to cross these agents. First, let's find
492 // out if any of them can't cross for some reason.
493 // We have to deny the crossing entirely if any
494 // of them are banned. Alternatively, we could
495 // unsit banned agents....
496
497
498 // We set the avatar position as being the object
499 // position to get the region to send to
500 if ((destination = entityTransfer.GetDestination(m_scene, av.UUID, val, ctx, out newpos, out failureReason)) == null)
501 {
502 canCross = false;
503 break;
504 }
505
506 m_log.DebugFormat("[SCENE OBJECT]: Avatar {0} needs to be crossed to {1}", av.Name, destination.RegionName);
507 }
508
509 if (canCross)
510 {
511 // We unparent the SP quietly so that it won't
512 // be made to stand up
513
514 List<avtocrossInfo> avsToCross = new List<avtocrossInfo>();
515
516 foreach (ScenePresence av in GetSittingAvatars())
517 {
518 avtocrossInfo avinfo = new avtocrossInfo();
519 SceneObjectPart parentPart = m_scene.GetSceneObjectPart(av.ParentID);
520 if (parentPart != null)
521 av.ParentUUID = parentPart.UUID;
522
523 avinfo.av = av;
524 avinfo.ParentID = av.ParentID;
525 avsToCross.Add(avinfo);
526
527 av.PrevSitOffset = av.OffsetPosition;
528 av.ParentID = 0;
529 }
530
531 m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
532
533 // Normalize
534 if (val.X >= m_scene.RegionInfo.RegionSizeX)
535 val.X -= m_scene.RegionInfo.RegionSizeX;
536 if (val.Y >= m_scene.RegionInfo.RegionSizeY)
537 val.Y -= m_scene.RegionInfo.RegionSizeY;
538 if (val.X < 0)
539 val.X += m_scene.RegionInfo.RegionSizeX;
540 if (val.Y < 0)
541 val.Y += m_scene.RegionInfo.RegionSizeY;
542
543 // If it's deleted, crossing was successful
544 if (IsDeleted)
545 {
546 foreach (avtocrossInfo avinfo in avsToCross)
547 {
548 ScenePresence av = avinfo.av;
549 if (!av.IsInTransit) // just in case...
550 {
551 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar {0} to {1}", av.Name, val);
552
553 av.IsInTransit = true;
554
555 // A temporary measure to allow regression tests to work.
556 // Quite possibly, all BeginInvoke() calls should be replaced by Util.FireAndForget
557 // or similar since BeginInvoke() always uses the system threadpool to launch
558 // threads rather than any replace threadpool that we might be using.
559 if (Util.FireAndForgetMethod == FireAndForgetMethod.RegressionTest)
560 {
561 entityTransfer.CrossAgentToNewRegionAsync(av, val, destination, av.Flying, ctx);
562 CrossAgentToNewRegionCompleted(av);
563 }
564 else
565 {
566 CrossAgentToNewRegionDelegate d = entityTransfer.CrossAgentToNewRegionAsync;
567 d.BeginInvoke(
568 av, val, destination, av.Flying, ctx,
569 ar => CrossAgentToNewRegionCompleted(d.EndInvoke(ar)), null);
570 }
571 }
572 else
573 {
574 m_log.DebugFormat("[SCENE OBJECT]: Not crossing avatar {0} to {1} because it's already in transit", av.Name, val);
575 }
576 }
577
578 return;
579 }
580 else // cross failed, put avas back ??
581 {
582 foreach (avtocrossInfo avinfo in avsToCross)
583 {
584 ScenePresence av = avinfo.av;
585 av.ParentUUID = UUID.Zero;
586 av.ParentID = avinfo.ParentID;
587 }
588 }
589 }
590 else
591 {
592 if (m_rootPart.KeyframeMotion != null)
593 m_rootPart.KeyframeMotion.CrossingFailure();
594
595 if (RootPart.PhysActor != null)
596 {
597 RootPart.PhysActor.CrossingFailure();
598 }
599 }
600
601 Vector3 oldp = AbsolutePosition;
602 val.X = Util.Clamp<float>(oldp.X, 0.5f, (float)m_scene.RegionInfo.RegionSizeX - 0.5f);
603 val.Y = Util.Clamp<float>(oldp.Y, 0.5f, (float)m_scene.RegionInfo.RegionSizeY - 0.5f);
604 val.Z = Util.Clamp<float>(oldp.Z, 0.5f, Constants.RegionHeight);
458 } 605 }
459 } 606 }
460 607
461 if (RootPart.GetStatusSandbox()) 608 if (RootPart.GetStatusSandbox())
462 { 609 {
463 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) 610 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10)
@@ -491,6 +638,36 @@ namespace OpenSim.Region.Framework.Scenes
491 } 638 }
492 } 639 }
493 640
641 public override Vector3 Velocity
642 {
643 get { return RootPart.Velocity; }
644 set { RootPart.Velocity = value; }
645 }
646
647 private void CrossAgentToNewRegionCompleted(ScenePresence agent)
648 {
649 //// If the cross was successful, this agent is a child agent
650 if (agent.IsChildAgent)
651 {
652 if (agent.ParentUUID != UUID.Zero)
653 {
654 agent.ParentPart = null;
655// agent.ParentPosition = Vector3.Zero;
656// agent.ParentUUID = UUID.Zero;
657 }
658 }
659
660 agent.ParentUUID = UUID.Zero;
661// agent.Reset();
662// else // Not successful
663// agent.RestoreInCurrentScene();
664
665 // In any case
666 agent.IsInTransit = false;
667
668 m_log.DebugFormat("[SCENE OBJECT]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname);
669 }
670
494 public override uint LocalId 671 public override uint LocalId
495 { 672 {
496 get { return m_rootPart.LocalId; } 673 get { return m_rootPart.LocalId; }
@@ -548,7 +725,11 @@ namespace OpenSim.Region.Framework.Scenes
548 set { m_rootPart.Text = value; } 725 set { m_rootPart.Text = value; }
549 } 726 }
550 727
551 protected virtual bool InSceneBackup 728 /// <summary>
729 /// If set to true then the scene object can be backed up in principle, though this will only actually occur
730 /// if Backup is set. If false then the scene object will never be backed up, Backup will always be false.
731 /// </summary>
732 protected virtual bool CanBeBackedUp
552 { 733 {
553 get { return true; } 734 get { return true; }
554 } 735 }
@@ -577,6 +758,8 @@ namespace OpenSim.Region.Framework.Scenes
577 childPa.Selected = value; 758 childPa.Selected = value;
578 } 759 }
579 } 760 }
761 if (RootPart.KeyframeMotion != null)
762 RootPart.KeyframeMotion.Selected = value;
580 } 763 }
581 } 764 }
582 765
@@ -648,6 +831,12 @@ namespace OpenSim.Region.Framework.Scenes
648 public UUID FromFolderID { get; set; } 831 public UUID FromFolderID { get; set; }
649 832
650 /// <summary> 833 /// <summary>
834 /// If true then grabs are blocked no matter what the individual part BlockGrab setting.
835 /// </summary>
836 /// <value><c>true</c> if block grab override; otherwise, <c>false</c>.</value>
837 public bool BlockGrabOverride { get; set; }
838
839 /// <summary>
651 /// IDs of all avatars sat on this scene object. 840 /// IDs of all avatars sat on this scene object.
652 /// </summary> 841 /// </summary>
653 /// <remarks> 842 /// <remarks>
@@ -657,7 +846,7 @@ namespace OpenSim.Region.Framework.Scenes
657 /// No avatar should appear more than once in this list. 846 /// No avatar should appear more than once in this list.
658 /// Do not manipulate this list directly - use the Add/Remove sitting avatar methods on SceneObjectPart. 847 /// Do not manipulate this list directly - use the Add/Remove sitting avatar methods on SceneObjectPart.
659 /// </remarks> 848 /// </remarks>
660 protected internal List<UUID> m_sittingAvatars = new List<UUID>(); 849 protected internal List<ScenePresence> m_sittingAvatars = new List<ScenePresence>();
661 850
662 #endregion 851 #endregion
663 852
@@ -722,20 +911,60 @@ namespace OpenSim.Region.Framework.Scenes
722 } 911 }
723 } 912 }
724 913
914 public void LoadScriptState(XmlReader reader)
915 {
916// m_log.DebugFormat("[SCENE OBJECT GROUP]: Looking for script state for {0}", Name);
917
918 while (true)
919 {
920 if (reader.Name == "SavedScriptState" && reader.NodeType == XmlNodeType.Element)
921 {
922// m_log.DebugFormat("[SCENE OBJECT GROUP]: Loading script state for {0}", Name);
923
924 if (m_savedScriptState == null)
925 m_savedScriptState = new Dictionary<UUID, string>();
926
927 string uuid = reader.GetAttribute("UUID");
928
929 // Even if there is no UUID attribute for some strange reason, we must always read the inner XML
930 // so we don't continually keep checking the same SavedScriptedState element.
931 string innerXml = reader.ReadInnerXml();
932
933 if (uuid != null)
934 {
935// m_log.DebugFormat("[SCENE OBJECT GROUP]: Found state for item ID {0} in object {1}", uuid, Name);
936
937 UUID itemid = new UUID(uuid);
938 if (itemid != UUID.Zero)
939 m_savedScriptState[itemid] = innerXml;
940 }
941 else
942 {
943 m_log.WarnFormat("[SCENE OBJECT GROUP]: SavedScriptState element had no UUID in object {0}", Name);
944 }
945 }
946 else
947 {
948 if (!reader.Read())
949 break;
950 }
951 }
952 }
953
725 /// <summary> 954 /// <summary>
726 /// Hooks this object up to the backup event so that it is persisted to the database when the update thread executes. 955 /// Hooks this object up to the backup event so that it is persisted to the database when the update thread executes.
727 /// </summary> 956 /// </summary>
728 public virtual void AttachToBackup() 957 public virtual void AttachToBackup()
729 { 958 {
730 if (InSceneBackup) 959 if (CanBeBackedUp)
731 { 960 {
732 //m_log.DebugFormat( 961// m_log.DebugFormat(
733 // "[SCENE OBJECT GROUP]: Attaching object {0} {1} to scene presistence sweep", Name, UUID); 962// "[SCENE OBJECT GROUP]: Attaching object {0} {1} to scene presistence sweep", Name, UUID);
734 963
735 if (!m_isBackedUp) 964 if (!Backup)
736 m_scene.EventManager.OnBackup += ProcessBackup; 965 m_scene.EventManager.OnBackup += ProcessBackup;
737 966
738 m_isBackedUp = true; 967 Backup = true;
739 } 968 }
740 } 969 }
741 970
@@ -757,6 +986,11 @@ namespace OpenSim.Region.Framework.Scenes
757 for (int i = 0; i < parts.Length; i++) 986 for (int i = 0; i < parts.Length; i++)
758 { 987 {
759 SceneObjectPart part = parts[i]; 988 SceneObjectPart part = parts[i];
989 if (part.KeyframeMotion != null)
990 {
991 part.KeyframeMotion.UpdateSceneObject(this);
992 }
993
760 if (Object.ReferenceEquals(part, m_rootPart)) 994 if (Object.ReferenceEquals(part, m_rootPart))
761 continue; 995 continue;
762 996
@@ -831,9 +1065,9 @@ namespace OpenSim.Region.Framework.Scenes
831 maxX = -256f; 1065 maxX = -256f;
832 maxY = -256f; 1066 maxY = -256f;
833 maxZ = -256f; 1067 maxZ = -256f;
834 minX = 256f; 1068 minX = 10000f;
835 minY = 256f; 1069 minY = 10000f;
836 minZ = 8192f; 1070 minZ = 10000f;
837 1071
838 SceneObjectPart[] parts = m_parts.GetArray(); 1072 SceneObjectPart[] parts = m_parts.GetArray();
839 for (int i = 0; i < parts.Length; i++) 1073 for (int i = 0; i < parts.Length; i++)
@@ -1085,6 +1319,7 @@ namespace OpenSim.Region.Framework.Scenes
1085 } 1319 }
1086 } 1320 }
1087 1321
1322
1088 /// <summary> 1323 /// <summary>
1089 /// 1324 ///
1090 /// </summary> 1325 /// </summary>
@@ -1220,11 +1455,11 @@ namespace OpenSim.Region.Framework.Scenes
1220 /// <summary> 1455 /// <summary>
1221 /// Delete this group from its scene. 1456 /// Delete this group from its scene.
1222 /// </summary> 1457 /// </summary>
1223 /// 1458 /// <remarks>
1224 /// This only handles the in-world consequences of deletion (e.g. any avatars sitting on it are forcibly stood 1459 /// This only handles the in-world consequences of deletion (e.g. any avatars sitting on it are forcibly stood
1225 /// up and all avatars receive notification of its removal. Removal of the scene object from database backup 1460 /// up and all avatars receive notification of its removal. Removal of the scene object from database backup
1226 /// must be handled by the caller. 1461 /// must be handled by the caller.
1227 /// 1462 /// </remarks>
1228 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1463 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1229 public void DeleteGroupFromScene(bool silent) 1464 public void DeleteGroupFromScene(bool silent)
1230 { 1465 {
@@ -1233,10 +1468,10 @@ namespace OpenSim.Region.Framework.Scenes
1233 { 1468 {
1234 SceneObjectPart part = parts[i]; 1469 SceneObjectPart part = parts[i];
1235 1470
1236 Scene.ForEachRootScenePresence(delegate(ScenePresence avatar) 1471 Scene.ForEachScenePresence(sp =>
1237 { 1472 {
1238 if (avatar.ParentID == LocalId) 1473 if (!sp.IsChildAgent && sp.ParentID == part.LocalId)
1239 avatar.StandUp(); 1474 sp.StandUp();
1240 1475
1241 if (!silent) 1476 if (!silent)
1242 { 1477 {
@@ -1244,9 +1479,9 @@ namespace OpenSim.Region.Framework.Scenes
1244 if (part == m_rootPart) 1479 if (part == m_rootPart)
1245 { 1480 {
1246 if (!IsAttachment 1481 if (!IsAttachment
1247 || AttachedAvatar == avatar.ControllingClient.AgentId 1482 || AttachedAvatar == sp.UUID
1248 || !HasPrivateAttachmentPoint) 1483 || !HasPrivateAttachmentPoint)
1249 avatar.ControllingClient.SendKillObject(m_regionHandle, new List<uint> { part.LocalId }); 1484 sp.ControllingClient.SendKillObject(new List<uint> { part.LocalId });
1250 } 1485 }
1251 } 1486 }
1252 }); 1487 });
@@ -1359,7 +1594,7 @@ namespace OpenSim.Region.Framework.Scenes
1359 /// <param name="datastore"></param> 1594 /// <param name="datastore"></param>
1360 public virtual void ProcessBackup(ISimulationDataService datastore, bool forcedBackup) 1595 public virtual void ProcessBackup(ISimulationDataService datastore, bool forcedBackup)
1361 { 1596 {
1362 if (!m_isBackedUp) 1597 if (!Backup)
1363 { 1598 {
1364// m_log.DebugFormat( 1599// m_log.DebugFormat(
1365// "[WATER WARS]: Ignoring backup of {0} {1} since object is not marked to be backed up", Name, UUID); 1600// "[WATER WARS]: Ignoring backup of {0} {1} since object is not marked to be backed up", Name, UUID);
@@ -1421,7 +1656,7 @@ namespace OpenSim.Region.Framework.Scenes
1421 backup_group.RootPart.AngularVelocity = RootPart.AngularVelocity; 1656 backup_group.RootPart.AngularVelocity = RootPart.AngularVelocity;
1422 backup_group.RootPart.ParticleSystem = RootPart.ParticleSystem; 1657 backup_group.RootPart.ParticleSystem = RootPart.ParticleSystem;
1423 HasGroupChanged = false; 1658 HasGroupChanged = false;
1424 HasGroupChangedDueToDelink = false; 1659 GroupContainsForeignPrims = false;
1425 1660
1426 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this); 1661 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this);
1427 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID); 1662 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID);
@@ -1480,31 +1715,14 @@ namespace OpenSim.Region.Framework.Scenes
1480 /// <returns></returns> 1715 /// <returns></returns>
1481 public SceneObjectGroup Copy(bool userExposed) 1716 public SceneObjectGroup Copy(bool userExposed)
1482 { 1717 {
1718 // FIXME: This is dangerous since it's easy to forget to reset some references when necessary and end up
1719 // with bugs that only occur in some circumstances (e.g. crossing between regions on the same simulator
1720 // but not between regions on different simulators). Really, all copying should be done explicitly.
1483 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 1721 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone();
1484 dupe.m_isBackedUp = false;
1485 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
1486
1487 // Warning, The following code related to previousAttachmentStatus is needed so that clones of
1488 // attachments do not bordercross while they're being duplicated. This is hacktastic!
1489 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
1490 // unless IsAttachment is true!, so to prevent border crossing, we save it's attachment state
1491 // (which should be false anyway) set it as an Attachment and then set it's Absolute Position,
1492 // then restore it's attachment state
1493
1494 // This is only necessary when userExposed is false!
1495
1496 bool previousAttachmentStatus = dupe.IsAttachment;
1497
1498 if (!userExposed)
1499 dupe.IsAttachment = true;
1500
1501 dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z);
1502
1503 if (!userExposed)
1504 {
1505 dupe.IsAttachment = previousAttachmentStatus;
1506 }
1507 1722
1723 dupe.Backup = false;
1724 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
1725 dupe.m_sittingAvatars = new List<ScenePresence>();
1508 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed); 1726 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed);
1509 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum; 1727 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum;
1510 1728
@@ -1550,6 +1768,8 @@ namespace OpenSim.Region.Framework.Scenes
1550 1768
1551 newPart.DoPhysicsPropertyUpdate(originalPartPa.IsPhysical, true); 1769 newPart.DoPhysicsPropertyUpdate(originalPartPa.IsPhysical, true);
1552 } 1770 }
1771 if (part.KeyframeMotion != null)
1772 newPart.KeyframeMotion = part.KeyframeMotion.Copy(dupe);
1553 } 1773 }
1554 1774
1555 if (userExposed) 1775 if (userExposed)
@@ -1577,6 +1797,12 @@ namespace OpenSim.Region.Framework.Scenes
1577 1797
1578 public void ScriptSetPhysicsStatus(bool usePhysics) 1798 public void ScriptSetPhysicsStatus(bool usePhysics)
1579 { 1799 {
1800 if (usePhysics)
1801 {
1802 if (RootPart.KeyframeMotion != null)
1803 RootPart.KeyframeMotion.Stop();
1804 RootPart.KeyframeMotion = null;
1805 }
1580 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect); 1806 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
1581 } 1807 }
1582 1808
@@ -1674,15 +1900,14 @@ namespace OpenSim.Region.Framework.Scenes
1674 return Vector3.Zero; 1900 return Vector3.Zero;
1675 } 1901 }
1676 1902
1677 public void moveToTarget(Vector3 target, float tau) 1903 public void MoveToTarget(Vector3 target, float tau)
1678 { 1904 {
1679 if (IsAttachment) 1905 if (IsAttachment)
1680 { 1906 {
1681 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar); 1907 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1908
1682 if (avatar != null) 1909 if (avatar != null)
1683 {
1684 avatar.MoveToTarget(target, false, false); 1910 avatar.MoveToTarget(target, false, false);
1685 }
1686 } 1911 }
1687 else 1912 else
1688 { 1913 {
@@ -1697,12 +1922,26 @@ namespace OpenSim.Region.Framework.Scenes
1697 } 1922 }
1698 } 1923 }
1699 1924
1700 public void stopMoveToTarget() 1925 public void StopMoveToTarget()
1701 { 1926 {
1702 PhysicsActor pa = RootPart.PhysActor; 1927 if (IsAttachment)
1928 {
1929 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1703 1930
1704 if (pa != null) 1931 if (avatar != null)
1705 pa.PIDActive = false; 1932 avatar.ResetMoveToTarget();
1933 }
1934 else
1935 {
1936 PhysicsActor pa = RootPart.PhysActor;
1937
1938 if (pa != null && pa.PIDActive)
1939 {
1940 pa.PIDActive = false;
1941
1942 ScheduleGroupForTerseUpdate();
1943 }
1944 }
1706 } 1945 }
1707 1946
1708 /// <summary> 1947 /// <summary>
@@ -2175,7 +2414,9 @@ namespace OpenSim.Region.Framework.Scenes
2175// objectGroup.m_rootPart = null; 2414// objectGroup.m_rootPart = null;
2176 2415
2177 // If linking prims with different permissions, fix them 2416 // If linking prims with different permissions, fix them
2178 AdjustChildPrimPermissions(); 2417 AdjustChildPrimPermissions(false);
2418
2419 GroupContainsForeignPrims = true;
2179 2420
2180 AttachToBackup(); 2421 AttachToBackup();
2181 2422
@@ -2320,9 +2561,16 @@ namespace OpenSim.Region.Framework.Scenes
2320 2561
2321 linkPart.Rezzed = RootPart.Rezzed; 2562 linkPart.Rezzed = RootPart.Rezzed;
2322 2563
2323 // When we delete a group, we currently have to force persist to the database if the object id has changed 2564 // We must persist the delinked group to the database immediately, for safety. The problem
2324 // (since delete works by deleting all rows which have a given object id) 2565 // is that although in memory the new group has a new SceneGroupID, in the database it
2325 objectGroup.HasGroupChangedDueToDelink = true; 2566 // still has the parent group's SceneGroupID (until the next backup). This means that if the
2567 // parent group is deleted then the delinked group will also be deleted from the database.
2568 // This problem will disappear if the region remains alive long enough for another backup,
2569 // since at that time the delinked group's new SceneGroupID will be written to the database.
2570 // But if the region crashes before that then the prims will be permanently gone, and this must
2571 // not happen. (We can't use a just-in-time trick like GroupContainsForeignPrims in this case
2572 // because the delinked group doesn't know when the source group is deleted.)
2573 m_scene.ForceSceneObjectBackup(objectGroup);
2326 2574
2327 return objectGroup; 2575 return objectGroup;
2328 } 2576 }
@@ -2333,10 +2581,10 @@ namespace OpenSim.Region.Framework.Scenes
2333 /// <param name="objectGroup"></param> 2581 /// <param name="objectGroup"></param>
2334 public virtual void DetachFromBackup() 2582 public virtual void DetachFromBackup()
2335 { 2583 {
2336 if (m_isBackedUp && Scene != null) 2584 if (Backup && Scene != null)
2337 m_scene.EventManager.OnBackup -= ProcessBackup; 2585 m_scene.EventManager.OnBackup -= ProcessBackup;
2338 2586
2339 m_isBackedUp = false; 2587 Backup = false;
2340 } 2588 }
2341 2589
2342 // This links an SOP from a previous linkset into my linkset. 2590 // This links an SOP from a previous linkset into my linkset.
@@ -2396,20 +2644,26 @@ namespace OpenSim.Region.Framework.Scenes
2396 /// If object is physical, apply force to move it around 2644 /// If object is physical, apply force to move it around
2397 /// If object is not physical, just put it at the resulting location 2645 /// If object is not physical, just put it at the resulting location
2398 /// </summary> 2646 /// </summary>
2647 /// <param name="partID">Part ID to check for grab</param>
2399 /// <param name="offset">Always seems to be 0,0,0, so ignoring</param> 2648 /// <param name="offset">Always seems to be 0,0,0, so ignoring</param>
2400 /// <param name="pos">New position. We do the math here to turn it into a force</param> 2649 /// <param name="pos">New position. We do the math here to turn it into a force</param>
2401 /// <param name="remoteClient"></param> 2650 /// <param name="remoteClient"></param>
2402 public void GrabMovement(Vector3 offset, Vector3 pos, IClientAPI remoteClient) 2651 public void GrabMovement(UUID partID, Vector3 offset, Vector3 pos, IClientAPI remoteClient)
2403 { 2652 {
2404 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 2653 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2405 { 2654 {
2655 SceneObjectPart part = GetPart(partID);
2656
2657 if (part == null)
2658 return;
2659
2406 PhysicsActor pa = m_rootPart.PhysActor; 2660 PhysicsActor pa = m_rootPart.PhysActor;
2407 2661
2408 if (pa != null) 2662 if (pa != null)
2409 { 2663 {
2410 if (pa.IsPhysical) 2664 if (pa.IsPhysical)
2411 { 2665 {
2412 if (!m_rootPart.BlockGrab) 2666 if (!BlockGrabOverride && !part.BlockGrab)
2413 { 2667 {
2414 Vector3 llmoveforce = pos - AbsolutePosition; 2668 Vector3 llmoveforce = pos - AbsolutePosition;
2415 Vector3 grabforce = llmoveforce; 2669 Vector3 grabforce = llmoveforce;
@@ -2420,20 +2674,27 @@ namespace OpenSim.Region.Framework.Scenes
2420 } 2674 }
2421 else 2675 else
2422 { 2676 {
2423 //NonPhysicalGrabMovement(pos); 2677 NonPhysicalGrabMovement(pos);
2424 } 2678 }
2425 } 2679 }
2426 else 2680 else
2427 { 2681 {
2428 //NonPhysicalGrabMovement(pos); 2682 NonPhysicalGrabMovement(pos);
2429 } 2683 }
2430 } 2684 }
2431 } 2685 }
2432 2686
2687 /// <summary>
2688 /// Apply possition for grabbing non-physical linksets (Ctrl+Drag)
2689 /// This MUST be blocked for linksets that contain touch scripts because the viewer triggers grab on the touch
2690 /// event (Viewer Bug?) This would allow anyone to drag a linkset with a touch script. SL behaviour is also to
2691 /// block grab on prims with touch events.
2692 /// </summary>
2693 /// <param name="pos">New Position</param>
2433 public void NonPhysicalGrabMovement(Vector3 pos) 2694 public void NonPhysicalGrabMovement(Vector3 pos)
2434 { 2695 {
2435 AbsolutePosition = pos; 2696 if(!IsAttachment && ScriptCount() == 0)
2436 m_rootPart.SendTerseUpdateToAllClients(); 2697 UpdateGroupPosition(pos);
2437 } 2698 }
2438 2699
2439 /// <summary> 2700 /// <summary>
@@ -2529,17 +2790,28 @@ namespace OpenSim.Region.Framework.Scenes
2529 } 2790 }
2530 else 2791 else
2531 { 2792 {
2532 //NonPhysicalSpinMovement(pos); 2793 NonPhysicalSpinMovement(newOrientation);
2533 } 2794 }
2534 } 2795 }
2535 else 2796 else
2536 { 2797 {
2537 //NonPhysicalSpinMovement(pos); 2798 NonPhysicalSpinMovement(newOrientation);
2538 } 2799 }
2539 } 2800 }
2540 } 2801 }
2541 2802
2542 /// <summary> 2803 /// <summary>
2804 /// Apply rotation for spinning non-physical linksets (Ctrl+Shift+Drag)
2805 /// As with dragging, scripted objects must be blocked from spinning
2806 /// </summary>
2807 /// <param name="newOrientation">New Rotation</param>
2808 private void NonPhysicalSpinMovement(Quaternion newOrientation)
2809 {
2810 if(!IsAttachment && ScriptCount() == 0)
2811 UpdateGroupRotationR(newOrientation);
2812 }
2813
2814 /// <summary>
2543 /// Set the name of a prim 2815 /// Set the name of a prim
2544 /// </summary> 2816 /// </summary>
2545 /// <param name="name"></param> 2817 /// <param name="name"></param>
@@ -2612,12 +2884,22 @@ namespace OpenSim.Region.Framework.Scenes
2612 { 2884 {
2613 SceneObjectPart selectionPart = GetPart(localID); 2885 SceneObjectPart selectionPart = GetPart(localID);
2614 2886
2615 if (SetTemporary && Scene != null) 2887 if (Scene != null)
2616 { 2888 {
2617 DetachFromBackup(); 2889 if (SetTemporary)
2618 // Remove from database and parcel prim count 2890 {
2619 // 2891 DetachFromBackup();
2620 m_scene.DeleteFromStorage(UUID); 2892 // Remove from database and parcel prim count
2893 //
2894 m_scene.DeleteFromStorage(UUID);
2895 }
2896 else if (!Backup)
2897 {
2898 // Previously been temporary now switching back so make it
2899 // available for persisting again
2900 AttachToBackup();
2901 }
2902
2621 m_scene.EventManager.TriggerParcelPrimCountTainted(); 2903 m_scene.EventManager.TriggerParcelPrimCountTainted();
2622 } 2904 }
2623 2905
@@ -2668,13 +2950,29 @@ namespace OpenSim.Region.Framework.Scenes
2668 } 2950 }
2669 } 2951 }
2670 2952
2671 public void AdjustChildPrimPermissions() 2953 public void AdjustChildPrimPermissions(bool forceTaskInventoryPermissive)
2672 { 2954 {
2955 uint newOwnerMask = (uint)(PermissionMask.All | PermissionMask.Export) & 0xfffffff8; // Mask folded bits
2956 uint foldedPerms = RootPart.OwnerMask & 3;
2957
2673 ForEachPart(part => 2958 ForEachPart(part =>
2674 { 2959 {
2960 newOwnerMask &= part.BaseMask;
2675 if (part != RootPart) 2961 if (part != RootPart)
2676 part.ClonePermissions(RootPart); 2962 part.ClonePermissions(RootPart);
2963 if (forceTaskInventoryPermissive)
2964 part.Inventory.ApplyGodPermissions(part.BaseMask);
2677 }); 2965 });
2966
2967 uint lockMask = ~(uint)(PermissionMask.Move | PermissionMask.Modify);
2968 uint lockBit = RootPart.OwnerMask & (uint)(PermissionMask.Move | PermissionMask.Modify);
2969 RootPart.OwnerMask = (RootPart.OwnerMask & lockBit) | ((newOwnerMask | foldedPerms) & lockMask);
2970
2971// m_log.DebugFormat(
2972// "[SCENE OBJECT GROUP]: RootPart.OwnerMask now {0} for {1} in {2}",
2973// (OpenMetaverse.PermissionMask)RootPart.OwnerMask, Name, Scene.Name);
2974
2975 RootPart.ScheduleFullUpdate();
2678 } 2976 }
2679 2977
2680 public void UpdatePermissions(UUID AgentID, byte field, uint localID, 2978 public void UpdatePermissions(UUID AgentID, byte field, uint localID,
@@ -2682,7 +2980,7 @@ namespace OpenSim.Region.Framework.Scenes
2682 { 2980 {
2683 RootPart.UpdatePermissions(AgentID, field, localID, mask, addRemTF); 2981 RootPart.UpdatePermissions(AgentID, field, localID, mask, addRemTF);
2684 2982
2685 AdjustChildPrimPermissions(); 2983 AdjustChildPrimPermissions(Scene.Permissions.IsGod(AgentID));
2686 2984
2687 HasGroupChanged = true; 2985 HasGroupChanged = true;
2688 2986
@@ -3000,8 +3298,8 @@ namespace OpenSim.Region.Framework.Scenes
3000 /// <summary> 3298 /// <summary>
3001 /// Update just the root prim position in a linkset 3299 /// Update just the root prim position in a linkset
3002 /// </summary> 3300 /// </summary>
3003 /// <param name="pos"></param> 3301 /// <param name="newPos"></param>
3004 public void UpdateRootPosition(Vector3 pos) 3302 public void UpdateRootPosition(Vector3 newPos)
3005 { 3303 {
3006// m_log.DebugFormat( 3304// m_log.DebugFormat(
3007// "[SCENE OBJECT GROUP]: Updating root position of {0} {1} to {2}", Name, LocalId, pos); 3305// "[SCENE OBJECT GROUP]: Updating root position of {0} {1} to {2}", Name, LocalId, pos);
@@ -3010,16 +3308,16 @@ namespace OpenSim.Region.Framework.Scenes
3010// for (int i = 0; i < parts.Length; i++) 3308// for (int i = 0; i < parts.Length; i++)
3011// parts[i].StoreUndoState(); 3309// parts[i].StoreUndoState();
3012 3310
3013 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3311 Vector3 oldPos;
3014 Vector3 oldPos = 3312
3015 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X, 3313 if (IsAttachment)
3016 AbsolutePosition.Y + m_rootPart.OffsetPosition.Y, 3314 oldPos = m_rootPart.AttachedPos + m_rootPart.OffsetPosition; // OffsetPosition should always be 0 in an attachments's root prim
3017 AbsolutePosition.Z + m_rootPart.OffsetPosition.Z); 3315 else
3316 oldPos = AbsolutePosition + m_rootPart.OffsetPosition;
3317
3018 Vector3 diff = oldPos - newPos; 3318 Vector3 diff = oldPos - newPos;
3019 Vector3 axDiff = new Vector3(diff.X, diff.Y, diff.Z);
3020 Quaternion partRotation = m_rootPart.RotationOffset; 3319 Quaternion partRotation = m_rootPart.RotationOffset;
3021 axDiff *= Quaternion.Inverse(partRotation); 3320 diff *= Quaternion.Inverse(partRotation);
3022 diff = axDiff;
3023 3321
3024 SceneObjectPart[] parts = m_parts.GetArray(); 3322 SceneObjectPart[] parts = m_parts.GetArray();
3025 for (int i = 0; i < parts.Length; i++) 3323 for (int i = 0; i < parts.Length; i++)
@@ -3030,6 +3328,9 @@ namespace OpenSim.Region.Framework.Scenes
3030 } 3328 }
3031 3329
3032 AbsolutePosition = newPos; 3330 AbsolutePosition = newPos;
3331
3332 if (IsAttachment)
3333 m_rootPart.AttachedPos = newPos;
3033 3334
3034 HasGroupChanged = true; 3335 HasGroupChanged = true;
3035 ScheduleGroupForTerseUpdate(); 3336 ScheduleGroupForTerseUpdate();
@@ -3583,10 +3884,10 @@ namespace OpenSim.Region.Framework.Scenes
3583 /// down after it move one place down the list. 3884 /// down after it move one place down the list.
3584 /// </remarks> 3885 /// </remarks>
3585 /// <returns>A list of the sitting avatars. Returns an empty list if there are no sitting avatars.</returns> 3886 /// <returns>A list of the sitting avatars. Returns an empty list if there are no sitting avatars.</returns>
3586 public List<UUID> GetSittingAvatars() 3887 public List<ScenePresence> GetSittingAvatars()
3587 { 3888 {
3588 lock (m_sittingAvatars) 3889 lock (m_sittingAvatars)
3589 return new List<UUID>(m_sittingAvatars); 3890 return new List<ScenePresence>(m_sittingAvatars);
3590 } 3891 }
3591 3892
3592 /// <summary> 3893 /// <summary>
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
index 44e8fdf..d1c5f72 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
@@ -37,11 +37,13 @@ using System.Xml.Serialization;
37using log4net; 37using log4net;
38using OpenMetaverse; 38using OpenMetaverse;
39using OpenMetaverse.Packets; 39using OpenMetaverse.Packets;
40using OpenMetaverse.StructuredData;
40using OpenSim.Framework; 41using OpenSim.Framework;
41using OpenSim.Region.Framework.Interfaces; 42using OpenSim.Region.Framework.Interfaces;
42using OpenSim.Region.Framework.Scenes.Scripting; 43using OpenSim.Region.Framework.Scenes.Scripting;
43using OpenSim.Region.Framework.Scenes.Serialization; 44using OpenSim.Region.Framework.Scenes.Serialization;
44using OpenSim.Region.Physics.Manager; 45using OpenSim.Region.PhysicsModules.SharedBase;
46using PermissionMask = OpenSim.Framework.PermissionMask;
45 47
46namespace OpenSim.Region.Framework.Scenes 48namespace OpenSim.Region.Framework.Scenes
47{ 49{
@@ -115,7 +117,7 @@ namespace OpenSim.Region.Framework.Scenes
115 117
116 #endregion Enumerations 118 #endregion Enumerations
117 119
118 public class SceneObjectPart : IScriptHost, ISceneEntity 120 public class SceneObjectPart : ISceneEntity
119 { 121 {
120 /// <value> 122 /// <value>
121 /// Denote all sides of the prim 123 /// Denote all sides of the prim
@@ -124,6 +126,32 @@ namespace OpenSim.Region.Framework.Scenes
124 126
125 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 127 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
126 128
129 /// <summary>
130 /// Dynamic attributes can be created and deleted as required.
131 /// </summary>
132 public DAMap DynAttrs { get; set; }
133
134 private DOMap m_dynObjs;
135
136 /// <summary>
137 /// Dynamic objects that can be created and deleted as required.
138 /// </summary>
139 public DOMap DynObjs
140 {
141 get
142 {
143 if (m_dynObjs == null)
144 m_dynObjs = new DOMap();
145
146 return m_dynObjs;
147 }
148
149 set
150 {
151 m_dynObjs = value;
152 }
153 }
154
127 /// <value> 155 /// <value>
128 /// Is this a root part? 156 /// Is this a root part?
129 /// </value> 157 /// </value>
@@ -158,7 +186,7 @@ namespace OpenSim.Region.Framework.Scenes
158 186
159 public bool RETURN_AT_EDGE; 187 public bool RETURN_AT_EDGE;
160 188
161 public bool BlockGrab; 189 public bool BlockGrab { get; set; }
162 190
163 public bool StatusSandbox; 191 public bool StatusSandbox;
164 192
@@ -191,6 +219,14 @@ namespace OpenSim.Region.Framework.Scenes
191 219
192 public double SoundRadius; 220 public double SoundRadius;
193 221
222 /// <summary>
223 /// Should sounds played from this prim be queued?
224 /// </summary>
225 /// <remarks>
226 /// This should only be changed by sound modules. It is up to sound modules as to how they interpret this setting.
227 /// </remarks>
228 public bool SoundQueueing { get; set; }
229
194 public uint TimeStampFull; 230 public uint TimeStampFull;
195 231
196 public uint TimeStampLastActivity; // Will be used for AutoReturn 232 public uint TimeStampLastActivity; // Will be used for AutoReturn
@@ -230,7 +266,7 @@ namespace OpenSim.Region.Framework.Scenes
230 266
231 public Quaternion SpinOldOrientation = Quaternion.Identity; 267 public Quaternion SpinOldOrientation = Quaternion.Identity;
232 268
233 protected int m_APIDIterations = 0; 269 protected bool m_APIDActive = false;
234 protected Quaternion m_APIDTarget = Quaternion.Identity; 270 protected Quaternion m_APIDTarget = Quaternion.Identity;
235 protected float m_APIDDamp = 0; 271 protected float m_APIDDamp = 0;
236 protected float m_APIDStrength = 0; 272 protected float m_APIDStrength = 0;
@@ -296,6 +332,12 @@ namespace OpenSim.Region.Framework.Scenes
296 protected Vector3 m_lastAcceleration; 332 protected Vector3 m_lastAcceleration;
297 protected Vector3 m_lastAngularVelocity; 333 protected Vector3 m_lastAngularVelocity;
298 protected int m_lastTerseSent; 334 protected int m_lastTerseSent;
335
336 protected byte m_physicsShapeType = (byte)PhysShapeType.prim;
337 protected float m_density = 1000.0f; // in kg/m^3
338 protected float m_gravitymod = 1.0f;
339 protected float m_friction = 0.6f; // wood
340 protected float m_bounce = 0.5f; // wood
299 341
300 /// <summary> 342 /// <summary>
301 /// Stores media texture data 343 /// Stores media texture data
@@ -312,6 +354,11 @@ namespace OpenSim.Region.Framework.Scenes
312 private UUID m_collisionSound; 354 private UUID m_collisionSound;
313 private float m_collisionSoundVolume; 355 private float m_collisionSoundVolume;
314 356
357 public KeyframeMotion KeyframeMotion
358 {
359 get; set;
360 }
361
315 #endregion Fields 362 #endregion Fields
316 363
317// ~SceneObjectPart() 364// ~SceneObjectPart()
@@ -335,6 +382,7 @@ namespace OpenSim.Region.Framework.Scenes
335 m_particleSystem = Utils.EmptyBytes; 382 m_particleSystem = Utils.EmptyBytes;
336 Rezzed = DateTime.UtcNow; 383 Rezzed = DateTime.UtcNow;
337 Description = String.Empty; 384 Description = String.Empty;
385 DynAttrs = new DAMap();
338 386
339 // Prims currently only contain a single folder (Contents). From looking at the Second Life protocol, 387 // Prims currently only contain a single folder (Contents). From looking at the Second Life protocol,
340 // this appears to have the same UUID (!) as the prim. If this isn't the case, one can't drag items from 388 // this appears to have the same UUID (!) as the prim. If this isn't the case, one can't drag items from
@@ -389,8 +437,8 @@ namespace OpenSim.Region.Framework.Scenes
389 private uint _category; 437 private uint _category;
390 private Int32 _creationDate; 438 private Int32 _creationDate;
391 private uint _parentID = 0; 439 private uint _parentID = 0;
392 private uint _baseMask = (uint)PermissionMask.All; 440 private uint _baseMask = (uint)(PermissionMask.All | PermissionMask.Export);
393 private uint _ownerMask = (uint)PermissionMask.All; 441 private uint _ownerMask = (uint)(PermissionMask.All | PermissionMask.Export);
394 private uint _groupMask = (uint)PermissionMask.None; 442 private uint _groupMask = (uint)PermissionMask.None;
395 private uint _everyoneMask = (uint)PermissionMask.None; 443 private uint _everyoneMask = (uint)PermissionMask.None;
396 private uint _nextOwnerMask = (uint)PermissionMask.All; 444 private uint _nextOwnerMask = (uint)PermissionMask.All;
@@ -425,7 +473,7 @@ namespace OpenSim.Region.Framework.Scenes
425 { 473 {
426 get 474 get
427 { 475 {
428 if (CreatorData != null && CreatorData != string.Empty) 476 if (!string.IsNullOrEmpty(CreatorData))
429 return CreatorID.ToString() + ';' + CreatorData; 477 return CreatorID.ToString() + ';' + CreatorData;
430 else 478 else
431 return CreatorID.ToString(); 479 return CreatorID.ToString();
@@ -455,7 +503,11 @@ namespace OpenSim.Region.Framework.Scenes
455 CreatorID = uuid; 503 CreatorID = uuid;
456 } 504 }
457 if (parts.Length >= 2) 505 if (parts.Length >= 2)
506 {
458 CreatorData = parts[1]; 507 CreatorData = parts[1];
508 if (!CreatorData.EndsWith("/"))
509 CreatorData += "/";
510 }
459 if (parts.Length >= 3) 511 if (parts.Length >= 3)
460 name = parts[2]; 512 name = parts[2];
461 513
@@ -590,6 +642,12 @@ namespace OpenSim.Region.Framework.Scenes
590 } 642 }
591 } 643 }
592 644
645 protected bool APIDActive
646 {
647 get { return m_APIDActive; }
648 set { m_APIDActive = value; }
649 }
650
593 protected Quaternion APIDTarget 651 protected Quaternion APIDTarget
594 { 652 {
595 get { return m_APIDTarget; } 653 get { return m_APIDTarget; }
@@ -729,23 +787,14 @@ namespace OpenSim.Region.Framework.Scenes
729 } 787 }
730 788
731 // Tell the physics engines that this prim changed. 789 // Tell the physics engines that this prim changed.
732 ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor); 790 if (ParentGroup != null && ParentGroup.Scene != null && ParentGroup.Scene.PhysicsScene != null)
791 ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor);
733 } 792 }
734 catch (Exception e) 793 catch (Exception e)
735 { 794 {
736 m_log.ErrorFormat("[SCENEOBJECTPART]: GROUP POSITION. {0}", e); 795 m_log.ErrorFormat("[SCENEOBJECTPART]: GROUP POSITION. {0}", e);
737 } 796 }
738 } 797 }
739
740 // TODO if we decide to do sitting in a more SL compatible way (multiple avatars per prim), this has to be fixed, too
741 if (SitTargetAvatar != UUID.Zero)
742 {
743 ScenePresence avatar;
744 if (ParentGroup.Scene.TryGetScenePresence(SitTargetAvatar, out avatar))
745 {
746 avatar.ParentPosition = GetWorldPosition();
747 }
748 }
749 } 798 }
750 } 799 }
751 800
@@ -842,7 +891,7 @@ namespace OpenSim.Region.Framework.Scenes
842 //m_log.Info("[PART]: RO2:" + actor.Orientation.ToString()); 891 //m_log.Info("[PART]: RO2:" + actor.Orientation.ToString());
843 } 892 }
844 893
845 if (ParentGroup != null) 894 if (ParentGroup != null && ParentGroup.Scene != null && ParentGroup.Scene.PhysicsScene != null)
846 ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor); 895 ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor);
847 //} 896 //}
848 } 897 }
@@ -880,14 +929,17 @@ namespace OpenSim.Region.Framework.Scenes
880 929
881 set 930 set
882 { 931 {
883 m_velocity = value; 932 if (Util.IsNanOrInfinity(value))
933 m_velocity = Vector3.Zero;
934 else
935 m_velocity = value;
884 936
885 PhysicsActor actor = PhysActor; 937 PhysicsActor actor = PhysActor;
886 if (actor != null) 938 if (actor != null)
887 { 939 {
888 if (actor.IsPhysical) 940 if (actor.IsPhysical)
889 { 941 {
890 actor.Velocity = value; 942 actor.Velocity = m_velocity;
891 ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor); 943 ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor);
892 } 944 }
893 } 945 }
@@ -914,14 +966,30 @@ namespace OpenSim.Region.Framework.Scenes
914 } 966 }
915 return m_angularVelocity; 967 return m_angularVelocity;
916 } 968 }
917 set { m_angularVelocity = value; } 969 set
970 {
971 if (Util.IsNanOrInfinity(value))
972 m_angularVelocity = Vector3.Zero;
973 else
974 m_angularVelocity = value;
975
976 PhysicsActor actor = PhysActor;
977 if ((actor != null) && actor.IsPhysical)
978 actor.RotationalVelocity = m_angularVelocity;
979 }
918 } 980 }
919 981
920 /// <summary></summary> 982 /// <summary></summary>
921 public Vector3 Acceleration 983 public Vector3 Acceleration
922 { 984 {
923 get { return m_acceleration; } 985 get { return m_acceleration; }
924 set { m_acceleration = value; } 986 set
987 {
988 if (Util.IsNanOrInfinity(value))
989 m_acceleration = Vector3.Zero;
990 else
991 m_acceleration = value;
992 }
925 } 993 }
926 994
927 public string Description { get; set; } 995 public string Description { get; set; }
@@ -1028,6 +1096,7 @@ namespace OpenSim.Region.Framework.Scenes
1028 } 1096 }
1029 1097
1030 public UpdateRequired UpdateFlag { get; set; } 1098 public UpdateRequired UpdateFlag { get; set; }
1099 public bool UpdatePhysRequired { get; set; }
1031 1100
1032 /// <summary> 1101 /// <summary>
1033 /// Used for media on a prim. 1102 /// Used for media on a prim.
@@ -1110,23 +1179,14 @@ namespace OpenSim.Region.Framework.Scenes
1110 // the mappings more consistant. 1179 // the mappings more consistant.
1111 public Vector3 SitTargetPositionLL 1180 public Vector3 SitTargetPositionLL
1112 { 1181 {
1113 get { return new Vector3(m_sitTargetPosition.X, m_sitTargetPosition.Y,m_sitTargetPosition.Z); } 1182 get { return m_sitTargetPosition; }
1114 set { m_sitTargetPosition = value; } 1183 set { m_sitTargetPosition = value; }
1115 } 1184 }
1116 1185
1117 public Quaternion SitTargetOrientationLL 1186 public Quaternion SitTargetOrientationLL
1118 { 1187 {
1119 get 1188 get { return m_sitTargetOrientation; }
1120 { 1189 set { m_sitTargetOrientation = value; }
1121 return new Quaternion(
1122 m_sitTargetOrientation.X,
1123 m_sitTargetOrientation.Y,
1124 m_sitTargetOrientation.Z,
1125 m_sitTargetOrientation.W
1126 );
1127 }
1128
1129 set { m_sitTargetOrientation = new Quaternion(value.X, value.Y, value.Z, value.W); }
1130 } 1190 }
1131 1191
1132 public bool Stopped 1192 public bool Stopped
@@ -1264,7 +1324,7 @@ namespace OpenSim.Region.Framework.Scenes
1264 /// <value> 1324 /// <value>
1265 /// null if there are no sitting avatars. This is to save us create a hashset for every prim in a scene. 1325 /// null if there are no sitting avatars. This is to save us create a hashset for every prim in a scene.
1266 /// </value> 1326 /// </value>
1267 private HashSet<UUID> m_sittingAvatars; 1327 private HashSet<ScenePresence> m_sittingAvatars;
1268 1328
1269 public virtual UUID RegionID 1329 public virtual UUID RegionID
1270 { 1330 {
@@ -1315,6 +1375,157 @@ namespace OpenSim.Region.Framework.Scenes
1315 set { m_collisionSoundVolume = value; } 1375 set { m_collisionSoundVolume = value; }
1316 } 1376 }
1317 1377
1378 public byte DefaultPhysicsShapeType()
1379 {
1380 byte type;
1381
1382 if (Shape != null && (Shape.SculptType == (byte)SculptType.Mesh))
1383 type = (byte)PhysShapeType.convex;
1384 else
1385 type = (byte)PhysShapeType.prim;
1386
1387 return type;
1388 }
1389
1390 public byte PhysicsShapeType
1391 {
1392 get { return m_physicsShapeType; }
1393 set
1394 {
1395 byte oldv = m_physicsShapeType;
1396
1397 if (value >= 0 && value <= (byte)PhysShapeType.convex)
1398 {
1399 if (value == (byte)PhysShapeType.none && ParentGroup != null && ParentGroup.RootPart == this)
1400 m_physicsShapeType = DefaultPhysicsShapeType();
1401 else
1402 m_physicsShapeType = value;
1403 }
1404 else
1405 m_physicsShapeType = DefaultPhysicsShapeType();
1406
1407 if (m_physicsShapeType != oldv && ParentGroup != null)
1408 {
1409 if (m_physicsShapeType == (byte)PhysShapeType.none)
1410 {
1411 if (PhysActor != null)
1412 {
1413 Velocity = new Vector3(0, 0, 0);
1414 Acceleration = new Vector3(0, 0, 0);
1415 if (ParentGroup.RootPart == this)
1416 AngularVelocity = new Vector3(0, 0, 0);
1417 ParentGroup.Scene.RemovePhysicalPrim(1);
1418 RemoveFromPhysics();
1419 }
1420 }
1421 else if (PhysActor == null)
1422 {
1423 ApplyPhysics((uint)Flags, VolumeDetectActive);
1424 }
1425 else
1426 {
1427 PhysActor.PhysicsShapeType = m_physicsShapeType;
1428 }
1429
1430 if (ParentGroup != null)
1431 ParentGroup.HasGroupChanged = true;
1432 }
1433
1434 if (m_physicsShapeType != value)
1435 {
1436 UpdatePhysRequired = true;
1437 }
1438 }
1439 }
1440
1441 public float Density // in kg/m^3
1442 {
1443 get { return m_density; }
1444 set
1445 {
1446 if (value >=1 && value <= 22587.0)
1447 {
1448 m_density = value;
1449 UpdatePhysRequired = true;
1450 }
1451
1452 ScheduleFullUpdateIfNone();
1453
1454 if (ParentGroup != null)
1455 ParentGroup.HasGroupChanged = true;
1456
1457 PhysicsActor pa = PhysActor;
1458 if (pa != null)
1459 pa.Density = Density;
1460 }
1461 }
1462
1463 public float GravityModifier
1464 {
1465 get { return m_gravitymod; }
1466 set
1467 {
1468 if( value >= -1 && value <=28.0f)
1469 {
1470 m_gravitymod = value;
1471 UpdatePhysRequired = true;
1472 }
1473
1474 ScheduleFullUpdateIfNone();
1475
1476 if (ParentGroup != null)
1477 ParentGroup.HasGroupChanged = true;
1478
1479 PhysicsActor pa = PhysActor;
1480 if (pa != null)
1481 pa.GravModifier = GravityModifier;
1482 }
1483 }
1484
1485 public float Friction
1486 {
1487 get { return m_friction; }
1488 set
1489 {
1490 if (value >= 0 && value <= 255.0f)
1491 {
1492 m_friction = value;
1493 UpdatePhysRequired = true;
1494 }
1495
1496 ScheduleFullUpdateIfNone();
1497
1498 if (ParentGroup != null)
1499 ParentGroup.HasGroupChanged = true;
1500
1501 PhysicsActor pa = PhysActor;
1502 if (pa != null)
1503 pa.Friction = Friction;
1504 }
1505 }
1506
1507 public float Restitution
1508 {
1509 get { return m_bounce; }
1510 set
1511 {
1512 if (value >= 0 && value <= 1.0f)
1513 {
1514 m_bounce = value;
1515 UpdatePhysRequired = true;
1516 }
1517
1518 ScheduleFullUpdateIfNone();
1519
1520 if (ParentGroup != null)
1521 ParentGroup.HasGroupChanged = true;
1522
1523 PhysicsActor pa = PhysActor;
1524 if (pa != null)
1525 pa.Restitution = Restitution;
1526 }
1527 }
1528
1318 #endregion Public Properties with only Get 1529 #endregion Public Properties with only Get
1319 1530
1320 private uint ApplyMask(uint val, bool set, uint mask) 1531 private uint ApplyMask(uint val, bool set, uint mask)
@@ -1403,20 +1614,29 @@ namespace OpenSim.Region.Framework.Scenes
1403 1614
1404 public void AddTextureAnimation(Primitive.TextureAnimation pTexAnim) 1615 public void AddTextureAnimation(Primitive.TextureAnimation pTexAnim)
1405 { 1616 {
1406 byte[] data = new byte[16]; 1617 byte[] data;
1407 int pos = 0;
1408 1618
1409 // The flags don't like conversion from uint to byte, so we have to do 1619 if (pTexAnim.Flags == Primitive.TextureAnimMode.ANIM_OFF)
1410 // it the crappy way. See the above function :( 1620 {
1621 data = Utils.EmptyBytes;
1622 }
1623 else
1624 {
1625 data = new byte[16];
1626 int pos = 0;
1411 1627
1412 data[pos] = ConvertScriptUintToByte((uint)pTexAnim.Flags); pos++; 1628 // The flags don't like conversion from uint to byte, so we have to do
1413 data[pos] = (byte)pTexAnim.Face; pos++; 1629 // it the crappy way. See the above function :(
1414 data[pos] = (byte)pTexAnim.SizeX; pos++;
1415 data[pos] = (byte)pTexAnim.SizeY; pos++;
1416 1630
1417 Utils.FloatToBytes(pTexAnim.Start).CopyTo(data, pos); 1631 data[pos] = ConvertScriptUintToByte((uint)pTexAnim.Flags); pos++;
1418 Utils.FloatToBytes(pTexAnim.Length).CopyTo(data, pos + 4); 1632 data[pos] = (byte)pTexAnim.Face; pos++;
1419 Utils.FloatToBytes(pTexAnim.Rate).CopyTo(data, pos + 8); 1633 data[pos] = (byte)pTexAnim.SizeX; pos++;
1634 data[pos] = (byte)pTexAnim.SizeY; pos++;
1635
1636 Utils.FloatToBytes(pTexAnim.Start).CopyTo(data, pos);
1637 Utils.FloatToBytes(pTexAnim.Length).CopyTo(data, pos + 4);
1638 Utils.FloatToBytes(pTexAnim.Rate).CopyTo(data, pos + 8);
1639 }
1420 1640
1421 m_TextureAnimation = data; 1641 m_TextureAnimation = data;
1422 } 1642 }
@@ -1511,40 +1731,36 @@ namespace OpenSim.Region.Framework.Scenes
1511 /// </summary> 1731 /// </summary>
1512 /// <param name="rootObjectFlags"></param> 1732 /// <param name="rootObjectFlags"></param>
1513 /// <param name="VolumeDetectActive"></param> 1733 /// <param name="VolumeDetectActive"></param>
1514 public void ApplyPhysics(uint rootObjectFlags, bool VolumeDetectActive) 1734 public void ApplyPhysics(uint rootObjectFlags, bool _VolumeDetectActive)
1515 { 1735 {
1736 VolumeDetectActive = _VolumeDetectActive;
1737
1516 if (!ParentGroup.Scene.CollidablePrims) 1738 if (!ParentGroup.Scene.CollidablePrims)
1517 return; 1739 return;
1518 1740
1519// m_log.DebugFormat( 1741 if (PhysicsShapeType == (byte)PhysShapeType.none)
1520// "[SCENE OBJECT PART]: Applying physics to {0} {1}, m_physicalPrim {2}", 1742 return;
1521// Name, LocalId, UUID, m_physicalPrim);
1522 1743
1523 bool isPhysical = (rootObjectFlags & (uint) PrimFlags.Physics) != 0; 1744 bool isPhysical = (rootObjectFlags & (uint) PrimFlags.Physics) != 0;
1524 bool isPhantom = (rootObjectFlags & (uint) PrimFlags.Phantom) != 0; 1745 bool isPhantom = (rootObjectFlags & (uint) PrimFlags.Phantom) != 0;
1525 1746
1747 if (_VolumeDetectActive)
1748 isPhantom = true;
1749
1526 if (IsJoint()) 1750 if (IsJoint())
1527 { 1751 {
1528 DoPhysicsPropertyUpdate(isPhysical, true); 1752 DoPhysicsPropertyUpdate(isPhysical, true);
1529 } 1753 }
1530 else 1754 else
1531 { 1755 {
1532 // Special case for VolumeDetection: If VolumeDetection is set, the phantom flag is locally ignored 1756 if ((!isPhantom || isPhysical || _VolumeDetectActive)
1533 if (VolumeDetectActive) 1757 && !ParentGroup.IsAttachmentCheckFull()
1534 isPhantom = false; 1758 && !(Shape.PathCurve == (byte)Extrusion.Flexible))
1535
1536 // The only time the physics scene shouldn't know about the prim is if it's phantom or an attachment, which is phantom by definition
1537 // or flexible
1538 if (!isPhantom && !ParentGroup.IsAttachment && !(Shape.PathCurve == (byte)Extrusion.Flexible))
1539 { 1759 {
1540 // Added clarification.. since A rigid body is an object that you can kick around, etc. 1760 AddToPhysics(isPhysical, isPhantom, isPhysical);
1541 bool rigidBody = isPhysical && !isPhantom;
1542
1543 PhysicsActor pa = AddToPhysics(rigidBody);
1544
1545 if (pa != null)
1546 pa.SetVolumeDetect(VolumeDetectActive ? 1 : 0);
1547 } 1761 }
1762 else
1763 PhysActor = null; // just to be sure
1548 } 1764 }
1549 } 1765 }
1550 1766
@@ -1572,7 +1788,11 @@ namespace OpenSim.Region.Framework.Scenes
1572 /// <returns></returns> 1788 /// <returns></returns>
1573 public SceneObjectPart Copy(uint localID, UUID AgentID, UUID GroupID, int linkNum, bool userExposed) 1789 public SceneObjectPart Copy(uint localID, UUID AgentID, UUID GroupID, int linkNum, bool userExposed)
1574 { 1790 {
1791 // FIXME: This is dangerous since it's easy to forget to reset some references when necessary and end up
1792 // with bugs that only occur in some circumstances (e.g. crossing between regions on the same simulator
1793 // but not between regions on different simulators). Really, all copying should be done explicitly.
1575 SceneObjectPart dupe = (SceneObjectPart)MemberwiseClone(); 1794 SceneObjectPart dupe = (SceneObjectPart)MemberwiseClone();
1795
1576 dupe.m_shape = m_shape.Copy(); 1796 dupe.m_shape = m_shape.Copy();
1577 dupe.m_regionHandle = m_regionHandle; 1797 dupe.m_regionHandle = m_regionHandle;
1578 if (userExposed) 1798 if (userExposed)
@@ -1618,6 +1838,14 @@ namespace OpenSim.Region.Framework.Scenes
1618 Array.Copy(Shape.ExtraParams, extraP, extraP.Length); 1838 Array.Copy(Shape.ExtraParams, extraP, extraP.Length);
1619 dupe.Shape.ExtraParams = extraP; 1839 dupe.Shape.ExtraParams = extraP;
1620 1840
1841 dupe.m_sittingAvatars = new HashSet<ScenePresence>();
1842
1843 // safeguard actual copy is done in sog.copy
1844 dupe.KeyframeMotion = null;
1845 dupe.PayPrice = (int[])PayPrice.Clone();
1846
1847 dupe.DynAttrs.CopyFrom(DynAttrs);
1848
1621 if (userExposed) 1849 if (userExposed)
1622 { 1850 {
1623/* 1851/*
@@ -1816,6 +2044,9 @@ namespace OpenSim.Region.Framework.Scenes
1816 { 2044 {
1817 if (UsePhysics) 2045 if (UsePhysics)
1818 { 2046 {
2047 if (ParentGroup.RootPart.KeyframeMotion != null)
2048 ParentGroup.RootPart.KeyframeMotion.Stop();
2049 ParentGroup.RootPart.KeyframeMotion = null;
1819 ParentGroup.Scene.AddPhysicalPrim(1); 2050 ParentGroup.Scene.AddPhysicalPrim(1);
1820 2051
1821 pa.OnRequestTerseUpdate += PhysicsRequestingTerseUpdate; 2052 pa.OnRequestTerseUpdate += PhysicsRequestingTerseUpdate;
@@ -1848,7 +2079,7 @@ namespace OpenSim.Region.Framework.Scenes
1848 /// </summary> 2079 /// </summary>
1849 /// <param name="xmlReader"></param> 2080 /// <param name="xmlReader"></param>
1850 /// <returns></returns> 2081 /// <returns></returns>
1851 public static SceneObjectPart FromXml(XmlTextReader xmlReader) 2082 public static SceneObjectPart FromXml(XmlReader xmlReader)
1852 { 2083 {
1853 SceneObjectPart part = SceneObjectSerializer.Xml2ToSOP(xmlReader); 2084 SceneObjectPart part = SceneObjectSerializer.Xml2ToSOP(xmlReader);
1854 2085
@@ -1883,22 +2114,6 @@ namespace OpenSim.Region.Framework.Scenes
1883 ParentGroup.RootPart.RETURN_AT_EDGE = p; 2114 ParentGroup.RootPart.RETURN_AT_EDGE = p;
1884 } 2115 }
1885 2116
1886 public bool GetBlockGrab()
1887 {
1888 if (ParentGroup.IsDeleted)
1889 return false;
1890
1891 return ParentGroup.RootPart.BlockGrab;
1892 }
1893
1894 public void SetBlockGrab(bool p)
1895 {
1896 if (ParentGroup.IsDeleted)
1897 return;
1898
1899 ParentGroup.RootPart.BlockGrab = p;
1900 }
1901
1902 public void SetStatusSandbox(bool p) 2117 public void SetStatusSandbox(bool p)
1903 { 2118 {
1904 if (ParentGroup.IsDeleted) 2119 if (ParentGroup.IsDeleted)
@@ -1952,9 +2167,19 @@ namespace OpenSim.Region.Framework.Scenes
1952 PhysicsActor pa = PhysActor; 2167 PhysicsActor pa = PhysActor;
1953 2168
1954 if (pa != null) 2169 if (pa != null)
1955 return new Vector3(pa.CenterOfMass.X, pa.CenterOfMass.Y, pa.CenterOfMass.Z); 2170 return pa.GeometricCenter;
2171 else
2172 return Vector3.Zero;
2173 }
2174
2175 public Vector3 GetCenterOfMass()
2176 {
2177 PhysicsActor pa = PhysActor;
2178
2179 if (pa != null)
2180 return pa.CenterOfMass;
1956 else 2181 else
1957 return new Vector3(0, 0, 0); 2182 return Vector3.Zero;
1958 } 2183 }
1959 2184
1960 public float GetMass() 2185 public float GetMass()
@@ -2030,7 +2255,7 @@ namespace OpenSim.Region.Framework.Scenes
2030 { 2255 {
2031 if (tau > 0) 2256 if (tau > 0)
2032 { 2257 {
2033 ParentGroup.moveToTarget(target, tau); 2258 ParentGroup.MoveToTarget(target, tau);
2034 } 2259 }
2035 else 2260 else
2036 { 2261 {
@@ -2168,7 +2393,7 @@ namespace OpenSim.Region.Framework.Scenes
2168 CollidingMessage = CreateColliderArgs(this, colliders); 2393 CollidingMessage = CreateColliderArgs(this, colliders);
2169 2394
2170 if (CollidingMessage.Colliders.Count > 0) 2395 if (CollidingMessage.Colliders.Count > 0)
2171 notify(LocalId, CollidingMessage); 2396 DoNotify(notify, LocalId, CollidingMessage);
2172 2397
2173 if (PassCollisions) 2398 if (PassCollisions)
2174 sendToRoot = true; 2399 sendToRoot = true;
@@ -2182,7 +2407,7 @@ namespace OpenSim.Region.Framework.Scenes
2182 { 2407 {
2183 CollidingMessage = CreateColliderArgs(ParentGroup.RootPart, colliders); 2408 CollidingMessage = CreateColliderArgs(ParentGroup.RootPart, colliders);
2184 if (CollidingMessage.Colliders.Count > 0) 2409 if (CollidingMessage.Colliders.Count > 0)
2185 notify(ParentGroup.RootPart.LocalId, CollidingMessage); 2410 DoNotify(notify, ParentGroup.RootPart.LocalId, CollidingMessage);
2186 } 2411 }
2187 } 2412 }
2188 } 2413 }
@@ -2197,7 +2422,33 @@ namespace OpenSim.Region.Framework.Scenes
2197 colliding.Add(CreateDetObjectForGround()); 2422 colliding.Add(CreateDetObjectForGround());
2198 LandCollidingMessage.Colliders = colliding; 2423 LandCollidingMessage.Colliders = colliding;
2199 2424
2200 notify(LocalId, LandCollidingMessage); 2425 DoNotify(notify, LocalId, LandCollidingMessage);
2426 }
2427 }
2428
2429 private void DoNotify(ScriptCollidingNotification notify, uint id, ColliderArgs collargs)
2430 {
2431 if (m_parentGroup != null && ParentGroup.Scene != null && ParentGroup.Scene.ShouldUseFireAndForgetForCollisions)
2432 {
2433 // For those learning C#, FireAndForget takes a function, an object to pass
2434 // to that function and an ID string. The "oo => {}" construct is a lambda expression
2435 // for a function with one arguement ('oo'). The 'new Object[] {}" construct creates an Object
2436 // that is an object array and initializes it with three items (the parameters
2437 // being passed). The parameters passed are the function to call ('notify') and
2438 // its two arguements. Finally, once in the function (called later by the FireAndForget
2439 // thread scheduler), the passed object is cast to an object array and then each
2440 // of its items (aoo[0] to aoo[2]) are individually cast to what they are and
2441 // then used in a call of the passed ScriptCollidingNotification function.
2442 Util.FireAndForget(oo =>
2443 {
2444 Object[] aoo = (Object[])oo;
2445 ((ScriptCollidingNotification)aoo[0])((uint)aoo[1], (ColliderArgs)aoo[2]);
2446
2447 }, new Object[] { notify, id, collargs }, "SOP.Collision");
2448 }
2449 else
2450 {
2451 notify(id, collargs);
2201 } 2452 }
2202 } 2453 }
2203 2454
@@ -2244,7 +2495,7 @@ namespace OpenSim.Region.Framework.Scenes
2244 if (soundModule != null) 2495 if (soundModule != null)
2245 { 2496 {
2246 soundModule.SendSound(UUID, CollisionSound, 2497 soundModule.SendSound(UUID, CollisionSound,
2247 CollisionSoundVolume, true, (byte)0, 0, false, 2498 CollisionSoundVolume, true, 0, 0, false,
2248 false); 2499 false);
2249 } 2500 }
2250 } 2501 }
@@ -2254,12 +2505,9 @@ namespace OpenSim.Region.Framework.Scenes
2254 SendCollisionEvent(scriptEvents.collision_end , endedColliders , ParentGroup.Scene.EventManager.TriggerScriptCollidingEnd); 2505 SendCollisionEvent(scriptEvents.collision_end , endedColliders , ParentGroup.Scene.EventManager.TriggerScriptCollidingEnd);
2255 2506
2256 if (startedColliders.Contains(0)) 2507 if (startedColliders.Contains(0))
2257 { 2508 SendLandCollisionEvent(scriptEvents.land_collision_start, ParentGroup.Scene.EventManager.TriggerScriptLandCollidingStart);
2258 if (m_lastColliders.Contains(0)) 2509 if (m_lastColliders.Contains(0))
2259 SendLandCollisionEvent(scriptEvents.land_collision, ParentGroup.Scene.EventManager.TriggerScriptLandColliding); 2510 SendLandCollisionEvent(scriptEvents.land_collision, ParentGroup.Scene.EventManager.TriggerScriptLandColliding);
2260 else
2261 SendLandCollisionEvent(scriptEvents.land_collision_start, ParentGroup.Scene.EventManager.TriggerScriptLandCollidingStart);
2262 }
2263 if (endedColliders.Contains(0)) 2511 if (endedColliders.Contains(0))
2264 SendLandCollisionEvent(scriptEvents.land_collision_end, ParentGroup.Scene.EventManager.TriggerScriptLandCollidingEnd); 2512 SendLandCollisionEvent(scriptEvents.land_collision_end, ParentGroup.Scene.EventManager.TriggerScriptLandCollidingEnd);
2265 } 2513 }
@@ -2282,19 +2530,36 @@ namespace OpenSim.Region.Framework.Scenes
2282 2530
2283 if (pa != null) 2531 if (pa != null)
2284 { 2532 {
2285 Vector3 newpos = new Vector3(pa.Position.GetBytes(), 0); 2533 Vector3 newpos = pa.Position;
2286 2534 if (!ParentGroup.Scene.PositionIsInCurrentRegion(newpos))
2287 if (ParentGroup.Scene.TestBorderCross(newpos, Cardinals.N)
2288 | ParentGroup.Scene.TestBorderCross(newpos, Cardinals.S)
2289 | ParentGroup.Scene.TestBorderCross(newpos, Cardinals.E)
2290 | ParentGroup.Scene.TestBorderCross(newpos, Cardinals.W))
2291 { 2535 {
2536 // Setting position outside current region will start region crossing
2292 ParentGroup.AbsolutePosition = newpos; 2537 ParentGroup.AbsolutePosition = newpos;
2293 return; 2538 return;
2294 } 2539 }
2295 //ParentGroup.RootPart.m_groupPosition = newpos; 2540 //ParentGroup.RootPart.m_groupPosition = newpos;
2296 } 2541 }
2297 2542
2543 if (pa != null && ParentID != 0 && ParentGroup != null)
2544 {
2545 // Special case where a child object is requesting property updates.
2546 // This happens when linksets are modified to use flexible links rather than
2547 // the default links.
2548 // The simulator code presumes that child parts are only modified by scripts
2549 // so the logic for changing position/rotation/etc does not take into
2550 // account the physical object actually moving.
2551 // This code updates the offset position and rotation of the child and then
2552 // lets the update code push the update to the viewer.
2553 // Since physics engines do not normally generate this event for linkset children,
2554 // this code will not be active unless you have a specially configured
2555 // physics engine.
2556 Quaternion invRootRotation = Quaternion.Normalize(Quaternion.Inverse(ParentGroup.RootPart.RotationOffset));
2557 m_offsetPosition = pa.Position - m_groupPosition;
2558 RotationOffset = pa.Orientation * invRootRotation;
2559 // m_log.DebugFormat("{0} PhysicsRequestingTerseUpdate child: pos={1}, rot={2}, offPos={3}, offRot={4}",
2560 // "[SCENE OBJECT PART]", pa.Position, pa.Orientation, m_offsetPosition, RotationOffset);
2561 }
2562
2298 ScheduleTerseUpdate(); 2563 ScheduleTerseUpdate();
2299 } 2564 }
2300 2565
@@ -2397,7 +2662,7 @@ namespace OpenSim.Region.Framework.Scenes
2397 return; 2662 return;
2398 } 2663 }
2399 2664
2400 m_APIDIterations = 1 + (int)(Math.PI * APIDStrength); 2665 APIDActive = true;
2401 } 2666 }
2402 2667
2403 // Necessary to get the lookat deltas applied 2668 // Necessary to get the lookat deltas applied
@@ -2411,7 +2676,20 @@ namespace OpenSim.Region.Framework.Scenes
2411 2676
2412 public void StopLookAt() 2677 public void StopLookAt()
2413 { 2678 {
2414 APIDTarget = Quaternion.Identity; 2679 APIDActive = false;
2680 }
2681
2682
2683
2684 public void ScheduleFullUpdateIfNone()
2685 {
2686 if (ParentGroup == null)
2687 return;
2688
2689// ??? ParentGroup.HasGroupChanged = true;
2690
2691 if (UpdateFlag != UpdateRequired.FULL)
2692 ScheduleFullUpdate();
2415 } 2693 }
2416 2694
2417 /// <summary> 2695 /// <summary>
@@ -2460,7 +2738,8 @@ namespace OpenSim.Region.Framework.Scenes
2460 return; 2738 return;
2461 2739
2462 // This was pulled from SceneViewer. Attachments always receive full updates. 2740 // This was pulled from SceneViewer. Attachments always receive full updates.
2463 // I could not verify if this is a requirement but this maintains existing behavior 2741 // This is needed because otherwise if only the root prim changes position, then
2742 // it looks as if the entire object has moved (including the other prims).
2464 if (ParentGroup.IsAttachment) 2743 if (ParentGroup.IsAttachment)
2465 { 2744 {
2466 ScheduleFullUpdate(); 2745 ScheduleFullUpdate();
@@ -2996,6 +3275,10 @@ namespace OpenSim.Region.Framework.Scenes
2996 /// <param name="events"></param> 3275 /// <param name="events"></param>
2997 public void SetScriptEvents(UUID scriptid, int events) 3276 public void SetScriptEvents(UUID scriptid, int events)
2998 { 3277 {
3278// m_log.DebugFormat(
3279// "[SCENE OBJECT PART]: Set script events for script with id {0} on {1}/{2} to {3} in {4}",
3280// scriptid, Name, ParentGroup.Name, events, ParentGroup.Scene.Name);
3281
2999 // scriptEvents oldparts; 3282 // scriptEvents oldparts;
3000 lock (m_scriptEvents) 3283 lock (m_scriptEvents)
3001 { 3284 {
@@ -3048,10 +3331,7 @@ namespace OpenSim.Region.Framework.Scenes
3048 3331
3049 public void StopMoveToTarget() 3332 public void StopMoveToTarget()
3050 { 3333 {
3051 ParentGroup.stopMoveToTarget(); 3334 ParentGroup.StopMoveToTarget();
3052
3053 ParentGroup.ScheduleGroupForTerseUpdate();
3054 //ParentGroup.ScheduleGroupForFullUpdate();
3055 } 3335 }
3056 3336
3057 public void StoreUndoState() 3337 public void StoreUndoState()
@@ -3618,6 +3898,7 @@ namespace OpenSim.Region.Framework.Scenes
3618 result.distance = distance2; 3898 result.distance = distance2;
3619 result.HitTF = true; 3899 result.HitTF = true;
3620 result.ipoint = q; 3900 result.ipoint = q;
3901 result.face = i;
3621 //m_log.Info("[FACE]:" + i.ToString()); 3902 //m_log.Info("[FACE]:" + i.ToString());
3622 //m_log.Info("[POINT]: " + q.ToString()); 3903 //m_log.Info("[POINT]: " + q.ToString());
3623 //m_log.Info("[DIST]: " + distance2.ToString()); 3904 //m_log.Info("[DIST]: " + distance2.ToString());
@@ -3664,10 +3945,10 @@ namespace OpenSim.Region.Framework.Scenes
3664 3945
3665 public void TrimPermissions() 3946 public void TrimPermissions()
3666 { 3947 {
3667 BaseMask &= (uint)PermissionMask.All; 3948 BaseMask &= (uint)(PermissionMask.All | PermissionMask.Export);
3668 OwnerMask &= (uint)PermissionMask.All; 3949 OwnerMask &= (uint)(PermissionMask.All | PermissionMask.Export);
3669 GroupMask &= (uint)PermissionMask.All; 3950 GroupMask &= (uint)PermissionMask.All;
3670 EveryoneMask &= (uint)PermissionMask.All; 3951 EveryoneMask &= (uint)(PermissionMask.All | PermissionMask.Export);
3671 NextOwnerMask &= (uint)PermissionMask.All; 3952 NextOwnerMask &= (uint)PermissionMask.All;
3672 } 3953 }
3673 3954
@@ -3690,30 +3971,31 @@ namespace OpenSim.Region.Framework.Scenes
3690 } 3971 }
3691 } 3972 }
3692 3973
3693 public void UpdateGroupPosition(Vector3 pos) 3974 public void UpdateGroupPosition(Vector3 newPos)
3694 { 3975 {
3695 if ((pos.X != GroupPosition.X) || 3976 Vector3 oldPos = GroupPosition;
3696 (pos.Y != GroupPosition.Y) || 3977
3697 (pos.Z != GroupPosition.Z)) 3978 if ((newPos.X != oldPos.X) ||
3979 (newPos.Y != oldPos.Y) ||
3980 (newPos.Z != oldPos.Z))
3698 { 3981 {
3699 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
3700 GroupPosition = newPos; 3982 GroupPosition = newPos;
3701 ScheduleTerseUpdate(); 3983 ScheduleTerseUpdate();
3702 } 3984 }
3703 } 3985 }
3704 3986
3705 /// <summary> 3987 /// <summary>
3706 /// 3988 /// Update this part's offset position.
3707 /// </summary> 3989 /// </summary>
3708 /// <param name="pos"></param> 3990 /// <param name="pos"></param>
3709 public void UpdateOffSet(Vector3 pos) 3991 public void UpdateOffSet(Vector3 newPos)
3710 { 3992 {
3711 if ((pos.X != OffsetPosition.X) || 3993 Vector3 oldPos = OffsetPosition;
3712 (pos.Y != OffsetPosition.Y) ||
3713 (pos.Z != OffsetPosition.Z))
3714 {
3715 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
3716 3994
3995 if ((newPos.X != oldPos.X) ||
3996 (newPos.Y != oldPos.Y) ||
3997 (newPos.Z != oldPos.Z))
3998 {
3717 if (ParentGroup.RootPart.GetStatusSandbox()) 3999 if (ParentGroup.RootPart.GetStatusSandbox())
3718 { 4000 {
3719 if (Util.GetDistanceTo(ParentGroup.RootPart.StatusSandboxPos, newPos) > 10) 4001 if (Util.GetDistanceTo(ParentGroup.RootPart.StatusSandboxPos, newPos) > 10)
@@ -3770,10 +4052,22 @@ namespace OpenSim.Region.Framework.Scenes
3770 baseMask; 4052 baseMask;
3771 break; 4053 break;
3772 case 8: 4054 case 8:
4055 // Trying to set export permissions - extra checks
4056 if (set && (mask & (uint)PermissionMask.Export) != 0)
4057 {
4058 if ((OwnerMask & (uint)PermissionMask.Export) == 0 || (BaseMask & (uint)PermissionMask.Export) == 0 || (NextOwnerMask & (uint)PermissionMask.All) != (uint)PermissionMask.All)
4059 mask &= ~(uint)PermissionMask.Export;
4060 }
3773 EveryoneMask = ApplyMask(EveryoneMask, set, mask) & 4061 EveryoneMask = ApplyMask(EveryoneMask, set, mask) &
3774 baseMask; 4062 baseMask;
3775 break; 4063 break;
3776 case 16: 4064 case 16:
4065 // Force full perm if export
4066 if ((EveryoneMask & (uint)PermissionMask.Export) != 0)
4067 {
4068 NextOwnerMask = (uint)PermissionMask.All;
4069 break;
4070 }
3777 NextOwnerMask = ApplyMask(NextOwnerMask, set, mask) & 4071 NextOwnerMask = ApplyMask(NextOwnerMask, set, mask) &
3778 baseMask; 4072 baseMask;
3779 // Prevent the client from creating no mod, no copy 4073 // Prevent the client from creating no mod, no copy
@@ -3848,7 +4142,7 @@ namespace OpenSim.Region.Framework.Scenes
3848 // For now, we use the NINJA naming scheme for identifying joints. 4142 // For now, we use the NINJA naming scheme for identifying joints.
3849 // In the future, we can support other joint specification schemes such as a 4143 // In the future, we can support other joint specification schemes such as a
3850 // custom checkbox in the viewer GUI. 4144 // custom checkbox in the viewer GUI.
3851 if (ParentGroup.Scene != null && ParentGroup.Scene.PhysicsScene.SupportsNINJAJoints) 4145 if (ParentGroup.Scene != null && ParentGroup.Scene.PhysicsScene != null && ParentGroup.Scene.PhysicsScene.SupportsNINJAJoints)
3852 { 4146 {
3853 return IsHingeJoint() || IsBallJoint(); 4147 return IsHingeJoint() || IsBallJoint();
3854 } 4148 }
@@ -3858,6 +4152,26 @@ namespace OpenSim.Region.Framework.Scenes
3858 } 4152 }
3859 } 4153 }
3860 4154
4155 public void UpdateExtraPhysics(ExtraPhysicsData physdata)
4156 {
4157 if (physdata.PhysShapeType == PhysShapeType.invalid || ParentGroup == null)
4158 return;
4159
4160 if (PhysicsShapeType != (byte)physdata.PhysShapeType)
4161 {
4162 PhysicsShapeType = (byte)physdata.PhysShapeType;
4163
4164 }
4165
4166 if(Density != physdata.Density)
4167 Density = physdata.Density;
4168 if(GravityModifier != physdata.GravitationModifier)
4169 GravityModifier = physdata.GravitationModifier;
4170 if(Friction != physdata.Friction)
4171 Friction = physdata.Friction;
4172 if(Restitution != physdata.Bounce)
4173 Restitution = physdata.Bounce;
4174 }
3861 /// <summary> 4175 /// <summary>
3862 /// Update the flags on this prim. This covers properties such as phantom, physics and temporary. 4176 /// Update the flags on this prim. This covers properties such as phantom, physics and temporary.
3863 /// </summary> 4177 /// </summary>
@@ -3928,7 +4242,8 @@ namespace OpenSim.Region.Framework.Scenes
3928 } 4242 }
3929 4243
3930 if (SetPhantom 4244 if (SetPhantom
3931 || ParentGroup.IsAttachment 4245 || ParentGroup.IsAttachmentCheckFull()
4246 || PhysicsShapeType == (byte)PhysShapeType.none
3932 || (Shape.PathCurve == (byte)Extrusion.Flexible)) // note: this may have been changed above in the case of joints 4247 || (Shape.PathCurve == (byte)Extrusion.Flexible)) // note: this may have been changed above in the case of joints
3933 { 4248 {
3934 AddFlag(PrimFlags.Phantom); 4249 AddFlag(PrimFlags.Phantom);
@@ -3948,32 +4263,17 @@ namespace OpenSim.Region.Framework.Scenes
3948 4263
3949 if (ParentGroup.Scene.CollidablePrims && pa == null) 4264 if (ParentGroup.Scene.CollidablePrims && pa == null)
3950 { 4265 {
3951 pa = AddToPhysics(UsePhysics); 4266 AddToPhysics(UsePhysics, SetPhantom, false);
4267 pa = PhysActor;
3952 4268
3953 if (pa != null) 4269 if (pa != null)
3954 { 4270 {
3955 pa.SetMaterial(Material); 4271 pa.SetMaterial(Material);
4272 pa.Position = GetWorldPosition();
4273 pa.Orientation = GetWorldRotation();
3956 DoPhysicsPropertyUpdate(UsePhysics, true); 4274 DoPhysicsPropertyUpdate(UsePhysics, true);
3957 4275
3958 if ( 4276 SubscribeForCollisionEvents();
3959 ((AggregateScriptEvents & scriptEvents.collision) != 0) ||
3960 ((AggregateScriptEvents & scriptEvents.collision_end) != 0) ||
3961 ((AggregateScriptEvents & scriptEvents.collision_start) != 0) ||
3962 ((AggregateScriptEvents & scriptEvents.land_collision_start) != 0) ||
3963 ((AggregateScriptEvents & scriptEvents.land_collision) != 0) ||
3964 ((AggregateScriptEvents & scriptEvents.land_collision_end) != 0) ||
3965 ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.collision) != 0) ||
3966 ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.collision_end) != 0) ||
3967 ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.collision_start) != 0) ||
3968 ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.land_collision_start) != 0) ||
3969 ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.land_collision) != 0) ||
3970 ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.land_collision_end) != 0) ||
3971 (CollisionSound != UUID.Zero)
3972 )
3973 {
3974 pa.OnCollisionUpdate += PhysicsCollision;
3975 pa.SubscribeEvents(1000);
3976 }
3977 } 4277 }
3978 } 4278 }
3979 else // it already has a physical representation 4279 else // it already has a physical representation
@@ -4028,6 +4328,50 @@ namespace OpenSim.Region.Framework.Scenes
4028 } 4328 }
4029 4329
4030 /// <summary> 4330 /// <summary>
4331 /// Subscribe for physics collision events if needed for scripts and sounds
4332 /// </summary>
4333 public void SubscribeForCollisionEvents()
4334 {
4335 PhysicsActor pa = PhysActor;
4336
4337 if (pa != null)
4338 {
4339 if (
4340 ((AggregateScriptEvents & scriptEvents.collision) != 0) ||
4341 ((AggregateScriptEvents & scriptEvents.collision_end) != 0) ||
4342 ((AggregateScriptEvents & scriptEvents.collision_start) != 0) ||
4343 ((AggregateScriptEvents & scriptEvents.land_collision_start) != 0) ||
4344 ((AggregateScriptEvents & scriptEvents.land_collision) != 0) ||
4345 ((AggregateScriptEvents & scriptEvents.land_collision_end) != 0) ||
4346 ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.collision) != 0) ||
4347 ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.collision_end) != 0) ||
4348 ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.collision_start) != 0) ||
4349 ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.land_collision_start) != 0) ||
4350 ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.land_collision) != 0) ||
4351 ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.land_collision_end) != 0) ||
4352 (CollisionSound != UUID.Zero)
4353 )
4354 {
4355 if (!pa.SubscribedEvents())
4356 {
4357 // If not already subscribed for event, set up for a collision event.
4358 pa.OnCollisionUpdate += PhysicsCollision;
4359 pa.SubscribeEvents(1000);
4360 }
4361 }
4362 else
4363 {
4364 // There is no need to be subscribed to collisions so, if subscribed, remove subscription
4365 if (pa.SubscribedEvents())
4366 {
4367 pa.OnCollisionUpdate -= PhysicsCollision;
4368 pa.UnSubscribeEvents();
4369 }
4370 }
4371 }
4372 }
4373
4374 /// <summary>
4031 /// Adds this part to the physics scene. 4375 /// Adds this part to the physics scene.
4032 /// </summary> 4376 /// </summary>
4033 /// <remarks>This method also sets the PhysActor property.</remarks> 4377 /// <remarks>This method also sets the PhysActor property.</remarks>
@@ -4035,10 +4379,13 @@ namespace OpenSim.Region.Framework.Scenes
4035 /// <returns> 4379 /// <returns>
4036 /// The physics actor. null if there was a failure. 4380 /// The physics actor. null if there was a failure.
4037 /// </returns> 4381 /// </returns>
4038 private PhysicsActor AddToPhysics(bool rigidBody) 4382 private void AddToPhysics(bool isPhysical, bool isPhantom, bool applyDynamics)
4039 { 4383 {
4040 PhysicsActor pa; 4384 PhysicsActor pa;
4041 4385
4386 Vector3 velocity = Velocity;
4387 Vector3 rotationalVelocity = AngularVelocity;;
4388
4042 try 4389 try
4043 { 4390 {
4044 pa = ParentGroup.Scene.PhysicsScene.AddPrimShape( 4391 pa = ParentGroup.Scene.PhysicsScene.AddPrimShape(
@@ -4046,8 +4393,10 @@ namespace OpenSim.Region.Framework.Scenes
4046 Shape, 4393 Shape,
4047 AbsolutePosition, 4394 AbsolutePosition,
4048 Scale, 4395 Scale,
4049 RotationOffset, 4396 GetWorldRotation(),
4050 rigidBody, 4397 isPhysical,
4398 isPhantom,
4399 PhysicsShapeType,
4051 m_localId); 4400 m_localId);
4052 } 4401 }
4053 catch (Exception e) 4402 catch (Exception e)
@@ -4056,20 +4405,56 @@ namespace OpenSim.Region.Framework.Scenes
4056 pa = null; 4405 pa = null;
4057 } 4406 }
4058 4407
4059 // FIXME: Ideally we wouldn't set the property here to reduce situations where threads changing physical
4060 // properties can stop on each other. However, DoPhysicsPropertyUpdate() currently relies on PhysActor
4061 // being set.
4062 PhysActor = pa;
4063
4064 // Basic Physics can also return null as well as an exception catch.
4065 if (pa != null) 4408 if (pa != null)
4066 { 4409 {
4067 pa.SOPName = this.Name; // save object into the PhysActor so ODE internals know the joint/body info 4410 pa.SOPName = this.Name; // save object into the PhysActor so ODE internals know the joint/body info
4068 pa.SetMaterial(Material); 4411 pa.SetMaterial(Material);
4069 DoPhysicsPropertyUpdate(rigidBody, true); 4412
4413 pa.Density = Density;
4414 pa.GravModifier = GravityModifier;
4415 pa.Friction = Friction;
4416 pa.Restitution = Restitution;
4417
4418 if (VolumeDetectActive) // change if not the default only
4419 pa.SetVolumeDetect(1);
4420 // we are going to tell rest of code about physics so better have this here
4421 PhysActor = pa;
4422
4423 if (isPhysical)
4424 {
4425 if (ParentGroup.RootPart.KeyframeMotion != null)
4426 ParentGroup.RootPart.KeyframeMotion.Stop();
4427 ParentGroup.RootPart.KeyframeMotion = null;
4428 ParentGroup.Scene.AddPhysicalPrim(1);
4429
4430 pa.OnRequestTerseUpdate += PhysicsRequestingTerseUpdate;
4431 pa.OnOutOfBounds += PhysicsOutOfBounds;
4432
4433 if (ParentID != 0 && ParentID != LocalId)
4434 {
4435 PhysicsActor parentPa = ParentGroup.RootPart.PhysActor;
4436
4437 if (parentPa != null)
4438 {
4439 pa.link(parentPa);
4440 }
4441 }
4442 }
4443
4444 if (applyDynamics)
4445 // do independent of isphysical so parameters get setted (at least some)
4446 {
4447 Velocity = velocity;
4448 AngularVelocity = rotationalVelocity;
4449// pa.Velocity = velocity;
4450 pa.RotationalVelocity = rotationalVelocity;
4451 }
4452
4453 ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(pa);
4070 } 4454 }
4071 4455
4072 return pa; 4456 PhysActor = pa;
4457 ParentGroup.Scene.EventManager.TriggerObjectAddedToPhysicalScene(this);
4073 } 4458 }
4074 4459
4075 /// <summary> 4460 /// <summary>
@@ -4082,7 +4467,9 @@ namespace OpenSim.Region.Framework.Scenes
4082 /// </remarks> 4467 /// </remarks>
4083 public void RemoveFromPhysics() 4468 public void RemoveFromPhysics()
4084 { 4469 {
4085 ParentGroup.Scene.PhysicsScene.RemovePrim(PhysActor); 4470 ParentGroup.Scene.EventManager.TriggerObjectRemovedFromPhysicalScene(this);
4471 if (ParentGroup.Scene.PhysicsScene != null)
4472 ParentGroup.Scene.PhysicsScene.RemovePrim(PhysActor);
4086 PhysActor = null; 4473 PhysActor = null;
4087 } 4474 }
4088 4475
@@ -4255,8 +4642,33 @@ namespace OpenSim.Region.Framework.Scenes
4255 4642
4256 Changed changeFlags = 0; 4643 Changed changeFlags = 0;
4257 4644
4645 Primitive.TextureEntryFace fallbackNewFace = newTex.DefaultTexture;
4646 Primitive.TextureEntryFace fallbackOldFace = oldTex.DefaultTexture;
4647
4648 // On Incoming packets, sometimes newText.DefaultTexture is null. The assumption is that all
4649 // other prim-sides are set, but apparently that's not always the case. Lets assume packet/data corruption at this point.
4650 if (fallbackNewFace == null)
4651 {
4652 fallbackNewFace = new Primitive.TextureEntry(Util.BLANK_TEXTURE_UUID).CreateFace(0);
4653 newTex.DefaultTexture = fallbackNewFace;
4654 }
4655 if (fallbackOldFace == null)
4656 {
4657 fallbackOldFace = new Primitive.TextureEntry(Util.BLANK_TEXTURE_UUID).CreateFace(0);
4658 oldTex.DefaultTexture = fallbackOldFace;
4659 }
4660
4661 // Materials capable viewers can send a ObjectImage packet
4662 // when nothing in TE has changed. MaterialID should be updated
4663 // by the RenderMaterials CAP handler, so updating it here may cause a
4664 // race condtion. Therefore, if no non-materials TE fields have changed,
4665 // we should ignore any changes and not update Shape.TextureEntry
4666
4667 bool otherFieldsChanged = false;
4668
4258 for (int i = 0 ; i < GetNumberOfSides(); i++) 4669 for (int i = 0 ; i < GetNumberOfSides(); i++)
4259 { 4670 {
4671
4260 Primitive.TextureEntryFace newFace = newTex.DefaultTexture; 4672 Primitive.TextureEntryFace newFace = newTex.DefaultTexture;
4261 Primitive.TextureEntryFace oldFace = oldTex.DefaultTexture; 4673 Primitive.TextureEntryFace oldFace = oldTex.DefaultTexture;
4262 4674
@@ -4280,18 +4692,36 @@ namespace OpenSim.Region.Framework.Scenes
4280 // Max change, skip the rest of testing 4692 // Max change, skip the rest of testing
4281 if (changeFlags == (Changed.TEXTURE | Changed.COLOR)) 4693 if (changeFlags == (Changed.TEXTURE | Changed.COLOR))
4282 break; 4694 break;
4695
4696 if (!otherFieldsChanged)
4697 {
4698 if (oldFace.Bump != newFace.Bump) otherFieldsChanged = true;
4699 if (oldFace.Fullbright != newFace.Fullbright) otherFieldsChanged = true;
4700 if (oldFace.Glow != newFace.Glow) otherFieldsChanged = true;
4701 if (oldFace.MediaFlags != newFace.MediaFlags) otherFieldsChanged = true;
4702 if (oldFace.OffsetU != newFace.OffsetU) otherFieldsChanged = true;
4703 if (oldFace.OffsetV != newFace.OffsetV) otherFieldsChanged = true;
4704 if (oldFace.RepeatU != newFace.RepeatU) otherFieldsChanged = true;
4705 if (oldFace.RepeatV != newFace.RepeatV) otherFieldsChanged = true;
4706 if (oldFace.Rotation != newFace.Rotation) otherFieldsChanged = true;
4707 if (oldFace.Shiny != newFace.Shiny) otherFieldsChanged = true;
4708 if (oldFace.TexMapType != newFace.TexMapType) otherFieldsChanged = true;
4709 }
4283 } 4710 }
4284 4711
4285 m_shape.TextureEntry = newTex.GetBytes(); 4712 if (changeFlags != 0 || otherFieldsChanged)
4286 if (changeFlags != 0) 4713 {
4287 TriggerScriptChangedEvent(changeFlags); 4714 m_shape.TextureEntry = newTex.GetBytes();
4288 UpdateFlag = UpdateRequired.FULL; 4715 if (changeFlags != 0)
4289 ParentGroup.HasGroupChanged = true; 4716 TriggerScriptChangedEvent(changeFlags);
4717 UpdateFlag = UpdateRequired.FULL;
4718 ParentGroup.HasGroupChanged = true;
4290 4719
4291 //This is madness.. 4720 //This is madness..
4292 //ParentGroup.ScheduleGroupForFullUpdate(); 4721 //ParentGroup.ScheduleGroupForFullUpdate();
4293 //This is sparta 4722 //This is sparta
4294 ScheduleFullUpdate(); 4723 ScheduleFullUpdate();
4724 }
4295 } 4725 }
4296 4726
4297 public void aggregateScriptEvents() 4727 public void aggregateScriptEvents()
@@ -4331,39 +4761,7 @@ namespace OpenSim.Region.Framework.Scenes
4331 objectflagupdate |= (uint) PrimFlags.AllowInventoryDrop; 4761 objectflagupdate |= (uint) PrimFlags.AllowInventoryDrop;
4332 } 4762 }
4333 4763
4334 PhysicsActor pa = PhysActor; 4764 SubscribeForCollisionEvents();
4335
4336 if (
4337 ((AggregateScriptEvents & scriptEvents.collision) != 0) ||
4338 ((AggregateScriptEvents & scriptEvents.collision_end) != 0) ||
4339 ((AggregateScriptEvents & scriptEvents.collision_start) != 0) ||
4340 ((AggregateScriptEvents & scriptEvents.land_collision_start) != 0) ||
4341 ((AggregateScriptEvents & scriptEvents.land_collision) != 0) ||
4342 ((AggregateScriptEvents & scriptEvents.land_collision_end) != 0) ||
4343 ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.collision) != 0) ||
4344 ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.collision_end) != 0) ||
4345 ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.collision_start) != 0) ||
4346 ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.land_collision_start) != 0) ||
4347 ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.land_collision) != 0) ||
4348 ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.land_collision_end) != 0) ||
4349 (CollisionSound != UUID.Zero)
4350 )
4351 {
4352 // subscribe to physics updates.
4353 if (pa != null)
4354 {
4355 pa.OnCollisionUpdate += PhysicsCollision;
4356 pa.SubscribeEvents(1000);
4357 }
4358 }
4359 else
4360 {
4361 if (pa != null)
4362 {
4363 pa.UnSubscribeEvents();
4364 pa.OnCollisionUpdate -= PhysicsCollision;
4365 }
4366 }
4367 4765
4368 //if ((GetEffectiveObjectFlags() & (uint)PrimFlags.Scripted) != 0) 4766 //if ((GetEffectiveObjectFlags() & (uint)PrimFlags.Scripted) != 0)
4369 //{ 4767 //{
@@ -4449,12 +4847,76 @@ namespace OpenSim.Region.Framework.Scenes
4449 { 4847 {
4450 ParentGroup.AddScriptLPS(count); 4848 ParentGroup.AddScriptLPS(count);
4451 } 4849 }
4850
4851 /// <summary>
4852 /// Sets a prim's owner and permissions when it's rezzed.
4853 /// </summary>
4854 /// <param name="item">The inventory item from which the item was rezzed</param>
4855 /// <param name="userInventory">True: the item is being rezzed from the user's inventory. False: from a prim's inventory.</param>
4856 /// <param name="scene">The scene the prim is being rezzed into</param>
4857 public void ApplyPermissionsOnRez(InventoryItemBase item, bool userInventory, Scene scene)
4858 {
4859 if ((OwnerID != item.Owner) || ((item.CurrentPermissions & SceneObjectGroup.SLAM) != 0) || ((item.Flags & (uint)InventoryItemFlags.ObjectSlamPerm) != 0))
4860 {
4861 if (scene.Permissions.PropagatePermissions())
4862 {
4863 if ((item.Flags & (uint)InventoryItemFlags.ObjectHasMultipleItems) == 0)
4864 {
4865 // Apply the item's permissions to the object
4866 //LogPermissions("Before applying item permissions");
4867 if (userInventory)
4868 {
4869 EveryoneMask = item.EveryOnePermissions;
4870 NextOwnerMask = item.NextPermissions;
4871 }
4872 else
4873 {
4874 if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteEveryone) != 0)
4875 EveryoneMask = item.EveryOnePermissions;
4876 if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteNextOwner) != 0)
4877 NextOwnerMask = item.NextPermissions;
4878 if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteGroup) != 0)
4879 GroupMask = item.GroupPermissions;
4880 }
4881 //LogPermissions("After applying item permissions");
4882 }
4883 }
4884
4885 GroupMask = 0; // DO NOT propagate here
4886 }
4887
4888 if (OwnerID != item.Owner)
4889 {
4890 //LogPermissions("Before ApplyNextOwnerPermissions");
4891
4892 if (scene.Permissions.PropagatePermissions())
4893 ApplyNextOwnerPermissions();
4894
4895 //LogPermissions("After ApplyNextOwnerPermissions");
4896
4897 LastOwnerID = OwnerID;
4898 OwnerID = item.Owner;
4899 Inventory.ChangeInventoryOwner(item.Owner);
4900 }
4901 }
4902
4903 /// <summary>
4904 /// Logs the prim's permissions. Useful when debugging permission problems.
4905 /// </summary>
4906 /// <param name="message"></param>
4907 private void LogPermissions(String message)
4908 {
4909 PermissionsUtil.LogPermissions(Name, message, BaseMask, OwnerMask, NextOwnerMask);
4910 }
4452 4911
4453 public void ApplyNextOwnerPermissions() 4912 public void ApplyNextOwnerPermissions()
4454 { 4913 {
4455 BaseMask &= NextOwnerMask; 4914 // Export needs to be preserved in the base and everyone
4915 // mask, but removed in the owner mask as a next owner
4916 // can never change the export status
4917 BaseMask &= NextOwnerMask | (uint)PermissionMask.Export;
4456 OwnerMask &= NextOwnerMask; 4918 OwnerMask &= NextOwnerMask;
4457 EveryoneMask &= NextOwnerMask; 4919 EveryoneMask &= NextOwnerMask | (uint)PermissionMask.Export;
4458 4920
4459 Inventory.ApplyNextOwnerPermissions(); 4921 Inventory.ApplyNextOwnerPermissions();
4460 } 4922 }
@@ -4463,20 +4925,34 @@ namespace OpenSim.Region.Framework.Scenes
4463 { 4925 {
4464 try 4926 try
4465 { 4927 {
4466 if (APIDTarget != Quaternion.Identity) 4928 if (APIDActive)
4467 { 4929 {
4468 if (m_APIDIterations <= 1) 4930 PhysicsActor pa = ParentGroup.RootPart.PhysActor;
4931 if (pa == null || !pa.IsPhysical || APIDStrength < 0.04)
4469 { 4932 {
4470 UpdateRotation(APIDTarget); 4933 StopLookAt();
4471 APIDTarget = Quaternion.Identity;
4472 return; 4934 return;
4473 } 4935 }
4474 4936
4475 Quaternion rot = Quaternion.Slerp(RotationOffset,APIDTarget,1.0f/(float)m_APIDIterations); 4937 Quaternion currRot = GetWorldRotation();
4476 rot.Normalize(); 4938 currRot.Normalize();
4477 UpdateRotation(rot); 4939
4940 // difference between current orientation and desired orientation
4941 Quaternion dR = currRot / APIDTarget;
4942
4943 // find axis and angle of rotation to rotate to desired orientation
4944 Vector3 axis = Vector3.UnitX;
4945 float angle;
4946 dR.GetAxisAngle(out axis, out angle);
4947 axis = axis * currRot;
4948
4949 // clamp strength to avoid overshoot
4950 float strength = 1.0f / APIDStrength;
4951 if (strength > 1.0) strength = 1.0f;
4478 4952
4479 m_APIDIterations--; 4953 // set angular velocity to rotate to desired orientation
4954 // with velocity proportional to strength and angle
4955 AngularVelocity = axis * angle * strength * (float)Math.PI;
4480 4956
4481 // This ensures that we'll check this object on the next iteration 4957 // This ensures that we'll check this object on the next iteration
4482 ParentGroup.QueueForUpdateCheck(); 4958 ParentGroup.QueueForUpdateCheck();
@@ -4502,19 +4978,19 @@ namespace OpenSim.Region.Framework.Scenes
4502 /// true if the avatar was not already recorded, false otherwise. 4978 /// true if the avatar was not already recorded, false otherwise.
4503 /// </returns> 4979 /// </returns>
4504 /// <param name='avatarId'></param> 4980 /// <param name='avatarId'></param>
4505 protected internal bool AddSittingAvatar(UUID avatarId) 4981 protected internal bool AddSittingAvatar(ScenePresence sp)
4506 { 4982 {
4507 lock (ParentGroup.m_sittingAvatars) 4983 lock (ParentGroup.m_sittingAvatars)
4508 { 4984 {
4509 if (IsSitTargetSet && SitTargetAvatar == UUID.Zero) 4985 if (IsSitTargetSet && SitTargetAvatar == UUID.Zero)
4510 SitTargetAvatar = avatarId; 4986 SitTargetAvatar = sp.UUID;
4511 4987
4512 if (m_sittingAvatars == null) 4988 if (m_sittingAvatars == null)
4513 m_sittingAvatars = new HashSet<UUID>(); 4989 m_sittingAvatars = new HashSet<ScenePresence>();
4514 4990
4515 if (m_sittingAvatars.Add(avatarId)) 4991 if (m_sittingAvatars.Add(sp))
4516 { 4992 {
4517 ParentGroup.m_sittingAvatars.Add(avatarId); 4993 ParentGroup.m_sittingAvatars.Add(sp);
4518 4994
4519 return true; 4995 return true;
4520 } 4996 }
@@ -4531,22 +5007,22 @@ namespace OpenSim.Region.Framework.Scenes
4531 /// true if the avatar was present and removed, false if it was not present. 5007 /// true if the avatar was present and removed, false if it was not present.
4532 /// </returns> 5008 /// </returns>
4533 /// <param name='avatarId'></param> 5009 /// <param name='avatarId'></param>
4534 protected internal bool RemoveSittingAvatar(UUID avatarId) 5010 protected internal bool RemoveSittingAvatar(ScenePresence sp)
4535 { 5011 {
4536 lock (ParentGroup.m_sittingAvatars) 5012 lock (ParentGroup.m_sittingAvatars)
4537 { 5013 {
4538 if (SitTargetAvatar == avatarId) 5014 if (SitTargetAvatar == sp.UUID)
4539 SitTargetAvatar = UUID.Zero; 5015 SitTargetAvatar = UUID.Zero;
4540 5016
4541 if (m_sittingAvatars == null) 5017 if (m_sittingAvatars == null)
4542 return false; 5018 return false;
4543 5019
4544 if (m_sittingAvatars.Remove(avatarId)) 5020 if (m_sittingAvatars.Remove(sp))
4545 { 5021 {
4546 if (m_sittingAvatars.Count == 0) 5022 if (m_sittingAvatars.Count == 0)
4547 m_sittingAvatars = null; 5023 m_sittingAvatars = null;
4548 5024
4549 ParentGroup.m_sittingAvatars.Remove(avatarId); 5025 ParentGroup.m_sittingAvatars.Remove(sp);
4550 5026
4551 return true; 5027 return true;
4552 } 5028 }
@@ -4560,14 +5036,14 @@ namespace OpenSim.Region.Framework.Scenes
4560 /// </summary> 5036 /// </summary>
4561 /// <remarks>This applies to all sitting avatars whether there is a sit target set or not.</remarks> 5037 /// <remarks>This applies to all sitting avatars whether there is a sit target set or not.</remarks>
4562 /// <returns>A hashset of the sitting avatars. Returns null if there are no sitting avatars.</returns> 5038 /// <returns>A hashset of the sitting avatars. Returns null if there are no sitting avatars.</returns>
4563 public HashSet<UUID> GetSittingAvatars() 5039 public HashSet<ScenePresence> GetSittingAvatars()
4564 { 5040 {
4565 lock (ParentGroup.m_sittingAvatars) 5041 lock (ParentGroup.m_sittingAvatars)
4566 { 5042 {
4567 if (m_sittingAvatars == null) 5043 if (m_sittingAvatars == null)
4568 return null; 5044 return null;
4569 else 5045 else
4570 return new HashSet<UUID>(m_sittingAvatars); 5046 return new HashSet<ScenePresence>(m_sittingAvatars);
4571 } 5047 }
4572 } 5048 }
4573 5049
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs
index db723fa..ec39726 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs
@@ -38,6 +38,7 @@ using OpenSim.Framework;
38using OpenSim.Region.Framework.Interfaces; 38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes.Scripting; 39using OpenSim.Region.Framework.Scenes.Scripting;
40using OpenSim.Region.Framework.Scenes.Serialization; 40using OpenSim.Region.Framework.Scenes.Serialization;
41using PermissionMask = OpenSim.Framework.PermissionMask;
41 42
42namespace OpenSim.Region.Framework.Scenes 43namespace OpenSim.Region.Framework.Scenes
43{ 44{
@@ -399,6 +400,10 @@ namespace OpenSim.Region.Framework.Scenes
399 400
400 private UUID RestoreSavedScriptState(UUID loadedID, UUID oldID, UUID newID) 401 private UUID RestoreSavedScriptState(UUID loadedID, UUID oldID, UUID newID)
401 { 402 {
403// m_log.DebugFormat(
404// "[PRIM INVENTORY]: Restoring scripted state for item {0}, oldID {1}, loadedID {2}",
405// newID, oldID, loadedID);
406
402 IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces<IScriptModule>(); 407 IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces<IScriptModule>();
403 if (engines.Length == 0) // No engine at all 408 if (engines.Length == 0) // No engine at all
404 return oldID; 409 return oldID;
@@ -411,7 +416,7 @@ namespace OpenSim.Region.Framework.Scenes
411 XmlDocument doc = new XmlDocument(); 416 XmlDocument doc = new XmlDocument();
412 417
413 doc.LoadXml(m_part.ParentGroup.m_savedScriptState[stateID]); 418 doc.LoadXml(m_part.ParentGroup.m_savedScriptState[stateID]);
414 419
415 ////////// CRUFT WARNING /////////////////////////////////// 420 ////////// CRUFT WARNING ///////////////////////////////////
416 // 421 //
417 // Old objects will have <ScriptState><State> ... 422 // Old objects will have <ScriptState><State> ...
@@ -441,6 +446,8 @@ namespace OpenSim.Region.Framework.Scenes
441 // This created document has only the minimun data 446 // This created document has only the minimun data
442 // necessary for XEngine to parse it successfully 447 // necessary for XEngine to parse it successfully
443 448
449// m_log.DebugFormat("[PRIM INVENTORY]: Adding legacy state {0} in {1}", stateID, newID);
450
444 m_part.ParentGroup.m_savedScriptState[stateID] = newDoc.OuterXml; 451 m_part.ParentGroup.m_savedScriptState[stateID] = newDoc.OuterXml;
445 } 452 }
446 453
@@ -552,7 +559,8 @@ namespace OpenSim.Region.Framework.Scenes
552 /// </param> 559 /// </param>
553 public void StopScriptInstance(TaskInventoryItem item) 560 public void StopScriptInstance(TaskInventoryItem item)
554 { 561 {
555 m_part.ParentGroup.Scene.EventManager.TriggerStopScript(m_part.LocalId, item.ItemID); 562 if (m_part.ParentGroup.Scene != null)
563 m_part.ParentGroup.Scene.EventManager.TriggerStopScript(m_part.LocalId, item.ItemID);
556 564
557 // At the moment, even stopped scripts are counted as active, which is probably wrong. 565 // At the moment, even stopped scripts are counted as active, which is probably wrong.
558// m_part.ParentGroup.AddActiveScriptCount(-1); 566// m_part.ParentGroup.AddActiveScriptCount(-1);
@@ -731,8 +739,8 @@ namespace OpenSim.Region.Framework.Scenes
731 739
732 return items; 740 return items;
733 } 741 }
734 742
735 public SceneObjectGroup GetRezReadySceneObject(TaskInventoryItem item) 743 public bool GetRezReadySceneObjects(TaskInventoryItem item, out List<SceneObjectGroup> objlist, out List<Vector3> veclist)
736 { 744 {
737 AssetBase rezAsset = m_part.ParentGroup.Scene.AssetService.Get(item.AssetID.ToString()); 745 AssetBase rezAsset = m_part.ParentGroup.Scene.AssetService.Get(item.AssetID.ToString());
738 746
@@ -741,66 +749,54 @@ namespace OpenSim.Region.Framework.Scenes
741 m_log.WarnFormat( 749 m_log.WarnFormat(
742 "[PRIM INVENTORY]: Could not find asset {0} for inventory item {1} in {2}", 750 "[PRIM INVENTORY]: Could not find asset {0} for inventory item {1} in {2}",
743 item.AssetID, item.Name, m_part.Name); 751 item.AssetID, item.Name, m_part.Name);
744 return null; 752 objlist = null;
753 veclist = null;
754 return false;
745 } 755 }
746 756
747 string xmlData = Utils.BytesToString(rezAsset.Data); 757 Vector3 bbox;
748 SceneObjectGroup group = SceneObjectSerializer.FromOriginalXmlFormat(xmlData); 758 float offsetHeight;
749
750 group.ResetIDs();
751 759
752 SceneObjectPart rootPart = group.GetPart(group.UUID); 760 m_part.ParentGroup.Scene.GetObjectsToRez(rezAsset.Data, false, out objlist, out veclist, out bbox, out offsetHeight);
753 761
754 // Since renaming the item in the inventory does not affect the name stored 762 for (int i = 0; i < objlist.Count; i++)
755 // in the serialization, transfer the correct name from the inventory to the 763 {
756 // object itself before we rez. 764 SceneObjectGroup group = objlist[i];
757 rootPart.Name = item.Name;
758 rootPart.Description = item.Description;
759 765
760 SceneObjectPart[] partList = group.Parts; 766 group.ResetIDs();
761 767
762 group.SetGroup(m_part.GroupID, null); 768 SceneObjectPart rootPart = group.GetPart(group.UUID);
763 769
764 // TODO: Remove magic number badness 770 // Since renaming the item in the inventory does not affect the name stored
765 if ((rootPart.OwnerID != item.OwnerID) || (item.CurrentPermissions & 16) != 0 || (item.Flags & (uint)InventoryItemFlags.ObjectSlamPerm) != 0) // Magic number 771 // in the serialization, transfer the correct name from the inventory to the
766 { 772 // object itself before we rez.
767 if (m_part.ParentGroup.Scene.Permissions.PropagatePermissions()) 773 // Only do these for the first object if we are rezzing a coalescence.
774 if (i == 0)
768 { 775 {
769 foreach (SceneObjectPart part in partList) 776 rootPart.Name = item.Name;
770 { 777 rootPart.Description = item.Description;
771 if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteEveryone) != 0)
772 part.EveryoneMask = item.EveryonePermissions;
773 if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteNextOwner) != 0)
774 part.NextOwnerMask = item.NextPermissions;
775 if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteGroup) != 0)
776 part.GroupMask = item.GroupPermissions;
777 }
778
779 group.ApplyNextOwnerPermissions();
780 } 778 }
781 }
782 779
783 foreach (SceneObjectPart part in partList) 780 group.SetGroup(m_part.GroupID, null);
784 { 781
785 // TODO: Remove magic number badness 782 foreach (SceneObjectPart part in group.Parts)
786 if ((part.OwnerID != item.OwnerID) || (item.CurrentPermissions & 16) != 0 || (item.Flags & (uint)InventoryItemFlags.ObjectSlamPerm) != 0) // Magic number
787 { 783 {
788 part.LastOwnerID = part.OwnerID; 784 // Convert between InventoryItem classes. You can never have too many similar but slightly different classes :)
789 part.OwnerID = item.OwnerID; 785 InventoryItemBase dest = new InventoryItemBase(item.ItemID, item.OwnerID);
790 part.Inventory.ChangeInventoryOwner(item.OwnerID); 786 dest.BasePermissions = item.BasePermissions;
787 dest.CurrentPermissions = item.CurrentPermissions;
788 dest.EveryOnePermissions = item.EveryonePermissions;
789 dest.GroupPermissions = item.GroupPermissions;
790 dest.NextPermissions = item.NextPermissions;
791 dest.Flags = item.Flags;
792
793 part.ApplyPermissionsOnRez(dest, false, m_part.ParentGroup.Scene);
791 } 794 }
792 795
793 if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteEveryone) != 0) 796 rootPart.TrimPermissions();
794 part.EveryoneMask = item.EveryonePermissions;
795 if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteNextOwner) != 0)
796 part.NextOwnerMask = item.NextPermissions;
797 if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteGroup) != 0)
798 part.GroupMask = item.GroupPermissions;
799 } 797 }
800 798
801 rootPart.TrimPermissions(); 799 return true;
802
803 return group;
804 } 800 }
805 801
806 /// <summary> 802 /// <summary>
@@ -880,8 +876,8 @@ namespace OpenSim.Region.Framework.Scenes
880 int type = m_items[itemID].InvType; 876 int type = m_items[itemID].InvType;
881 if (type == 10) // Script 877 if (type == 10) // Script
882 { 878 {
883 m_part.RemoveScriptEvents(itemID); 879 // route it through here, to handle script cleanup tasks
884 m_part.ParentGroup.Scene.EventManager.TriggerRemoveScript(m_part.LocalId, itemID); 880 RemoveScriptInstance(itemID, false);
885 } 881 }
886 m_items.Remove(itemID); 882 m_items.Remove(itemID);
887 m_inventorySerial++; 883 m_inventorySerial++;
@@ -1119,25 +1115,6 @@ namespace OpenSim.Region.Framework.Scenes
1119 mask &= ~((uint)PermissionMask.Transfer >> 13); 1115 mask &= ~((uint)PermissionMask.Transfer >> 13);
1120 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Modify) == 0) 1116 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Modify) == 0)
1121 mask &= ~((uint)PermissionMask.Modify >> 13); 1117 mask &= ~((uint)PermissionMask.Modify >> 13);
1122
1123 if (item.InvType != (int)InventoryType.Object)
1124 {
1125 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Copy) == 0)
1126 mask &= ~((uint)PermissionMask.Copy >> 13);
1127 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Transfer) == 0)
1128 mask &= ~((uint)PermissionMask.Transfer >> 13);
1129 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Modify) == 0)
1130 mask &= ~((uint)PermissionMask.Modify >> 13);
1131 }
1132 else
1133 {
1134 if ((item.CurrentPermissions & ((uint)PermissionMask.Copy >> 13)) == 0)
1135 mask &= ~((uint)PermissionMask.Copy >> 13);
1136 if ((item.CurrentPermissions & ((uint)PermissionMask.Transfer >> 13)) == 0)
1137 mask &= ~((uint)PermissionMask.Transfer >> 13);
1138 if ((item.CurrentPermissions & ((uint)PermissionMask.Modify >> 13)) == 0)
1139 mask &= ~((uint)PermissionMask.Modify >> 13);
1140 }
1141 1118
1142 if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0) 1119 if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
1143 mask &= ~(uint)PermissionMask.Copy; 1120 mask &= ~(uint)PermissionMask.Copy;
@@ -1161,14 +1138,11 @@ namespace OpenSim.Region.Framework.Scenes
1161// "[SCENE OBJECT PART INVENTORY]: Applying next permissions {0} to {1} in {2} with current {3}, base {4}, everyone {5}", 1138// "[SCENE OBJECT PART INVENTORY]: Applying next permissions {0} to {1} in {2} with current {3}, base {4}, everyone {5}",
1162// item.NextPermissions, item.Name, m_part.Name, item.CurrentPermissions, item.BasePermissions, item.EveryonePermissions); 1139// item.NextPermissions, item.Name, m_part.Name, item.CurrentPermissions, item.BasePermissions, item.EveryonePermissions);
1163 1140
1164 if (item.InvType == (int)InventoryType.Object && (item.CurrentPermissions & 7) != 0) 1141 if (item.InvType == (int)InventoryType.Object)
1165 { 1142 {
1166 if ((item.CurrentPermissions & ((uint)PermissionMask.Copy >> 13)) == 0) 1143 uint perms = item.CurrentPermissions;
1167 item.CurrentPermissions &= ~(uint)PermissionMask.Copy; 1144 PermissionsUtil.ApplyFoldedPermissions(perms, ref perms);
1168 if ((item.CurrentPermissions & ((uint)PermissionMask.Transfer >> 13)) == 0) 1145 item.CurrentPermissions = perms;
1169 item.CurrentPermissions &= ~(uint)PermissionMask.Transfer;
1170 if ((item.CurrentPermissions & ((uint)PermissionMask.Modify >> 13)) == 0)
1171 item.CurrentPermissions &= ~(uint)PermissionMask.Modify;
1172 } 1146 }
1173 1147
1174 item.CurrentPermissions &= item.NextPermissions; 1148 item.CurrentPermissions &= item.NextPermissions;
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index a90872e..1fddd91 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -29,16 +29,19 @@ using System;
29using System.Xml; 29using System.Xml;
30using System.Collections.Generic; 30using System.Collections.Generic;
31using System.Reflection; 31using System.Reflection;
32using System.Threading;
32using System.Timers; 33using System.Timers;
34using Timer = System.Timers.Timer;
33using OpenMetaverse; 35using OpenMetaverse;
34using log4net; 36using log4net;
35using Nini.Config; 37using Nini.Config;
36using OpenSim.Framework; 38using OpenSim.Framework;
37using OpenSim.Framework.Client; 39using OpenSim.Framework.Client;
40using OpenSim.Framework.Monitoring;
38using OpenSim.Region.Framework.Interfaces; 41using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes.Animation; 42using OpenSim.Region.Framework.Scenes.Animation;
40using OpenSim.Region.Framework.Scenes.Types; 43using OpenSim.Region.Framework.Scenes.Types;
41using OpenSim.Region.Physics.Manager; 44using OpenSim.Region.PhysicsModules.SharedBase;
42using GridRegion = OpenSim.Services.Interfaces.GridRegion; 45using GridRegion = OpenSim.Services.Interfaces.GridRegion;
43using OpenSim.Services.Interfaces; 46using OpenSim.Services.Interfaces;
44using TeleportFlags = OpenSim.Framework.Constants.TeleportFlags; 47using TeleportFlags = OpenSim.Framework.Constants.TeleportFlags;
@@ -63,6 +66,7 @@ namespace OpenSim.Region.Framework.Scenes
63 66
64 struct ScriptControllers 67 struct ScriptControllers
65 { 68 {
69 public UUID objectID;
66 public UUID itemID; 70 public UUID itemID;
67 public ScriptControlled ignoreControls; 71 public ScriptControlled ignoreControls;
68 public ScriptControlled eventControls; 72 public ScriptControlled eventControls;
@@ -72,21 +76,51 @@ namespace OpenSim.Region.Framework.Scenes
72 76
73 public class ScenePresence : EntityBase, IScenePresence 77 public class ScenePresence : EntityBase, IScenePresence
74 { 78 {
79 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
80 private static readonly String LogHeader = "[SCENE PRESENCE]";
81
75// ~ScenePresence() 82// ~ScenePresence()
76// { 83// {
77// m_log.DebugFormat("[SCENE PRESENCE]: Destructor called on {0}", Name); 84// m_log.DebugFormat("[SCENE PRESENCE]: Destructor called on {0}", Name);
78// } 85// }
79 86
80 private void TriggerScenePresenceUpdated() 87 public void TriggerScenePresenceUpdated()
81 { 88 {
82 if (m_scene != null) 89 if (m_scene != null)
83 m_scene.EventManager.TriggerScenePresenceUpdated(this); 90 m_scene.EventManager.TriggerScenePresenceUpdated(this);
84 } 91 }
85 92
86 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
87
88 public PresenceType PresenceType { get; private set; } 93 public PresenceType PresenceType { get; private set; }
89 94
95 private ScenePresenceStateMachine m_stateMachine;
96
97 /// <summary>
98 /// The current state of this presence. Governs only the existence lifecycle. See ScenePresenceStateMachine
99 /// for more details.
100 /// </summary>
101 public ScenePresenceState LifecycleState
102 {
103 get
104 {
105 return m_stateMachine.GetState();
106 }
107
108 set
109 {
110 m_stateMachine.SetState(value);
111 }
112 }
113
114 /// <summary>
115 /// This exists to prevent race conditions between two CompleteMovement threads if the simulator is slow and
116 /// the viewer fires these in quick succession.
117 /// </summary>
118 /// <remarks>
119 /// TODO: The child -> agent transition should be folded into LifecycleState and the CompleteMovement
120 /// regulation done there.
121 /// </remarks>
122 private object m_completeMovementLock = new object();
123
90// private static readonly byte[] DEFAULT_TEXTURE = AvatarAppearance.GetDefaultTexture().GetBytes(); 124// private static readonly byte[] DEFAULT_TEXTURE = AvatarAppearance.GetDefaultTexture().GetBytes();
91 private static readonly Array DIR_CONTROL_FLAGS = Enum.GetValues(typeof(Dir_ControlFlags)); 125 private static readonly Array DIR_CONTROL_FLAGS = Enum.GetValues(typeof(Dir_ControlFlags));
92 private static readonly Vector3 HEAD_ADJUSTMENT = new Vector3(0f, 0f, 0.3f); 126 private static readonly Vector3 HEAD_ADJUSTMENT = new Vector3(0f, 0f, 0.3f);
@@ -99,7 +133,7 @@ namespace OpenSim.Region.Framework.Scenes
99 /// rotation, prim cut, prim twist, prim taper, and prim shear. See mantis 133 /// rotation, prim cut, prim twist, prim taper, and prim shear. See mantis
100 /// issue #1716 134 /// issue #1716
101 /// </summary> 135 /// </summary>
102 public static readonly Vector3 SIT_TARGET_ADJUSTMENT = new Vector3(0.0f, 0.0f, 0.418f); 136 public static readonly Vector3 SIT_TARGET_ADJUSTMENT = new Vector3(0.0f, 0.0f, 0.4f);
103 137
104 /// <summary> 138 /// <summary>
105 /// Movement updates for agents in neighboring regions are sent directly to clients. 139 /// Movement updates for agents in neighboring regions are sent directly to clients.
@@ -139,6 +173,10 @@ namespace OpenSim.Region.Framework.Scenes
139 private Vector3 m_lastPosition; 173 private Vector3 m_lastPosition;
140 private Quaternion m_lastRotation; 174 private Quaternion m_lastRotation;
141 private Vector3 m_lastVelocity; 175 private Vector3 m_lastVelocity;
176 private Vector3 m_lastSize = new Vector3(0.45f,0.6f,1.9f);
177
178 private bool m_followCamAuto = false;
179
142 180
143 private Vector3? m_forceToApply; 181 private Vector3? m_forceToApply;
144 private int m_userFlags; 182 private int m_userFlags;
@@ -196,10 +234,15 @@ namespace OpenSim.Region.Framework.Scenes
196 private float m_sitAvatarHeight = 2.0f; 234 private float m_sitAvatarHeight = 2.0f;
197 235
198 private Vector3 m_lastChildAgentUpdatePosition; 236 private Vector3 m_lastChildAgentUpdatePosition;
199 private Vector3 m_lastChildAgentUpdateCamPosition; 237// private Vector3 m_lastChildAgentUpdateCamPosition;
200 238
201 private const int LAND_VELOCITYMAG_MAX = 12; 239 private const int LAND_VELOCITYMAG_MAX = 12;
202 240
241 private const float FLY_ROLL_MAX_RADIANS = 1.1f;
242
243 private const float FLY_ROLL_RADIANS_PER_UPDATE = 0.06f;
244 private const float FLY_ROLL_RESET_RADIANS_PER_UPDATE = 0.02f;
245
203 private float m_health = 100f; 246 private float m_health = 100f;
204 247
205 protected ulong crossingFromRegion; 248 protected ulong crossingFromRegion;
@@ -221,8 +264,6 @@ namespace OpenSim.Region.Framework.Scenes
221 /// </summary> 264 /// </summary>
222 public bool LandAtTarget { get; private set; } 265 public bool LandAtTarget { get; private set; }
223 266
224 private bool m_followCamAuto;
225
226 private int m_movementUpdateCount; 267 private int m_movementUpdateCount;
227 private const int NumMovementsBetweenRayCast = 5; 268 private const int NumMovementsBetweenRayCast = 5;
228 269
@@ -230,6 +271,10 @@ namespace OpenSim.Region.Framework.Scenes
230 //private int m_moveToPositionStateStatus; 271 //private int m_moveToPositionStateStatus;
231 //***************************************************** 272 //*****************************************************
232 273
274 private int m_movementAnimationUpdateCounter = 0;
275
276 public Vector3 PrevSitOffset { get; set; }
277
233 protected AvatarAppearance m_appearance; 278 protected AvatarAppearance m_appearance;
234 279
235 public AvatarAppearance Appearance 280 public AvatarAppearance Appearance
@@ -242,6 +287,8 @@ namespace OpenSim.Region.Framework.Scenes
242 } 287 }
243 } 288 }
244 289
290 public bool SentInitialDataToClient { get; private set; }
291
245 /// <summary> 292 /// <summary>
246 /// Copy of the script states while the agent is in transit. This state may 293 /// Copy of the script states while the agent is in transit. This state may
247 /// need to be placed back in case of transfer fail. 294 /// need to be placed back in case of transfer fail.
@@ -276,9 +323,43 @@ namespace OpenSim.Region.Framework.Scenes
276 /// </summary> 323 /// </summary>
277 private Vector3 posLastSignificantMove; 324 private Vector3 posLastSignificantMove;
278 325
279 // For teleports and crossings callbacks 326 #region For teleports and crossings callbacks
280 string m_callbackURI; 327
281 UUID m_originRegionID; 328 /// <summary>
329 /// In the V1 teleport protocol, the destination simulator sends ReleaseAgent to this address.
330 /// </summary>
331 private string m_callbackURI;
332
333 /// <summary>
334 /// Records the region from which this presence originated, if not from login.
335 /// </summary>
336 /// <remarks>
337 /// Also acts as a signal in the teleport V2 process to release UpdateAgent after a viewer has triggered
338 /// CompleteMovement and made the previous child agent a root agent.
339 /// </remarks>
340 private UUID m_originRegionID;
341
342 /// <summary>
343 /// This object is used as a lock before accessing m_originRegionID to make sure that every thread is seeing
344 /// the very latest value and not using some cached version. Cannot make m_originRegionID itself volatite as
345 /// it is a value type.
346 /// </summary>
347 private object m_originRegionIDAccessLock = new object();
348
349 /// <summary>
350 /// Triggered on entity transfer after to allow CompleteMovement() to proceed after we have received an
351 /// UpdateAgent from the originating region.ddkjjkj
352 /// </summary>
353 private AutoResetEvent m_updateAgentReceivedAfterTransferEvent = new AutoResetEvent(false);
354
355 /// <summary>
356 /// Used by the entity transfer module to signal when the presence should not be closed because a subsequent
357 /// teleport is reusing the connection.
358 /// </summary>
359 /// <remarks>May be refactored or move somewhere else soon.</remarks>
360 public bool DoNotCloseAfterTeleport { get; set; }
361
362 #endregion
282 363
283 /// <value> 364 /// <value>
284 /// Script engines present in the scene 365 /// Script engines present in the scene
@@ -295,15 +376,17 @@ namespace OpenSim.Region.Framework.Scenes
295 /// <summary> 376 /// <summary>
296 /// Record user movement inputs. 377 /// Record user movement inputs.
297 /// </summary> 378 /// </summary>
298 public byte MovementFlag { get; private set; } 379 public uint MovementFlag { get; private set; }
299 380
300 private bool m_updateflag; 381 /// <summary>
382 /// Set this if we need to force a movement update on the next received AgentUpdate from the viewer.
383 /// </summary>
384 private const uint ForceUpdateMovementFlagValue = uint.MaxValue;
301 385
302 public bool Updated 386 /// <summary>
303 { 387 /// Is the agent stop control flag currently active?
304 set { m_updateflag = value; } 388 /// </summary>
305 get { return m_updateflag; } 389 public bool AgentControlStopActive { get; private set; }
306 }
307 390
308 private bool m_invulnerable = true; 391 private bool m_invulnerable = true;
309 392
@@ -344,6 +427,9 @@ namespace OpenSim.Region.Framework.Scenes
344 /// </summary> 427 /// </summary>
345 protected Vector3 m_lastCameraPosition; 428 protected Vector3 m_lastCameraPosition;
346 429
430 private Vector4 m_lastCameraCollisionPlane = new Vector4(0f, 0f, 0f, 1);
431 private bool m_doingCamRayCast = false;
432
347 public Vector3 CameraPosition { get; set; } 433 public Vector3 CameraPosition { get; set; }
348 434
349 public Quaternion CameraRotation 435 public Quaternion CameraRotation
@@ -375,7 +461,19 @@ namespace OpenSim.Region.Framework.Scenes
375 public string Firstname { get; private set; } 461 public string Firstname { get; private set; }
376 public string Lastname { get; private set; } 462 public string Lastname { get; private set; }
377 463
378 public string Grouptitle { get; set; } 464 public string Grouptitle
465 {
466 get { return UseFakeGroupTitle ? "(Loading)" : m_groupTitle; }
467 set { m_groupTitle = value; }
468 }
469 private string m_groupTitle;
470
471 /// <summary>
472 /// When this is 'true', return a dummy group title instead of the real group title. This is
473 /// used as part of a hack to force viewers to update the displayed avatar name.
474 /// </summary>
475 public bool UseFakeGroupTitle { get; set; }
476
379 477
380 // Agent's Draw distance. 478 // Agent's Draw distance.
381 public float DrawDistance { get; set; } 479 public float DrawDistance { get; set; }
@@ -424,7 +522,9 @@ namespace OpenSim.Region.Framework.Scenes
424 get { return (IClientCore)ControllingClient; } 522 get { return (IClientCore)ControllingClient; }
425 } 523 }
426 524
427 public Vector3 ParentPosition { get; set; } 525 public UUID COF { get; set; }
526
527// public Vector3 ParentPosition { get; set; }
428 528
429 /// <summary> 529 /// <summary>
430 /// Position of this avatar relative to the region the avatar is in 530 /// Position of this avatar relative to the region the avatar is in
@@ -437,12 +537,13 @@ namespace OpenSim.Region.Framework.Scenes
437 { 537 {
438 m_pos = PhysicsActor.Position; 538 m_pos = PhysicsActor.Position;
439 539
440 //m_log.DebugFormat( 540// m_log.DebugFormat(
441 // "[SCENE PRESENCE]: Set position {0} for {1} in {2} via getting AbsolutePosition!", 541// "[SCENE PRESENCE]: Set position of {0} in {1} to {2} via getting AbsolutePosition!",
442 // m_pos, Name, Scene.RegionInfo.RegionName); 542// Name, Scene.Name, m_pos);
443 } 543 }
444 else 544 else
445 { 545 {
546// m_log.DebugFormat("[SCENE PRESENCE]: Fetching abs pos where PhysicsActor == null and parent part {0} for {1}", Name, Scene.Name);
446 // Obtain the correct position of a seated avatar. 547 // Obtain the correct position of a seated avatar.
447 // In addition to providing the correct position while 548 // In addition to providing the correct position while
448 // the avatar is seated, this value will also 549 // the avatar is seated, this value will also
@@ -459,13 +560,16 @@ namespace OpenSim.Region.Framework.Scenes
459 SceneObjectPart sitPart = ParentPart; 560 SceneObjectPart sitPart = ParentPart;
460 561
461 if (sitPart != null) 562 if (sitPart != null)
462 return sitPart.AbsolutePosition + (m_pos * sitPart.GetWorldRotation()); 563 return sitPart.ParentGroup.AbsolutePosition + (m_pos * sitPart.GetWorldRotation());
463 } 564 }
464 565
465 return m_pos; 566 return m_pos;
466 } 567 }
467 set 568 set
468 { 569 {
570// m_log.DebugFormat("[SCENE PRESENCE]: Setting position of {0} to {1} in {2}", Name, value, Scene.Name);
571// Util.PrintCallStack();
572
469 if (PhysicsActor != null) 573 if (PhysicsActor != null)
470 { 574 {
471 try 575 try
@@ -480,10 +584,7 @@ namespace OpenSim.Region.Framework.Scenes
480 584
481 // Don't update while sitting. The PhysicsActor above is null whilst sitting. 585 // Don't update while sitting. The PhysicsActor above is null whilst sitting.
482 if (ParentID == 0) 586 if (ParentID == 0)
483 {
484 m_pos = value; 587 m_pos = value;
485 ParentPosition = Vector3.Zero;
486 }
487 588
488 //m_log.DebugFormat( 589 //m_log.DebugFormat(
489 // "[ENTITY BASE]: In {0} set AbsolutePosition of {1} to {2}", 590 // "[ENTITY BASE]: In {0} set AbsolutePosition of {1} to {2}",
@@ -513,8 +614,11 @@ namespace OpenSim.Region.Framework.Scenes
513 } 614 }
514 615
515 /// <summary> 616 /// <summary>
516 /// Current velocity of the avatar. 617 /// Velocity of the avatar with respect to its local reference frame.
517 /// </summary> 618 /// </summary>
619 /// <remarks>
620 /// So when sat on a vehicle this will be 0. To get velocity with respect to the world use GetWorldVelocity()
621 /// </remarks>
518 public override Vector3 Velocity 622 public override Vector3 Velocity
519 { 623 {
520 get 624 get
@@ -527,11 +631,21 @@ namespace OpenSim.Region.Framework.Scenes
527// "[SCENE PRESENCE]: Set velocity {0} for {1} in {2} via getting Velocity!", 631// "[SCENE PRESENCE]: Set velocity {0} for {1} in {2} via getting Velocity!",
528// m_velocity, Name, Scene.RegionInfo.RegionName); 632// m_velocity, Name, Scene.RegionInfo.RegionName);
529 } 633 }
634// else if (ParentPart != null)
635// {
636// return ParentPart.ParentGroup.Velocity;
637// }
530 638
531 return m_velocity; 639 return m_velocity;
532 } 640 }
641
533 set 642 set
534 { 643 {
644// Util.PrintCallStack();
645// m_log.DebugFormat(
646// "[SCENE PRESENCE]: In {0} set velocity of {1} to {2}",
647// Scene.RegionInfo.RegionName, Name, value);
648
535 if (PhysicsActor != null) 649 if (PhysicsActor != null)
536 { 650 {
537 try 651 try
@@ -544,37 +658,86 @@ namespace OpenSim.Region.Framework.Scenes
544 } 658 }
545 } 659 }
546 660
547 m_velocity = value; 661 m_velocity = value;
548
549// m_log.DebugFormat(
550// "[SCENE PRESENCE]: In {0} set velocity of {1} to {2}",
551// Scene.RegionInfo.RegionName, Name, m_velocity);
552 } 662 }
553 } 663 }
664/*
665 public override Vector3 AngularVelocity
666 {
667 get
668 {
669 if (PhysicsActor != null)
670 {
671 m_rotationalvelocity = PhysicsActor.RotationalVelocity;
672
673 // m_log.DebugFormat(
674 // "[SCENE PRESENCE]: Set velocity {0} for {1} in {2} via getting Velocity!",
675 // m_velocity, Name, Scene.RegionInfo.RegionName);
676 }
554 677
678 return m_rotationalvelocity;
679 }
680 }
681*/
555 private Quaternion m_bodyRot = Quaternion.Identity; 682 private Quaternion m_bodyRot = Quaternion.Identity;
556 683
684 /// <summary>
685 /// The rotation of the avatar.
686 /// </summary>
687 /// <remarks>
688 /// If the avatar is not sitting, this is with respect to the world
689 /// If the avatar is sitting, this is a with respect to the part that it's sitting upon (a local rotation).
690 /// If you always want the world rotation, use GetWorldRotation()
691 /// </remarks>
557 public Quaternion Rotation 692 public Quaternion Rotation
558 { 693 {
559 get { return m_bodyRot; } 694 get
695 {
696 return m_bodyRot;
697 }
698
560 set 699 set
561 { 700 {
562 m_bodyRot = value; 701 m_bodyRot = value;
702
563 if (PhysicsActor != null) 703 if (PhysicsActor != null)
564 { 704 {
565 PhysicsActor.Orientation = m_bodyRot; 705 try
706 {
707 PhysicsActor.Orientation = m_bodyRot;
708 }
709 catch (Exception e)
710 {
711 m_log.Error("[SCENE PRESENCE]: Orientation " + e.Message);
712 }
566 } 713 }
567// m_log.DebugFormat("[SCENE PRESENCE]: Body rot for {0} set to {1}", Name, m_bodyRot); 714// m_log.DebugFormat("[SCENE PRESENCE]: Body rot for {0} set to {1}", Name, m_bodyRot);
568 } 715 }
569 } 716 }
570 717
718 // Used for limited viewer 'fake' user rotations.
719 private Vector3 m_AngularVelocity = Vector3.Zero;
720
721 public Vector3 AngularVelocity
722 {
723 get { return m_AngularVelocity; }
724 }
725
571 public bool IsChildAgent { get; set; } 726 public bool IsChildAgent { get; set; }
727 public bool IsLoggingIn { get; set; }
572 728
573 /// <summary> 729 /// <summary>
574 /// If the avatar is sitting, the local ID of the prim that it's sitting on. If not sitting then zero. 730 /// If the avatar is sitting, the local ID of the prim that it's sitting on. If not sitting then zero.
575 /// </summary> 731 /// </summary>
576 public uint ParentID { get; set; } 732 public uint ParentID { get; set; }
577 733
734 public UUID ParentUUID
735 {
736 get { return m_parentUUID; }
737 set { m_parentUUID = value; }
738 }
739 private UUID m_parentUUID = UUID.Zero;
740
578 /// <summary> 741 /// <summary>
579 /// Are we sitting on an object? 742 /// Are we sitting on an object?
580 /// </summary> 743 /// </summary>
@@ -595,6 +758,33 @@ namespace OpenSim.Region.Framework.Scenes
595 set { m_health = value; } 758 set { m_health = value; }
596 } 759 }
597 760
761 /// <summary>
762 /// Get rotation relative to the world.
763 /// </summary>
764 /// <returns></returns>
765 public Quaternion GetWorldRotation()
766 {
767 SceneObjectPart sitPart = ParentPart;
768
769 if (sitPart != null)
770 return sitPart.GetWorldRotation() * Rotation;
771
772 return Rotation;
773 }
774
775 /// <summary>
776 /// Get velocity relative to the world.
777 /// </summary>
778 public Vector3 GetWorldVelocity()
779 {
780 SceneObjectPart sitPart = ParentPart;
781
782 if (sitPart != null)
783 return sitPart.ParentGroup.Velocity;
784
785 return Velocity;
786 }
787
598 public void AdjustKnownSeeds() 788 public void AdjustKnownSeeds()
599 { 789 {
600 Dictionary<ulong, string> seeds; 790 Dictionary<ulong, string> seeds;
@@ -608,9 +798,8 @@ namespace OpenSim.Region.Framework.Scenes
608 foreach (ulong handle in seeds.Keys) 798 foreach (ulong handle in seeds.Keys)
609 { 799 {
610 uint x, y; 800 uint x, y;
611 Utils.LongToUInts(handle, out x, out y); 801 Util.RegionHandleToRegionLoc(handle, out x, out y);
612 x = x / Constants.RegionSize; 802
613 y = y / Constants.RegionSize;
614 if (Util.IsOutsideView(DrawDistance, x, Scene.RegionInfo.RegionLocX, y, Scene.RegionInfo.RegionLocY)) 803 if (Util.IsOutsideView(DrawDistance, x, Scene.RegionInfo.RegionLocX, y, Scene.RegionInfo.RegionLocY))
615 { 804 {
616 old.Add(handle); 805 old.Add(handle);
@@ -632,18 +821,22 @@ namespace OpenSim.Region.Framework.Scenes
632 foreach (KeyValuePair<ulong, string> kvp in KnownRegions) 821 foreach (KeyValuePair<ulong, string> kvp in KnownRegions)
633 { 822 {
634 uint x, y; 823 uint x, y;
635 Utils.LongToUInts(kvp.Key, out x, out y); 824 Util.RegionHandleToRegionLoc(kvp.Key, out x, out y);
636 x = x / Constants.RegionSize;
637 y = y / Constants.RegionSize;
638 m_log.Info(" >> "+x+", "+y+": "+kvp.Value); 825 m_log.Info(" >> "+x+", "+y+": "+kvp.Value);
639 } 826 }
640 } 827 }
641 828
642 private bool m_mouseLook; 829 private bool m_mouseLook;
643 private bool m_leftButtonDown; 830// private bool m_leftButtonDown;
644 831
645 private bool m_inTransit; 832 private bool m_inTransit;
646 833
834 /// <summary>
835 /// This signals whether the presence is in transit between neighbouring regions.
836 /// </summary>
837 /// <remarks>
838 /// It is not set when the presence is teleporting or logging in/out directly to a region.
839 /// </remarks>
647 public bool IsInTransit 840 public bool IsInTransit
648 { 841 {
649 get { return m_inTransit; } 842 get { return m_inTransit; }
@@ -667,6 +860,14 @@ namespace OpenSim.Region.Framework.Scenes
667 set { m_speedModifier = value; } 860 set { m_speedModifier = value; }
668 } 861 }
669 862
863 /// <summary>
864 /// Modifier for agent movement if we get an AGENT_CONTROL_STOP whilst walking or running
865 /// </summary>
866 /// <remarks>
867 /// AGENT_CONTRL_STOP comes about if user holds down space key on viewers.
868 /// </remarks>
869 private float AgentControlStopSlowWhilstMoving = 0.5f;
870
670 private bool m_forceFly; 871 private bool m_forceFly;
671 872
672 public bool ForceFly 873 public bool ForceFly
@@ -685,23 +886,30 @@ namespace OpenSim.Region.Framework.Scenes
685 886
686 public string Viewer 887 public string Viewer
687 { 888 {
688 get { return m_scene.AuthenticateHandler.GetAgentCircuitData(ControllingClient.CircuitCode).Viewer; } 889 get { return Util.GetViewerName(m_scene.AuthenticateHandler.GetAgentCircuitData(ControllingClient.CircuitCode)); }
689 } 890 }
690 891
892 /// <summary>
893 /// Count of how many terse updates we have sent out. It doesn't matter if this overflows.
894 /// </summary>
895 private int m_terseUpdateCount;
896
691 #endregion 897 #endregion
692 898
693 #region Constructor(s) 899 #region Constructor(s)
694 900
695 public ScenePresence( 901 public ScenePresence(
696 IClientAPI client, Scene world, AvatarAppearance appearance, PresenceType type) 902 IClientAPI client, Scene world, AvatarAppearance appearance, PresenceType type)
697 { 903 {
698 AttachmentsSyncLock = new Object(); 904 AttachmentsSyncLock = new Object();
699 AllowMovement = true; 905 AllowMovement = true;
700 IsChildAgent = true; 906 IsChildAgent = true;
907 IsLoggingIn = false;
701 m_sendCoarseLocationsMethod = SendCoarseLocationsDefault; 908 m_sendCoarseLocationsMethod = SendCoarseLocationsDefault;
702 Animator = new ScenePresenceAnimator(this); 909 Animator = new ScenePresenceAnimator(this);
703 PresenceType = type; 910 PresenceType = type;
704 DrawDistance = world.DefaultDrawDistance; 911 // DrawDistance = world.DefaultDrawDistance;
912 DrawDistance = Constants.RegionSize;
705 RegionHandle = world.RegionInfo.RegionHandle; 913 RegionHandle = world.RegionInfo.RegionHandle;
706 ControllingClient = client; 914 ControllingClient = client;
707 Firstname = ControllingClient.FirstName; 915 Firstname = ControllingClient.FirstName;
@@ -739,12 +947,42 @@ namespace OpenSim.Region.Framework.Scenes
739 SetDirectionVectors(); 947 SetDirectionVectors();
740 948
741 Appearance = appearance; 949 Appearance = appearance;
950
951 m_stateMachine = new ScenePresenceStateMachine(this);
952 }
953
954 private void RegionHeartbeatEnd(Scene scene)
955 {
956 if (IsChildAgent)
957 return;
958
959 m_movementAnimationUpdateCounter ++;
960 if (m_movementAnimationUpdateCounter >= 2)
961 {
962 m_movementAnimationUpdateCounter = 0;
963 if (Animator != null)
964 {
965 // If the parentID == 0 we are not sitting
966 // if !SitGournd then we are not sitting on the ground
967 // Fairly straightforward, now here comes the twist
968 // if ParentUUID is NOT UUID.Zero, we are looking to
969 // be sat on an object that isn't there yet. Should
970 // be treated as if sat.
971 if(ParentID == 0 && !SitGround && ParentUUID == UUID.Zero) // skip it if sitting
972 Animator.UpdateMovementAnimations();
973 }
974 else
975 {
976 m_scene.EventManager.OnRegionHeartbeatEnd -= RegionHeartbeatEnd;
977 }
978 }
742 } 979 }
743 980
744 public void RegisterToEvents() 981 public void RegisterToEvents()
745 { 982 {
746 ControllingClient.OnCompleteMovementToRegion += CompleteMovement; 983 ControllingClient.OnCompleteMovementToRegion += CompleteMovement;
747 ControllingClient.OnAgentUpdate += HandleAgentUpdate; 984 ControllingClient.OnAgentUpdate += HandleAgentUpdate;
985 ControllingClient.OnAgentCameraUpdate += HandleAgentCamerasUpdate;
748 ControllingClient.OnAgentRequestSit += HandleAgentRequestSit; 986 ControllingClient.OnAgentRequestSit += HandleAgentRequestSit;
749 ControllingClient.OnAgentSit += HandleAgentSit; 987 ControllingClient.OnAgentSit += HandleAgentSit;
750 ControllingClient.OnSetAlwaysRun += HandleSetAlwaysRun; 988 ControllingClient.OnSetAlwaysRun += HandleSetAlwaysRun;
@@ -772,23 +1010,6 @@ namespace OpenSim.Region.Framework.Scenes
772 Dir_Vectors[10] = new Vector3(0f, 0f, -0.5f); //DOWN_Nudge 1010 Dir_Vectors[10] = new Vector3(0f, 0f, -0.5f); //DOWN_Nudge
773 } 1011 }
774 1012
775 private Vector3[] GetWalkDirectionVectors()
776 {
777 Vector3[] vector = new Vector3[11];
778 vector[0] = new Vector3(CameraUpAxis.Z, 0f, -CameraAtAxis.Z); //FORWARD
779 vector[1] = new Vector3(-CameraUpAxis.Z, 0f, CameraAtAxis.Z); //BACK
780 vector[2] = Vector3.UnitY; //LEFT
781 vector[3] = -Vector3.UnitY; //RIGHT
782 vector[4] = new Vector3(CameraAtAxis.Z, 0f, CameraUpAxis.Z); //UP
783 vector[5] = new Vector3(-CameraAtAxis.Z, 0f, -CameraUpAxis.Z); //DOWN
784 vector[6] = new Vector3(CameraUpAxis.Z, 0f, -CameraAtAxis.Z); //FORWARD_NUDGE
785 vector[7] = new Vector3(-CameraUpAxis.Z, 0f, CameraAtAxis.Z); //BACK_NUDGE
786 vector[8] = Vector3.UnitY; //LEFT_NUDGE
787 vector[9] = -Vector3.UnitY; //RIGHT_NUDGE
788 vector[10] = new Vector3(-CameraAtAxis.Z, 0f, -CameraUpAxis.Z); //DOWN_NUDGE
789 return vector;
790 }
791
792 #endregion 1013 #endregion
793 1014
794 #region Status Methods 1015 #region Status Methods
@@ -796,6 +1017,7 @@ namespace OpenSim.Region.Framework.Scenes
796 /// <summary> 1017 /// <summary>
797 /// Turns a child agent into a root agent. 1018 /// Turns a child agent into a root agent.
798 /// </summary> 1019 /// </summary>
1020 /// <remarks>
799 /// Child agents are logged into neighbouring sims largely to observe changes. Root agents exist when the 1021 /// Child agents are logged into neighbouring sims largely to observe changes. Root agents exist when the
800 /// avatar is actual in the sim. They can perform all actions. 1022 /// avatar is actual in the sim. They can perform all actions.
801 /// This change is made whenever an avatar enters a region, whether by crossing over from a neighbouring sim, 1023 /// This change is made whenever an avatar enters a region, whether by crossing over from a neighbouring sim,
@@ -803,80 +1025,188 @@ namespace OpenSim.Region.Framework.Scenes
803 /// 1025 ///
804 /// This method is on the critical path for transferring an avatar from one region to another. Delay here 1026 /// This method is on the critical path for transferring an avatar from one region to another. Delay here
805 /// delays that crossing. 1027 /// delays that crossing.
806 /// </summary> 1028 /// </remarks>
807 public void MakeRootAgent(Vector3 pos, bool isFlying) 1029 private bool MakeRootAgent(Vector3 pos, bool isFlying)
808 { 1030 {
809 m_log.DebugFormat( 1031 lock (m_completeMovementLock)
810 "[SCENE]: Upgrading child to root agent for {0} in {1}", 1032 {
811 Name, m_scene.RegionInfo.RegionName); 1033 if (!IsChildAgent)
1034 return false;
1035
1036 //m_log.DebugFormat("[SCENE]: known regions in {0}: {1}", Scene.RegionInfo.RegionName, KnownChildRegionHandles.Count);
1037
1038 // m_log.InfoFormat(
1039 // "[SCENE]: Upgrading child to root agent for {0} in {1}",
1040 // Name, m_scene.RegionInfo.RegionName);
1041
1042 if (ParentUUID != UUID.Zero)
1043 {
1044 m_log.DebugFormat("[SCENE PRESENCE]: Sitting avatar back on prim {0}", ParentUUID);
1045 SceneObjectPart part = m_scene.GetSceneObjectPart(ParentUUID);
1046 if (part == null)
1047 {
1048 m_log.ErrorFormat("[SCENE PRESENCE]: Can't find prim {0} to sit on", ParentUUID);
1049 }
1050 else
1051 {
1052 part.AddSittingAvatar(this);
1053 // ParentPosition = part.GetWorldPosition();
1054 ParentID = part.LocalId;
1055 ParentPart = part;
1056 m_pos = PrevSitOffset;
1057 // pos = ParentPosition;
1058 pos = part.GetWorldPosition();
1059 }
1060 ParentUUID = UUID.Zero;
1061
1062 // Animator.TrySetMovementAnimation("SIT");
1063 }
1064 else
1065 {
1066 IsLoggingIn = false;
1067 }
812 1068
813 //m_log.DebugFormat("[SCENE]: known regions in {0}: {1}", Scene.RegionInfo.RegionName, KnownChildRegionHandles.Count); 1069 IsChildAgent = false;
1070 }
814 1071
815 bool wasChild = IsChildAgent; 1072 // Must reset this here so that a teleport to a region next to an existing region does not keep the flag
816 IsChildAgent = false; 1073 // set and prevent the close of the connection on a subsequent re-teleport.
1074 // Should not be needed if we are not trying to tell this region to close
1075// DoNotCloseAfterTeleport = false;
817 1076
818 IGroupsModule gm = m_scene.RequestModuleInterface<IGroupsModule>(); 1077 IGroupsModule gm = m_scene.RequestModuleInterface<IGroupsModule>();
819 if (gm != null) 1078 if (gm != null)
820 Grouptitle = gm.GetGroupTitle(m_uuid); 1079 Grouptitle = gm.GetGroupTitle(m_uuid);
821 1080
1081 AgentCircuitData aCircuit = m_scene.AuthenticateHandler.GetAgentCircuitData(ControllingClient.CircuitCode);
1082 uint teleportFlags = (aCircuit == null) ? 0 : aCircuit.teleportFlags;
1083 if ((teleportFlags & (uint)TeleportFlags.ViaHGLogin) != 0)
1084 {
1085 // The avatar is arriving from another grid. This means that we may have changed the
1086 // avatar's name to or from the special Hypergrid format ("First.Last @grid.example.com").
1087 // Unfortunately, due to a viewer bug, viewers don't always show the new name.
1088 // But we have a trick that can force them to update the name anyway.
1089 ForceViewersUpdateName();
1090 }
1091
822 RegionHandle = m_scene.RegionInfo.RegionHandle; 1092 RegionHandle = m_scene.RegionInfo.RegionHandle;
823 1093
824 m_scene.EventManager.TriggerSetRootAgentScene(m_uuid, m_scene); 1094 m_scene.EventManager.TriggerSetRootAgentScene(m_uuid, m_scene);
825 1095
826 // Moved this from SendInitialData to ensure that Appearance is initialized 1096 UUID groupUUID = ControllingClient.ActiveGroupId;
827 // before the inventory is processed in MakeRootAgent. This fixes a race condition 1097 string groupName = string.Empty;
828 // related to the handling of attachments 1098 ulong groupPowers = 0;
829 //m_scene.GetAvatarAppearance(ControllingClient, out Appearance); 1099
830 if (m_scene.TestBorderCross(pos, Cardinals.E)) 1100 // ----------------------------------
1101 // Previous Agent Difference - AGNI sends an unsolicited AgentDataUpdate upon root agent status
1102 try
831 { 1103 {
832 Border crossedBorder = m_scene.GetCrossedBorder(pos, Cardinals.E); 1104 if (groupUUID != UUID.Zero && gm != null)
833 pos.X = crossedBorder.BorderLine.Z - 1; 1105 {
834 } 1106 GroupRecord record = gm.GetGroupRecord(groupUUID);
1107 if (record != null)
1108 groupName = record.GroupName;
1109
1110 GroupMembershipData groupMembershipData = gm.GetMembershipData(groupUUID, m_uuid);
835 1111
836 if (m_scene.TestBorderCross(pos, Cardinals.N)) 1112 if (groupMembershipData != null)
1113 groupPowers = groupMembershipData.GroupPowers;
1114 }
1115
1116 ControllingClient.SendAgentDataUpdate(
1117 m_uuid, groupUUID, Firstname, Lastname, groupPowers, groupName, Grouptitle);
1118 }
1119 catch (Exception e)
837 { 1120 {
838 Border crossedBorder = m_scene.GetCrossedBorder(pos, Cardinals.N); 1121 m_log.Error("[AGENTUPDATE]: Error ", e);
839 pos.Y = crossedBorder.BorderLine.Z - 1;
840 } 1122 }
1123 // ------------------------------------
841 1124
842 CheckAndAdjustLandingPoint(ref pos); 1125 if (ParentID == 0)
843
844 if (pos.X < 0f || pos.Y < 0f || pos.Z < 0f)
845 { 1126 {
846 m_log.WarnFormat( 1127 // Moved this from SendInitialData to ensure that Appearance is initialized
847 "[SCENE PRESENCE]: MakeRootAgent() was given an illegal position of {0} for avatar {1}, {2}. Clamping", 1128 // before the inventory is processed in MakeRootAgent. This fixes a race condition
848 pos, Name, UUID); 1129 // related to the handling of attachments
1130 //m_scene.GetAvatarAppearance(ControllingClient, out Appearance);
1131
1132 /* RA 20140111: Commented out these TestBorderCross's.
1133 * Not sure why this code is here. It is not checking all the borders
1134 * and 'in region' sanity checking is done in CheckAndAdjustLandingPoint and below.
1135 if (m_scene.TestBorderCross(pos, Cardinals.E))
1136 {
1137 Border crossedBorder = m_scene.GetCrossedBorder(pos, Cardinals.E);
1138 pos.X = crossedBorder.BorderLine.Z - 1;
1139 }
849 1140
850 if (pos.X < 0f) pos.X = 0f; 1141 if (m_scene.TestBorderCross(pos, Cardinals.N))
851 if (pos.Y < 0f) pos.Y = 0f; 1142 {
852 if (pos.Z < 0f) pos.Z = 0f; 1143 Border crossedBorder = m_scene.GetCrossedBorder(pos, Cardinals.N);
853 } 1144 pos.Y = crossedBorder.BorderLine.Z - 1;
1145 }
1146 */
854 1147
855 float localAVHeight = 1.56f; 1148 CheckAndAdjustLandingPoint(ref pos);
856 if (Appearance.AvatarHeight > 0)
857 localAVHeight = Appearance.AvatarHeight;
858 1149
859 float posZLimit = 0; 1150 if (pos.X < 0f || pos.Y < 0f || pos.Z < 0f)
1151 {
1152 m_log.WarnFormat(
1153 "[SCENE PRESENCE]: MakeRootAgent() was given an illegal position of {0} for avatar {1}, {2}. Clamping",
1154 pos, Name, UUID);
860 1155
861 if (pos.X < Constants.RegionSize && pos.Y < Constants.RegionSize) 1156 if (pos.X < 0f) pos.X = 0f;
862 posZLimit = (float)m_scene.Heightmap[(int)pos.X, (int)pos.Y]; 1157 if (pos.Y < 0f) pos.Y = 0f;
863 1158 if (pos.Z < 0f) pos.Z = 0f;
864 float newPosZ = posZLimit + localAVHeight / 2; 1159 }
865 if (posZLimit >= (pos.Z - (localAVHeight / 2)) && !(Single.IsInfinity(newPosZ) || Single.IsNaN(newPosZ)))
866 {
867 pos.Z = newPosZ;
868 }
869 AbsolutePosition = pos;
870 1160
871 AddToPhysicalScene(isFlying); 1161 float localAVHeight = 1.56f;
1162 if (Appearance.AvatarHeight > 0)
1163 localAVHeight = Appearance.AvatarHeight;
872 1164
873 if (ForceFly) 1165 float posZLimit = 0;
874 { 1166
875 Flying = true; 1167 if (pos.X < m_scene.RegionInfo.RegionSizeX && pos.Y < m_scene.RegionInfo.RegionSizeY)
876 } 1168 posZLimit = (float)m_scene.Heightmap[(int)pos.X, (int)pos.Y];
877 else if (FlyDisabled) 1169
878 { 1170 float newPosZ = posZLimit + localAVHeight / 2;
879 Flying = false; 1171 if (posZLimit >= (pos.Z - (localAVHeight / 2)) && !(Single.IsInfinity(newPosZ) || Single.IsNaN(newPosZ)))
1172 {
1173 pos.Z = newPosZ;
1174 }
1175 AbsolutePosition = pos;
1176
1177// m_log.DebugFormat(
1178// "Set pos {0}, vel {1} in {1} to {2} from input position of {3} on MakeRootAgent",
1179// Name, Scene.Name, AbsolutePosition, pos);
1180//
1181 if (m_teleportFlags == TeleportFlags.Default)
1182 {
1183 AddToPhysicalScene(isFlying);
1184//
1185// Console.WriteLine(
1186// "Set velocity of {0} in {1} to {2} from input velocity of {3} on MakeRootAgent",
1187// Name, Scene.Name, PhysicsActor.Velocity, vel);
1188// }
1189 }
1190 else
1191 {
1192 AddToPhysicalScene(isFlying);
1193 }
1194
1195 // XXX: This is to trigger any secondary teleport needed for a megaregion when the user has teleported to a
1196 // location outside the 'root region' (the south-west 256x256 corner). This is the earlist we can do it
1197 // since it requires a physics actor to be present. If it is left any later, then physics appears to reset
1198 // the value to a negative position which does not trigger the border cross.
1199 // This may not be the best location for this.
1200 CheckForBorderCrossing();
1201
1202 if (ForceFly)
1203 {
1204 Flying = true;
1205 }
1206 else if (FlyDisabled)
1207 {
1208 Flying = false;
1209 }
880 } 1210 }
881 1211
882 // Don't send an animation pack here, since on a region crossing this will sometimes cause a flying 1212 // Don't send an animation pack here, since on a region crossing this will sometimes cause a flying
@@ -886,26 +1216,33 @@ namespace OpenSim.Region.Framework.Scenes
886 1216
887 m_scene.SwapRootAgentCount(false); 1217 m_scene.SwapRootAgentCount(false);
888 1218
889 // The initial login scene presence is already root when it gets here 1219 if (Scene.AttachmentsModule != null)
890 // and it has already rezzed the attachments and started their scripts.
891 // We do the following only for non-login agents, because their scripts
892 // haven't started yet.
893 lock (m_attachments)
894 { 1220 {
895 if (wasChild && HasAttachments()) 1221 // The initial login scene presence is already root when it gets here
1222 // and it has already rezzed the attachments and started their scripts.
1223 // We do the following only for non-login agents, because their scripts
1224 // haven't started yet.
1225 if (PresenceType == PresenceType.Npc || IsRealLogin(m_teleportFlags))
896 { 1226 {
897 m_log.DebugFormat( 1227 WorkManager.RunJob(
898 "[SCENE PRESENCE]: Restarting scripts in attachments for {0} in {1}", Name, Scene.Name); 1228 "RezAttachments",
899 1229 o => Scene.AttachmentsModule.RezAttachments(this),
900 // Resume scripts 1230 null,
901 foreach (SceneObjectGroup sog in m_attachments) 1231 string.Format("Rez attachments for {0} in {1}", Name, Scene.Name));
902 { 1232 }
903 sog.RootPart.ParentGroup.CreateScriptInstances(0, false, m_scene.DefaultScriptEngine, GetStateSource()); 1233 else
904 sog.ResumeScripts(); 1234 {
905 } 1235 WorkManager.RunJob(
1236 "StartAttachmentScripts",
1237 o => RestartAttachmentScripts(),
1238 null,
1239 string.Format("Start attachment scripts for {0} in {1}", Name, Scene.Name),
1240 true);
906 } 1241 }
907 } 1242 }
908 1243
1244 SendAvatarDataToAllClients();
1245
909 // send the animations of the other presences to me 1246 // send the animations of the other presences to me
910 m_scene.ForEachRootScenePresence(delegate(ScenePresence presence) 1247 m_scene.ForEachRootScenePresence(delegate(ScenePresence presence)
911 { 1248 {
@@ -916,9 +1253,75 @@ namespace OpenSim.Region.Framework.Scenes
916 // If we don't reset the movement flag here, an avatar that crosses to a neighbouring sim and returns will 1253 // If we don't reset the movement flag here, an avatar that crosses to a neighbouring sim and returns will
917 // stall on the border crossing since the existing child agent will still have the last movement 1254 // stall on the border crossing since the existing child agent will still have the last movement
918 // recorded, which stops the input from being processed. 1255 // recorded, which stops the input from being processed.
919 MovementFlag = 0; 1256 MovementFlag = ForceUpdateMovementFlagValue;
920 1257
921 m_scene.EventManager.TriggerOnMakeRootAgent(this); 1258 m_scene.EventManager.TriggerOnMakeRootAgent(this);
1259
1260 return true;
1261 }
1262
1263 private void RestartAttachmentScripts()
1264 {
1265 // We need to restart scripts here so that they receive the correct changed events (CHANGED_TELEPORT
1266 // and CHANGED_REGION) when the attachments have been rezzed in the new region. This cannot currently
1267 // be done in AttachmentsModule.CopyAttachments(AgentData ad, IScenePresence sp) itself since we are
1268 // not transporting the required data.
1269 //
1270 // We must take a copy of the attachments list here (rather than locking) to avoid a deadlock where a script in one of
1271 // the attachments may start processing an event (which locks ScriptInstance.m_Script) that then calls a method here
1272 // which needs to lock m_attachments. ResumeScripts() needs to take a ScriptInstance.m_Script lock to try to unset the Suspend status.
1273 //
1274 // FIXME: In theory, this deadlock should not arise since scripts should not be processing events until ResumeScripts().
1275 // But XEngine starts all scripts unsuspended. Starting them suspended will not currently work because script rezzing
1276 // is placed in an asynchronous queue in XEngine and so the ResumeScripts() call will almost certainly execute before the
1277 // script is rezzed. This means the ResumeScripts() does absolutely nothing when using XEngine.
1278 List<SceneObjectGroup> attachments = GetAttachments();
1279
1280 m_log.DebugFormat(
1281 "[SCENE PRESENCE]: Restarting scripts in {0} attachments for {1} in {2}", attachments.Count, Name, Scene.Name);
1282
1283 // Resume scripts
1284 foreach (SceneObjectGroup sog in attachments)
1285 {
1286 sog.ScheduleGroupForFullUpdate();
1287 sog.RootPart.ParentGroup.CreateScriptInstances(0, false, m_scene.DefaultScriptEngine, GetStateSource());
1288 sog.ResumeScripts();
1289 }
1290 }
1291
1292 private static bool IsRealLogin(TeleportFlags teleportFlags)
1293 {
1294 return ((teleportFlags & TeleportFlags.ViaLogin) != 0) && ((teleportFlags & TeleportFlags.ViaHGLogin) == 0);
1295 }
1296
1297 /// <summary>
1298 /// Force viewers to show the avatar's current name.
1299 /// </summary>
1300 /// <remarks>
1301 /// The avatar name that is shown above the avatar in the viewers is sent in ObjectUpdate packets,
1302 /// and they get the name from the ScenePresence. Unfortunately, viewers have a bug (as of April 2014)
1303 /// where they ignore changes to the avatar name. However, tey don't ignore changes to the avatar's
1304 /// Group Title. So the following trick makes viewers update the avatar's name by briefly changing
1305 /// the group title (to "(Loading)"), and then restoring it.
1306 /// </remarks>
1307 public void ForceViewersUpdateName()
1308 {
1309 m_log.DebugFormat("[SCENE PRESENCE]: Forcing viewers to update the avatar name for " + Name);
1310
1311 UseFakeGroupTitle = true;
1312 SendAvatarDataToAllClients(false);
1313
1314 Util.FireAndForget(o =>
1315 {
1316 // Viewers only update the avatar name when idle. Therefore, we must wait long
1317 // enough for the viewer to show the fake name that we had set above, and only
1318 // then switch back to the true name. This delay was chosen because it has a high
1319 // chance of succeeding (we don't want to choose a value that's too low).
1320 Thread.Sleep(5000);
1321
1322 UseFakeGroupTitle = false;
1323 SendAvatarDataToAllClients(false);
1324 }, null, "Scenepresence.ForceViewersUpdateName");
922 } 1325 }
923 1326
924 public int GetStateSource() 1327 public int GetStateSource()
@@ -946,12 +1349,21 @@ namespace OpenSim.Region.Framework.Scenes
946 /// </remarks> 1349 /// </remarks>
947 public void MakeChildAgent() 1350 public void MakeChildAgent()
948 { 1351 {
1352 m_scene.EventManager.OnRegionHeartbeatEnd -= RegionHeartbeatEnd;
1353
949 m_log.DebugFormat("[SCENE PRESENCE]: Making {0} a child agent in {1}", Name, Scene.RegionInfo.RegionName); 1354 m_log.DebugFormat("[SCENE PRESENCE]: Making {0} a child agent in {1}", Name, Scene.RegionInfo.RegionName);
950 1355
1356 // Reset the m_originRegionID as it has dual use as a flag to signal that the UpdateAgent() call orignating
1357 // from the source simulator has completed on a V2 teleport.
1358 lock (m_originRegionIDAccessLock)
1359 m_originRegionID = UUID.Zero;
1360
951 // Reset these so that teleporting in and walking out isn't seen 1361 // Reset these so that teleporting in and walking out isn't seen
952 // as teleporting back 1362 // as teleporting back
953 TeleportFlags = TeleportFlags.Default; 1363 TeleportFlags = TeleportFlags.Default;
954 1364
1365 MovementFlag = 0;
1366
955 // It looks like Animator is set to null somewhere, and MakeChild 1367 // It looks like Animator is set to null somewhere, and MakeChild
956 // is called after that. Probably in aborted teleports. 1368 // is called after that. Probably in aborted teleports.
957 if (Animator == null) 1369 if (Animator == null)
@@ -959,6 +1371,7 @@ namespace OpenSim.Region.Framework.Scenes
959 else 1371 else
960 Animator.ResetAnimations(); 1372 Animator.ResetAnimations();
961 1373
1374
962// m_log.DebugFormat( 1375// m_log.DebugFormat(
963// "[SCENE PRESENCE]: Downgrading root agent {0}, {1} to a child agent in {2}", 1376// "[SCENE PRESENCE]: Downgrading root agent {0}, {1} to a child agent in {2}",
964// Name, UUID, m_scene.RegionInfo.RegionName); 1377// Name, UUID, m_scene.RegionInfo.RegionName);
@@ -970,6 +1383,7 @@ namespace OpenSim.Region.Framework.Scenes
970 IsChildAgent = true; 1383 IsChildAgent = true;
971 m_scene.SwapRootAgentCount(true); 1384 m_scene.SwapRootAgentCount(true);
972 RemoveFromPhysicalScene(); 1385 RemoveFromPhysicalScene();
1386 ParentID = 0; // Child agents can't be sitting
973 1387
974 // FIXME: Set RegionHandle to the region handle of the scene this agent is moving into 1388 // FIXME: Set RegionHandle to the region handle of the scene this agent is moving into
975 1389
@@ -984,10 +1398,10 @@ namespace OpenSim.Region.Framework.Scenes
984 if (PhysicsActor != null) 1398 if (PhysicsActor != null)
985 { 1399 {
986// PhysicsActor.OnRequestTerseUpdate -= SendTerseUpdateToAllClients; 1400// PhysicsActor.OnRequestTerseUpdate -= SendTerseUpdateToAllClients;
987 PhysicsActor.OnOutOfBounds -= OutOfBoundsCall;
988 m_scene.PhysicsScene.RemoveAvatar(PhysicsActor);
989 PhysicsActor.UnSubscribeEvents(); 1401 PhysicsActor.UnSubscribeEvents();
1402 PhysicsActor.OnOutOfBounds -= OutOfBoundsCall;
990 PhysicsActor.OnCollisionUpdate -= PhysicsCollisionUpdate; 1403 PhysicsActor.OnCollisionUpdate -= PhysicsCollisionUpdate;
1404 m_scene.PhysicsScene.RemoveAvatar(PhysicsActor);
991 PhysicsActor = null; 1405 PhysicsActor = null;
992 } 1406 }
993// else 1407// else
@@ -1004,7 +1418,7 @@ namespace OpenSim.Region.Framework.Scenes
1004 /// <param name="pos"></param> 1418 /// <param name="pos"></param>
1005 public void Teleport(Vector3 pos) 1419 public void Teleport(Vector3 pos)
1006 { 1420 {
1007 TeleportWithMomentum(pos, null); 1421 TeleportWithMomentum(pos, Vector3.Zero);
1008 } 1422 }
1009 1423
1010 public void TeleportWithMomentum(Vector3 pos, Vector3? v) 1424 public void TeleportWithMomentum(Vector3 pos, Vector3? v)
@@ -1024,14 +1438,141 @@ namespace OpenSim.Region.Framework.Scenes
1024 else 1438 else
1025 PhysicsActor.SetMomentum(vel); 1439 PhysicsActor.SetMomentum(vel);
1026 } 1440 }
1441 }
1027 1442
1028 SendTerseUpdateToAllClients(); 1443 public void avnLocalTeleport(Vector3 newpos, Vector3? newvel, bool rotateToVelXY)
1444 {
1445 CheckLandingPoint(ref newpos);
1446 AbsolutePosition = newpos;
1447
1448 if (newvel.HasValue)
1449 {
1450 if ((Vector3)newvel == Vector3.Zero)
1451 {
1452 if (PhysicsActor != null)
1453 PhysicsActor.SetMomentum(Vector3.Zero);
1454 m_velocity = Vector3.Zero;
1455 }
1456 else
1457 {
1458 if (PhysicsActor != null)
1459 PhysicsActor.SetMomentum((Vector3)newvel);
1460 m_velocity = (Vector3)newvel;
1461
1462 if (rotateToVelXY)
1463 {
1464 Vector3 lookAt = (Vector3)newvel;
1465 lookAt.Z = 0;
1466 lookAt.Normalize();
1467 ControllingClient.SendLocalTeleport(newpos, lookAt, (uint)TeleportFlags.ViaLocation);
1468 return;
1469 }
1470 }
1471 }
1029 } 1472 }
1030 1473
1031 public void StopFlying() 1474 public void StopFlying()
1032 { 1475 {
1033 ControllingClient.StopFlying(this); 1476 Vector3 pos = AbsolutePosition;
1477 if (Appearance.AvatarHeight != 127.0f)
1478 pos += new Vector3(0f, 0f, (Appearance.AvatarHeight / 6f));
1479 else
1480 pos += new Vector3(0f, 0f, (1.56f / 6f));
1481
1482 AbsolutePosition = pos;
1483
1484 // attach a suitable collision plane regardless of the actual situation to force the LLClient to land.
1485 // Collision plane below the avatar's position a 6th of the avatar's height is suitable.
1486 // Mind you, that this method doesn't get called if the avatar's velocity magnitude is greater then a
1487 // certain amount.. because the LLClient wouldn't land in that situation anyway.
1488
1489 // why are we still testing for this really old height value default???
1490 if (Appearance.AvatarHeight != 127.0f)
1491 CollisionPlane = new Vector4(0, 0, 0, pos.Z - Appearance.AvatarHeight / 6f);
1492 else
1493 CollisionPlane = new Vector4(0, 0, 0, pos.Z - (1.56f / 6f));
1494
1495 ControllingClient.SendAgentTerseUpdate(this);
1496 }
1497
1498 /// <summary>
1499 /// Applies a roll accumulator to the avatar's angular velocity for the avatar fly roll effect.
1500 /// </summary>
1501 /// <param name="amount">Postive or negative roll amount in radians</param>
1502 private void ApplyFlyingRoll(float amount, bool PressingUp, bool PressingDown)
1503 {
1504
1505 float rollAmount = Util.Clamp(m_AngularVelocity.Z + amount, -FLY_ROLL_MAX_RADIANS, FLY_ROLL_MAX_RADIANS);
1506 m_AngularVelocity.Z = rollAmount;
1507
1508 // APPLY EXTRA consideration for flying up and flying down during this time.
1509 // if we're turning left
1510 if (amount > 0)
1511 {
1512
1513 // If we're at the max roll and pressing up, we want to swing BACK a bit
1514 // Automatically adds noise
1515 if (PressingUp)
1516 {
1517 if (m_AngularVelocity.Z >= FLY_ROLL_MAX_RADIANS - 0.04f)
1518 m_AngularVelocity.Z -= 0.9f;
1519 }
1520 // If we're at the max roll and pressing down, we want to swing MORE a bit
1521 if (PressingDown)
1522 {
1523 if (m_AngularVelocity.Z >= FLY_ROLL_MAX_RADIANS && m_AngularVelocity.Z < FLY_ROLL_MAX_RADIANS + 0.6f)
1524 m_AngularVelocity.Z += 0.6f;
1525 }
1526 }
1527 else // we're turning right.
1528 {
1529 // If we're at the max roll and pressing up, we want to swing BACK a bit
1530 // Automatically adds noise
1531 if (PressingUp)
1532 {
1533 if (m_AngularVelocity.Z <= (-FLY_ROLL_MAX_RADIANS))
1534 m_AngularVelocity.Z += 0.6f;
1535 }
1536 // If we're at the max roll and pressing down, we want to swing MORE a bit
1537 if (PressingDown)
1538 {
1539 if (m_AngularVelocity.Z >= -FLY_ROLL_MAX_RADIANS - 0.6f)
1540 m_AngularVelocity.Z -= 0.6f;
1541 }
1542 }
1543 }
1544
1545 /// <summary>
1546 /// incrementally sets roll amount to zero
1547 /// </summary>
1548 /// <param name="amount">Positive roll amount in radians</param>
1549 /// <returns></returns>
1550 private float CalculateFlyingRollResetToZero(float amount)
1551 {
1552 const float rollMinRadians = 0f;
1553
1554 if (m_AngularVelocity.Z > 0)
1555 {
1556
1557 float leftOverToMin = m_AngularVelocity.Z - rollMinRadians;
1558 if (amount > leftOverToMin)
1559 return -leftOverToMin;
1560 else
1561 return -amount;
1562
1563 }
1564 else
1565 {
1566
1567 float leftOverToMin = -m_AngularVelocity.Z - rollMinRadians;
1568 if (amount > leftOverToMin)
1569 return leftOverToMin;
1570 else
1571 return amount;
1572 }
1034 } 1573 }
1574
1575
1035 1576
1036 // neighbouring regions we have enabled a child agent in 1577 // neighbouring regions we have enabled a child agent in
1037 // holds the seed cap for the child agent in that region 1578 // holds the seed cap for the child agent in that region
@@ -1118,6 +1659,40 @@ namespace OpenSim.Region.Framework.Scenes
1118 PhysicsActor.Size = new Vector3(0.45f, 0.6f, height); 1659 PhysicsActor.Size = new Vector3(0.45f, 0.6f, height);
1119 } 1660 }
1120 1661
1662 public void SetSize(Vector3 size, float feetoffset)
1663 {
1664 if (PhysicsActor != null && !IsChildAgent)
1665 {
1666 // Eventually there will be a physics call that sets avatar size that includes offset info.
1667 // For the moment, just set the size as passed.
1668 PhysicsActor.Size = size;
1669 // PhysicsActor.setAvatarSize(size, feetoffset);
1670 }
1671 }
1672
1673 private bool WaitForUpdateAgent(IClientAPI client)
1674 {
1675 // Before the source region executes UpdateAgent
1676 // (which triggers Scene.IncomingUpdateChildAgent(AgentData cAgentData) here in the destination,
1677 // m_originRegionID is UUID.Zero; after, it's non-Zero. The CompleteMovement sequence initiated from the
1678 // viewer (in turn triggered by the source region sending it a TeleportFinish event) waits until it's non-zero
1679 m_updateAgentReceivedAfterTransferEvent.WaitOne(10000);
1680
1681 UUID originID = UUID.Zero;
1682
1683 lock (m_originRegionIDAccessLock)
1684 originID = m_originRegionID;
1685
1686 if (originID.Equals(UUID.Zero))
1687 {
1688 // Movement into region will fail
1689 m_log.WarnFormat("[SCENE PRESENCE]: Update agent {0} never arrived in {1}", client.Name, Scene.Name);
1690 return false;
1691 }
1692
1693 return true;
1694 }
1695
1121 /// <summary> 1696 /// <summary>
1122 /// Complete Avatar's movement into the region. 1697 /// Complete Avatar's movement into the region.
1123 /// </summary> 1698 /// </summary>
@@ -1131,74 +1706,131 @@ namespace OpenSim.Region.Framework.Scenes
1131 { 1706 {
1132// DateTime startTime = DateTime.Now; 1707// DateTime startTime = DateTime.Now;
1133 1708
1134 m_log.DebugFormat( 1709 m_log.InfoFormat(
1135 "[SCENE PRESENCE]: Completing movement of {0} into region {1} in position {2}", 1710 "[SCENE PRESENCE]: Completing movement of {0} into region {1} in position {2}",
1136 client.Name, Scene.RegionInfo.RegionName, AbsolutePosition); 1711 client.Name, Scene.Name, AbsolutePosition);
1137 1712
1138 Vector3 look = Velocity; 1713 bool flying = ((m_AgentControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0); // Get this ahead of time because IsInTransit modifies 'm_AgentControlFlags'
1139 1714
1140 if ((look.X == 0) && (look.Y == 0) && (look.Z == 0)) 1715 IsInTransit = true;
1716 try
1141 { 1717 {
1142 look = new Vector3(0.99f, 0.042f, 0); 1718 // Make sure it's not a login agent. We don't want to wait for updates during login
1143 } 1719 if (!(PresenceType == PresenceType.Npc || IsRealLogin(m_teleportFlags)))
1720 {
1721 // Let's wait until UpdateAgent (called by departing region) is done
1722 if (!WaitForUpdateAgent(client))
1723 // The sending region never sent the UpdateAgent data, we have to refuse
1724 return;
1725 }
1144 1726
1145 // Prevent teleporting to an underground location 1727 Vector3 look = Velocity;
1146 // (may crash client otherwise)
1147 //
1148 Vector3 pos = AbsolutePosition;
1149 float ground = m_scene.GetGroundHeight(pos.X, pos.Y);
1150 if (pos.Z < ground + 1.5f)
1151 {
1152 pos.Z = ground + 1.5f;
1153 AbsolutePosition = pos;
1154 }
1155 1728
1156 bool flying = ((m_AgentControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0); 1729 // if ((look.X == 0) && (look.Y == 0) && (look.Z == 0))
1157 MakeRootAgent(AbsolutePosition, flying); 1730 if ((Math.Abs(look.X) < 0.1) && (Math.Abs(look.Y) < 0.1) && (Math.Abs(look.Z) < 0.1))
1158 ControllingClient.MoveAgentIntoRegion(m_scene.RegionInfo, AbsolutePosition, look); 1731 {
1732 look = new Vector3(0.99f, 0.042f, 0);
1733 }
1159 1734
1160// m_log.DebugFormat("[SCENE PRESENCE] Completed movement"); 1735 // Prevent teleporting to an underground location
1736 // (may crash client otherwise)
1737 //
1738 Vector3 pos = AbsolutePosition;
1739 float ground = m_scene.GetGroundHeight(pos.X, pos.Y);
1740 if (pos.Z < ground + 1.5f)
1741 {
1742 pos.Z = ground + 1.5f;
1743 AbsolutePosition = pos;
1744 }
1161 1745
1162 if ((m_callbackURI != null) && !m_callbackURI.Equals("")) 1746 if (!MakeRootAgent(AbsolutePosition, flying))
1163 { 1747 {
1164 // We cannot sleep here since this would hold up the inbound packet processing thread, as 1748 m_log.DebugFormat(
1165 // CompleteMovement() is executed synchronously. However, it might be better to delay the release 1749 "[SCENE PRESENCE]: Aborting CompleteMovement call for {0} in {1} as they are already root",
1166 // here until we know for sure that the agent is active in this region. Sending AgentMovementComplete 1750 Name, Scene.Name);
1167 // is not enough for Imprudence clients - there appears to be a small delay (<200ms, <500ms) until they regard this
1168 // region as the current region, meaning that a close sent before then will fail the teleport.
1169// System.Threading.Thread.Sleep(2000);
1170 1751
1171 m_log.DebugFormat( 1752 return;
1172 "[SCENE PRESENCE]: Releasing {0} {1} with callback to {2}", 1753 }
1173 client.Name, client.AgentId, m_callbackURI);
1174 1754
1175 Scene.SimulationService.ReleaseAgent(m_originRegionID, UUID, m_callbackURI); 1755 // Tell the client that we're totally ready
1176 m_callbackURI = null; 1756 ControllingClient.MoveAgentIntoRegion(m_scene.RegionInfo, AbsolutePosition, look);
1177 }
1178// else
1179// {
1180// m_log.DebugFormat(
1181// "[SCENE PRESENCE]: No callback provided on CompleteMovement of {0} {1} to {2}",
1182// client.Name, client.AgentId, m_scene.RegionInfo.RegionName);
1183// }
1184 1757
1185 ValidateAndSendAppearanceAndAgentData(); 1758 // Child agents send initial data up in LLUDPServer.HandleUseCircuitCode()
1759 if (!SentInitialDataToClient)
1760 SendInitialDataToClient();
1186 1761
1187 // Create child agents in neighbouring regions 1762 // m_log.DebugFormat("[SCENE PRESENCE] Completed movement");
1188 if (openChildAgents && !IsChildAgent) 1763
1189 { 1764 if (!string.IsNullOrEmpty(m_callbackURI))
1190 IEntityTransferModule m_agentTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>(); 1765 {
1191 if (m_agentTransfer != null) 1766 // We cannot sleep here since this would hold up the inbound packet processing thread, as
1192 Util.FireAndForget(delegate { m_agentTransfer.EnableChildAgents(this); }); 1767 // CompleteMovement() is executed synchronously. However, it might be better to delay the release
1768 // here until we know for sure that the agent is active in this region. Sending AgentMovementComplete
1769 // is not enough for Imprudence clients - there appears to be a small delay (<200ms, <500ms) until they regard this
1770 // region as the current region, meaning that a close sent before then will fail the teleport.
1771 // System.Threading.Thread.Sleep(2000);
1772
1773 m_log.DebugFormat(
1774 "[SCENE PRESENCE]: Releasing {0} {1} with callback to {2}",
1775 client.Name, client.AgentId, m_callbackURI);
1776
1777 Scene.SimulationService.ReleaseAgent(m_originRegionID, UUID, m_callbackURI);
1778 m_callbackURI = null;
1779 }
1780 // else
1781 // {
1782 // m_log.DebugFormat(
1783 // "[SCENE PRESENCE]: No callback provided on CompleteMovement of {0} {1} to {2}",
1784 // client.Name, client.AgentId, m_scene.RegionInfo.RegionName);
1785 // }
1786
1787 ValidateAndSendAppearanceAndAgentData();
1193 1788
1194 IFriendsModule friendsModule = m_scene.RequestModuleInterface<IFriendsModule>(); 1789 // Create child agents in neighbouring regions
1195 if (friendsModule != null) 1790 if (openChildAgents && !IsChildAgent)
1196 friendsModule.SendFriendsOnlineIfNeeded(ControllingClient); 1791 {
1792 IEntityTransferModule m_agentTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>();
1793 if (m_agentTransfer != null)
1794 {
1795 // Note: this call can take a while, because it notifies each of the simulator's neighbours.
1796 // It's important that we don't allow the avatar to cross regions meanwhile, as that will
1797 // cause serious errors. We've prevented that from happening by setting IsInTransit=true.
1798 m_agentTransfer.EnableChildAgents(this);
1799 }
1800
1801 IFriendsModule friendsModule = m_scene.RequestModuleInterface<IFriendsModule>();
1802 if (friendsModule != null)
1803 friendsModule.SendFriendsOnlineIfNeeded(ControllingClient);
1804
1805 }
1806
1807 // XXX: If we force an update after activity has completed, then multiple attachments do appear correctly on a destination region
1808 // If we do it a little bit earlier (e.g. when converting the child to a root agent) then this does not work.
1809 // This may be due to viewer code or it may be something we're not doing properly simulator side.
1810 WorkManager.RunJob(
1811 "ScheduleAttachmentsForFullUpdate",
1812 o => ScheduleAttachmentsForFullUpdate(),
1813 null,
1814 string.Format("Schedule attachments for full update for {0} in {1}", Name, Scene.Name),
1815 true);
1816
1817 // m_log.DebugFormat(
1818 // "[SCENE PRESENCE]: Completing movement of {0} into region {1} took {2}ms",
1819 // client.Name, Scene.RegionInfo.RegionName, (DateTime.Now - startTime).Milliseconds);
1197 } 1820 }
1821 finally
1822 {
1823 IsInTransit = false;
1824 }
1825 }
1198 1826
1199// m_log.DebugFormat( 1827 private void ScheduleAttachmentsForFullUpdate()
1200// "[SCENE PRESENCE]: Completing movement of {0} into region {1} took {2}ms", 1828 {
1201// client.Name, Scene.RegionInfo.RegionName, (DateTime.Now - startTime).Milliseconds); 1829 lock (m_attachments)
1830 {
1831 foreach (SceneObjectGroup sog in m_attachments)
1832 sog.ScheduleGroupForFullUpdate();
1833 }
1202 } 1834 }
1203 1835
1204 /// <summary> 1836 /// <summary>
@@ -1209,36 +1841,69 @@ namespace OpenSim.Region.Framework.Scenes
1209 /// <param name="collisionPoint"></param> 1841 /// <param name="collisionPoint"></param>
1210 /// <param name="localid"></param> 1842 /// <param name="localid"></param>
1211 /// <param name="distance"></param> 1843 /// <param name="distance"></param>
1844 ///
1845
1846 private void UpdateCameraCollisionPlane(Vector4 plane)
1847 {
1848 if (m_lastCameraCollisionPlane != plane)
1849 {
1850 m_lastCameraCollisionPlane = plane;
1851 ControllingClient.SendCameraConstraint(plane);
1852 }
1853 }
1854
1212 public void RayCastCameraCallback(bool hitYN, Vector3 collisionPoint, uint localid, float distance, Vector3 pNormal) 1855 public void RayCastCameraCallback(bool hitYN, Vector3 collisionPoint, uint localid, float distance, Vector3 pNormal)
1213 { 1856 {
1214 const float POSITION_TOLERANCE = 0.02f; 1857 const float POSITION_TOLERANCE = 0.02f;
1215 const float VELOCITY_TOLERANCE = 0.02f;
1216 const float ROTATION_TOLERANCE = 0.02f; 1858 const float ROTATION_TOLERANCE = 0.02f;
1217 1859
1218 if (m_followCamAuto) 1860 m_doingCamRayCast = false;
1861 if (hitYN && localid != LocalId)
1219 { 1862 {
1220 if (hitYN) 1863 SceneObjectGroup group = m_scene.GetGroupByPrim(localid);
1864 bool IsPrim = group != null;
1865 if (IsPrim)
1221 { 1866 {
1222 CameraConstraintActive = true; 1867 SceneObjectPart part = group.GetPart(localid);
1223 //m_log.DebugFormat("[RAYCASTRESULT]: {0}, {1}, {2}, {3}", hitYN, collisionPoint, localid, distance); 1868 if (part != null && !part.VolumeDetectActive)
1224 1869 {
1225 Vector3 normal = Vector3.Normalize(new Vector3(0f, 0f, collisionPoint.Z) - collisionPoint); 1870 CameraConstraintActive = true;
1226 ControllingClient.SendCameraConstraint(new Vector4(normal.X, normal.Y, normal.Z, -1 * Vector3.Distance(new Vector3(0,0,collisionPoint.Z),collisionPoint))); 1871 pNormal.X = (float) Math.Round(pNormal.X, 2);
1872 pNormal.Y = (float) Math.Round(pNormal.Y, 2);
1873 pNormal.Z = (float) Math.Round(pNormal.Z, 2);
1874 pNormal.Normalize();
1875 collisionPoint.X = (float) Math.Round(collisionPoint.X, 1);
1876 collisionPoint.Y = (float) Math.Round(collisionPoint.Y, 1);
1877 collisionPoint.Z = (float) Math.Round(collisionPoint.Z, 1);
1878
1879 Vector4 plane = new Vector4(pNormal.X, pNormal.Y, pNormal.Z,
1880 Vector3.Dot(collisionPoint, pNormal));
1881 UpdateCameraCollisionPlane(plane);
1882 }
1227 } 1883 }
1228 else 1884 else
1229 { 1885 {
1230 if (!m_pos.ApproxEquals(m_lastPosition, POSITION_TOLERANCE) || 1886 CameraConstraintActive = true;
1231 !Velocity.ApproxEquals(m_lastVelocity, VELOCITY_TOLERANCE) || 1887 pNormal.X = (float) Math.Round(pNormal.X, 2);
1232 !Rotation.ApproxEquals(m_lastRotation, ROTATION_TOLERANCE)) 1888 pNormal.Y = (float) Math.Round(pNormal.Y, 2);
1233 { 1889 pNormal.Z = (float) Math.Round(pNormal.Z, 2);
1234 if (CameraConstraintActive) 1890 pNormal.Normalize();
1235 { 1891 collisionPoint.X = (float) Math.Round(collisionPoint.X, 1);
1236 ControllingClient.SendCameraConstraint(new Vector4(0f, 0.5f, 0.9f, -3000f)); 1892 collisionPoint.Y = (float) Math.Round(collisionPoint.Y, 1);
1237 CameraConstraintActive = false; 1893 collisionPoint.Z = (float) Math.Round(collisionPoint.Z, 1);
1238 } 1894
1239 } 1895 Vector4 plane = new Vector4(pNormal.X, pNormal.Y, pNormal.Z,
1896 Vector3.Dot(collisionPoint, pNormal));
1897 UpdateCameraCollisionPlane(plane);
1240 } 1898 }
1241 } 1899 }
1900 else if (!m_pos.ApproxEquals(m_lastPosition, POSITION_TOLERANCE) ||
1901 !Rotation.ApproxEquals(m_lastRotation, ROTATION_TOLERANCE))
1902 {
1903 Vector4 plane = new Vector4(0.9f, 0.0f, 0.361f, -9000f); // not right...
1904 UpdateCameraCollisionPlane(plane);
1905 CameraConstraintActive = false;
1906 }
1242 } 1907 }
1243 1908
1244 /// <summary> 1909 /// <summary>
@@ -1248,18 +1913,14 @@ namespace OpenSim.Region.Framework.Scenes
1248 { 1913 {
1249// m_log.DebugFormat( 1914// m_log.DebugFormat(
1250// "[SCENE PRESENCE]: In {0} received agent update from {1}, flags {2}", 1915// "[SCENE PRESENCE]: In {0} received agent update from {1}, flags {2}",
1251// Scene.RegionInfo.RegionName, remoteClient.Name, (AgentManager.ControlFlags)agentData.ControlFlags); 1916// Scene.Name, remoteClient.Name, (AgentManager.ControlFlags)agentData.ControlFlags);
1252 1917
1253 if (IsChildAgent) 1918 if (IsChildAgent)
1254 { 1919 {
1255 // // m_log.Debug("DEBUG: HandleAgentUpdate: child agent"); 1920// m_log.DebugFormat("DEBUG: HandleAgentUpdate: child agent in {0}", Scene.Name);
1256 return; 1921 return;
1257 } 1922 }
1258 1923
1259 ++m_movementUpdateCount;
1260 if (m_movementUpdateCount < 1)
1261 m_movementUpdateCount = 1;
1262
1263 #region Sanity Checking 1924 #region Sanity Checking
1264 1925
1265 // This is irritating. Really. 1926 // This is irritating. Really.
@@ -1290,36 +1951,20 @@ namespace OpenSim.Region.Framework.Scenes
1290 1951
1291 AgentManager.ControlFlags flags = (AgentManager.ControlFlags)agentData.ControlFlags; 1952 AgentManager.ControlFlags flags = (AgentManager.ControlFlags)agentData.ControlFlags;
1292 1953
1293 // Camera location in world. We'll need to raytrace
1294 // from this location from time to time.
1295 CameraPosition = agentData.CameraCenter;
1296 if (Vector3.Distance(m_lastCameraPosition, CameraPosition) >= Scene.RootReprioritizationDistance)
1297 {
1298 ReprioritizeUpdates();
1299 m_lastCameraPosition = CameraPosition;
1300 }
1301
1302 // Use these three vectors to figure out what the agent is looking at
1303 // Convert it to a Matrix and/or Quaternion
1304 CameraAtAxis = agentData.CameraAtAxis;
1305 CameraLeftAxis = agentData.CameraLeftAxis;
1306 CameraUpAxis = agentData.CameraUpAxis;
1307
1308 // The Agent's Draw distance setting 1954 // The Agent's Draw distance setting
1309 // When we get to the point of re-computing neighbors everytime this 1955 // When we get to the point of re-computing neighbors everytime this
1310 // changes, then start using the agent's drawdistance rather than the 1956 // changes, then start using the agent's drawdistance rather than the
1311 // region's draw distance. 1957 // region's draw distance.
1312 // DrawDistance = agentData.Far; 1958 DrawDistance = agentData.Far;
1313 DrawDistance = Scene.DefaultDrawDistance; 1959 // DrawDistance = Scene.DefaultDrawDistance;
1314
1315 // Check if Client has camera in 'follow cam' or 'build' mode.
1316 Vector3 camdif = (Vector3.One * Rotation - Vector3.One * CameraRotation);
1317
1318 m_followCamAuto = ((CameraUpAxis.Z > 0.959f && CameraUpAxis.Z < 0.98f)
1319 && (Math.Abs(camdif.X) < 0.4f && Math.Abs(camdif.Y) < 0.4f)) ? true : false;
1320 1960
1321 m_mouseLook = (flags & AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0; 1961 m_mouseLook = (flags & AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0;
1322 m_leftButtonDown = (flags & AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_DOWN) != 0; 1962
1963 // FIXME: This does not work as intended because the viewer only sends the lbutton down when the button
1964 // is first pressed, not whilst it is held down. If this is required in the future then need to look
1965 // for an AGENT_CONTROL_LBUTTON_UP event and make sure to handle cases where an initial DOWN is not
1966 // received (e.g. on holding LMB down on the avatar in a viewer).
1967// m_leftButtonDown = (flags & AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_DOWN) != 0;
1323 1968
1324 #endregion Inputs 1969 #endregion Inputs
1325 1970
@@ -1337,14 +1982,38 @@ namespace OpenSim.Region.Framework.Scenes
1337 StandUp(); 1982 StandUp();
1338 } 1983 }
1339 1984
1340 //m_log.DebugFormat("[FollowCam]: {0}", m_followCamAuto);
1341 // Raycast from the avatar's head to the camera to see if there's anything blocking the view 1985 // Raycast from the avatar's head to the camera to see if there's anything blocking the view
1342 if ((m_movementUpdateCount % NumMovementsBetweenRayCast) == 0 && m_scene.PhysicsScene.SupportsRayCast()) 1986 // this exclude checks may not be complete
1987
1988 if (m_movementUpdateCount % NumMovementsBetweenRayCast == 0 && m_scene.PhysicsScene.SupportsRayCast())
1343 { 1989 {
1344 if (m_followCamAuto) 1990 if (!m_doingCamRayCast && !m_mouseLook && ParentID == 0)
1345 { 1991 {
1346 Vector3 posAdjusted = m_pos + HEAD_ADJUSTMENT; 1992 Vector3 posAdjusted = AbsolutePosition;
1347 m_scene.PhysicsScene.RaycastWorld(m_pos, Vector3.Normalize(CameraPosition - posAdjusted), Vector3.Distance(CameraPosition, posAdjusted) + 0.3f, RayCastCameraCallback); 1993// posAdjusted.Z += 0.5f * Appearance.AvatarSize.Z - 0.5f;
1994 posAdjusted.Z += 1.0f; // viewer current camera focus point
1995 Vector3 tocam = CameraPosition - posAdjusted;
1996 tocam.X = (float)Math.Round(tocam.X, 1);
1997 tocam.Y = (float)Math.Round(tocam.Y, 1);
1998 tocam.Z = (float)Math.Round(tocam.Z, 1);
1999
2000 float distTocamlen = tocam.Length();
2001 if (distTocamlen > 0.3f)
2002 {
2003 tocam *= (1.0f / distTocamlen);
2004 posAdjusted.X = (float)Math.Round(posAdjusted.X, 1);
2005 posAdjusted.Y = (float)Math.Round(posAdjusted.Y, 1);
2006 posAdjusted.Z = (float)Math.Round(posAdjusted.Z, 1);
2007
2008 m_doingCamRayCast = true;
2009 m_scene.PhysicsScene.RaycastWorld(posAdjusted, tocam, distTocamlen + 1.0f, RayCastCameraCallback);
2010 }
2011 }
2012 else if (CameraConstraintActive && (m_mouseLook || ParentID != 0))
2013 {
2014 Vector4 plane = new Vector4(0.9f, 0.0f, 0.361f, -10000f); // not right...
2015 UpdateCameraCollisionPlane(plane);
2016 CameraConstraintActive = false;
1348 } 2017 }
1349 } 2018 }
1350 2019
@@ -1358,9 +2027,16 @@ namespace OpenSim.Region.Framework.Scenes
1358 // Here's where you get them. 2027 // Here's where you get them.
1359 m_AgentControlFlags = flags; 2028 m_AgentControlFlags = flags;
1360 m_headrotation = agentData.HeadRotation; 2029 m_headrotation = agentData.HeadRotation;
2030 byte oldState = State;
1361 State = agentData.State; 2031 State = agentData.State;
1362 2032
2033 // We need to send this back to the client in order to stop the edit beams
2034 if ((oldState & (uint)AgentState.Editing) != 0 && State == (uint)AgentState.None)
2035 ControllingClient.SendAgentTerseUpdate(this);
2036
1363 PhysicsActor actor = PhysicsActor; 2037 PhysicsActor actor = PhysicsActor;
2038
2039 // This will be the case if the agent is sitting on the groudn or on an object.
1364 if (actor == null) 2040 if (actor == null)
1365 { 2041 {
1366 SendControlsToScripts(flagsForScripts); 2042 SendControlsToScripts(flagsForScripts);
@@ -1369,17 +2045,26 @@ namespace OpenSim.Region.Framework.Scenes
1369 2045
1370 if (AllowMovement && !SitGround) 2046 if (AllowMovement && !SitGround)
1371 { 2047 {
1372 Quaternion bodyRotation = agentData.BodyRotation; 2048// m_log.DebugFormat("[SCENE PRESENCE]: Initial body rotation {0} for {1}", agentData.BodyRotation, Name);
2049
1373 bool update_rotation = false; 2050 bool update_rotation = false;
1374 2051
1375 if (bodyRotation != Rotation) 2052 if (agentData.BodyRotation != Rotation)
1376 { 2053 {
1377 Rotation = bodyRotation; 2054 Rotation = agentData.BodyRotation;
1378 update_rotation = true; 2055 update_rotation = true;
1379 } 2056 }
1380 2057
1381 bool update_movementflag = false; 2058 bool update_movementflag = false;
1382 2059
2060 // If we were just made root agent then we must perform movement updates for the first AgentUpdate that
2061 // we get
2062 if (MovementFlag == ForceUpdateMovementFlagValue)
2063 {
2064 MovementFlag = 0;
2065 update_movementflag = true;
2066 }
2067
1383 if (agentData.UseClientAgentPosition) 2068 if (agentData.UseClientAgentPosition)
1384 { 2069 {
1385 MovingToTarget = (agentData.ClientAgentPosition - AbsolutePosition).Length() > 0.2f; 2070 MovingToTarget = (agentData.ClientAgentPosition - AbsolutePosition).Length() > 0.2f;
@@ -1411,19 +2096,7 @@ namespace OpenSim.Region.Framework.Scenes
1411 { 2096 {
1412 bool bAllowUpdateMoveToPosition = false; 2097 bool bAllowUpdateMoveToPosition = false;
1413 2098
1414 Vector3[] dirVectors;
1415
1416 // use camera up angle when in mouselook and not flying or when holding the left mouse button down and not flying
1417 // this prevents 'jumping' in inappropriate situations.
1418 if (!Flying && (m_mouseLook || m_leftButtonDown))
1419 dirVectors = GetWalkDirectionVectors();
1420 else
1421 dirVectors = Dir_Vectors;
1422
1423 // The fact that MovementFlag is a byte needs to be fixed
1424 // it really should be a uint
1425 // A DIR_CONTROL_FLAG occurs when the user is trying to move in a particular direction. 2099 // A DIR_CONTROL_FLAG occurs when the user is trying to move in a particular direction.
1426 uint nudgehack = 250;
1427 foreach (Dir_ControlFlags DCF in DIR_CONTROL_FLAGS) 2100 foreach (Dir_ControlFlags DCF in DIR_CONTROL_FLAGS)
1428 { 2101 {
1429 if (((uint)flags & (uint)DCF) != 0) 2102 if (((uint)flags & (uint)DCF) != 0)
@@ -1432,7 +2105,9 @@ namespace OpenSim.Region.Framework.Scenes
1432 2105
1433 try 2106 try
1434 { 2107 {
1435 agent_control_v3 += dirVectors[i]; 2108 // Don't slide against ground when crouching if camera is panned around avatar
2109 if (Flying || DCF != Dir_ControlFlags.DIR_CONTROL_FLAG_DOWN)
2110 agent_control_v3 += Dir_Vectors[i];
1436 //m_log.DebugFormat("[Motion]: {0}, {1}",i, dirVectors[i]); 2111 //m_log.DebugFormat("[Motion]: {0}, {1}",i, dirVectors[i]);
1437 } 2112 }
1438 catch (IndexOutOfRangeException) 2113 catch (IndexOutOfRangeException)
@@ -1440,29 +2115,19 @@ namespace OpenSim.Region.Framework.Scenes
1440 // Why did I get this? 2115 // Why did I get this?
1441 } 2116 }
1442 2117
1443 if ((MovementFlag & (byte)(uint)DCF) == 0) 2118 if (((MovementFlag & (uint)DCF) == 0) & !AgentControlStopActive)
1444 { 2119 {
1445 if (DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_BACKWARD_NUDGE ||
1446 DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_LEFT_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_RIGHT_NUDGE)
1447 {
1448 MovementFlag |= (byte)nudgehack;
1449 }
1450
1451 //m_log.DebugFormat("[SCENE PRESENCE]: Updating MovementFlag for {0} with {1}", Name, DCF); 2120 //m_log.DebugFormat("[SCENE PRESENCE]: Updating MovementFlag for {0} with {1}", Name, DCF);
1452 MovementFlag += (byte)(uint)DCF; 2121 MovementFlag += (uint)DCF;
1453 update_movementflag = true; 2122 update_movementflag = true;
1454 } 2123 }
1455 } 2124 }
1456 else 2125 else
1457 { 2126 {
1458 if ((MovementFlag & (byte)(uint)DCF) != 0 || 2127 if ((MovementFlag & (uint)DCF) != 0)
1459 ((DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_BACKWARD_NUDGE ||
1460 DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_LEFT_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_RIGHT_NUDGE)
1461 && ((MovementFlag & (byte)nudgehack) == nudgehack))
1462 ) // This or is for Nudge forward
1463 { 2128 {
1464 //m_log.DebugFormat("[SCENE PRESENCE]: Updating MovementFlag for {0} with lack of {1}", Name, DCF); 2129 //m_log.DebugFormat("[SCENE PRESENCE]: Updating MovementFlag for {0} with lack of {1}", Name, DCF);
1465 MovementFlag -= ((byte)(uint)DCF); 2130 MovementFlag -= (uint)DCF;
1466 update_movementflag = true; 2131 update_movementflag = true;
1467 2132
1468 /* 2133 /*
@@ -1482,6 +2147,13 @@ namespace OpenSim.Region.Framework.Scenes
1482 i++; 2147 i++;
1483 } 2148 }
1484 2149
2150 // Detect AGENT_CONTROL_STOP state changes
2151 if (AgentControlStopActive != ((flags & AgentManager.ControlFlags.AGENT_CONTROL_STOP) != 0))
2152 {
2153 AgentControlStopActive = !AgentControlStopActive;
2154 update_movementflag = true;
2155 }
2156
1485 if (MovingToTarget) 2157 if (MovingToTarget)
1486 { 2158 {
1487 // If the user has pressed a key then we want to cancel any move to target. 2159 // If the user has pressed a key then we want to cancel any move to target.
@@ -1507,30 +2179,79 @@ namespace OpenSim.Region.Framework.Scenes
1507 // Only do this if we're flying 2179 // Only do this if we're flying
1508 if (Flying && !ForceFly) 2180 if (Flying && !ForceFly)
1509 { 2181 {
1510 // Landing detection code 2182 // Need to stop in mid air if user holds down AGENT_CONTROL_STOP
2183 if (AgentControlStopActive)
2184 {
2185 agent_control_v3 = Vector3.Zero;
2186 }
2187 else
2188 {
2189 // Landing detection code
1511 2190
1512 // Are the landing controls requirements filled? 2191 // Are the landing controls requirements filled?
1513 bool controlland = (((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) || 2192 bool controlland = (((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) ||
1514 ((flags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0)); 2193 ((flags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0));
1515 2194
1516 if (Flying && IsColliding && controlland) 2195 //m_log.Debug("[CONTROL]: " +flags);
1517 { 2196 // Applies a satisfying roll effect to the avatar when flying.
1518 // nesting this check because LengthSquared() is expensive and we don't 2197 if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT) != 0 && (flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_POS) != 0)
1519 // want to do it every step when flying. 2198 {
1520 if ((Velocity.LengthSquared() <= LAND_VELOCITYMAG_MAX)) 2199 ApplyFlyingRoll(
1521 StopFlying(); 2200 FLY_ROLL_RADIANS_PER_UPDATE,
2201 (flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) != 0,
2202 (flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0);
2203 }
2204 else if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT) != 0 &&
2205 (flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_NEG) != 0)
2206 {
2207 ApplyFlyingRoll(
2208 -FLY_ROLL_RADIANS_PER_UPDATE,
2209 (flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) != 0,
2210 (flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0);
2211 }
2212 else
2213 {
2214 if (m_AngularVelocity.Z != 0)
2215 m_AngularVelocity.Z += CalculateFlyingRollResetToZero(FLY_ROLL_RESET_RADIANS_PER_UPDATE);
2216 }
2217
2218 if (Flying && IsColliding && controlland)
2219 {
2220 // nesting this check because LengthSquared() is expensive and we don't
2221 // want to do it every step when flying.
2222 if ((Velocity.LengthSquared() <= LAND_VELOCITYMAG_MAX))
2223 StopFlying();
2224 }
1522 } 2225 }
1523 } 2226 }
1524 2227
2228// m_log.DebugFormat("[SCENE PRESENCE]: MovementFlag {0} for {1}", MovementFlag, Name);
2229
1525 // If the agent update does move the avatar, then calculate the force ready for the velocity update, 2230 // If the agent update does move the avatar, then calculate the force ready for the velocity update,
1526 // which occurs later in the main scene loop 2231 // which occurs later in the main scene loop
1527 if (update_movementflag || (update_rotation && DCFlagKeyPressed)) 2232 // We also need to update if the user rotates their avatar whilst it is slow walking/running (if they
2233 // held down AGENT_CONTROL_STOP whilst normal walking/running). However, we do not want to update
2234 // if the user rotated whilst holding down AGENT_CONTROL_STOP when already still (which locks the
2235 // avatar location in place).
2236 if (update_movementflag
2237 || (update_rotation && DCFlagKeyPressed && (!AgentControlStopActive || MovementFlag != 0)))
1528 { 2238 {
1529// m_log.DebugFormat( 2239// if (update_movementflag || !AgentControlStopActive || MovementFlag != 0)
1530// "[SCENE PRESENCE]: In {0} adding velocity of {1} to {2}, umf = {3}, ur = {4}", 2240// {
1531// m_scene.RegionInfo.RegionName, agent_control_v3, Name, update_movementflag, update_rotation); 2241// m_log.DebugFormat(
2242// "[SCENE PRESENCE]: In {0} adding velocity of {1} to {2}, umf = {3}, mf = {4}, ur = {5}",
2243// m_scene.RegionInfo.RegionName, agent_control_v3, Name,
2244// update_movementflag, MovementFlag, update_rotation);
2245
2246 float speedModifier;
1532 2247
1533 AddNewMovement(agent_control_v3); 2248 if (AgentControlStopActive)
2249 speedModifier = AgentControlStopSlowWhilstMoving;
2250 else
2251 speedModifier = 1;
2252
2253 AddNewMovement(agent_control_v3, speedModifier);
2254// }
1534 } 2255 }
1535// else 2256// else
1536// { 2257// {
@@ -1543,15 +2264,86 @@ namespace OpenSim.Region.Framework.Scenes
1543// } 2264// }
1544 2265
1545 if (update_movementflag && ParentID == 0) 2266 if (update_movementflag && ParentID == 0)
2267 {
2268// m_log.DebugFormat("[SCENE PRESENCE]: Updating movement animations for {0}", Name);
1546 Animator.UpdateMovementAnimations(); 2269 Animator.UpdateMovementAnimations();
2270 }
1547 2271
1548 SendControlsToScripts(flagsForScripts); 2272 SendControlsToScripts(flagsForScripts);
1549 } 2273 }
1550 2274
2275 // We need to send this back to the client in order to see the edit beams
2276 if ((State & (uint)AgentState.Editing) != 0)
2277 ControllingClient.SendAgentTerseUpdate(this);
2278
1551 m_scene.EventManager.TriggerOnClientMovement(this); 2279 m_scene.EventManager.TriggerOnClientMovement(this);
1552 TriggerScenePresenceUpdated();
1553 } 2280 }
1554 2281
2282
2283 /// <summary>
2284 /// This is the event handler for client cameras. If a client is moving, or moving the camera, this event is triggering.
2285 /// </summary>
2286 private void HandleAgentCamerasUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData)
2287 {
2288 //m_log.DebugFormat(
2289 // "[SCENE PRESENCE]: In {0} received agent camera update from {1}, flags {2}",
2290 // Scene.RegionInfo.RegionName, remoteClient.Name, (AgentManager.ControlFlags)agentData.ControlFlags);
2291
2292 if (IsChildAgent)
2293 {
2294 // // m_log.Debug("DEBUG: HandleAgentUpdate: child agent");
2295 return;
2296 }
2297
2298 ++m_movementUpdateCount;
2299 if (m_movementUpdateCount < 1)
2300 m_movementUpdateCount = 1;
2301
2302// AgentManager.ControlFlags flags = (AgentManager.ControlFlags)agentData.ControlFlags;
2303
2304 // Camera location in world. We'll need to raytrace
2305 // from this location from time to time.
2306 CameraPosition = agentData.CameraCenter;
2307 if (Vector3.Distance(m_lastCameraPosition, CameraPosition) >= Scene.RootReprioritizationDistance)
2308 {
2309 ReprioritizeUpdates();
2310 m_lastCameraPosition = CameraPosition;
2311 }
2312
2313 // Use these three vectors to figure out what the agent is looking at
2314 // Convert it to a Matrix and/or Quaternion
2315 CameraAtAxis = agentData.CameraAtAxis;
2316 CameraLeftAxis = agentData.CameraLeftAxis;
2317 CameraUpAxis = agentData.CameraUpAxis;
2318
2319 // The Agent's Draw distance setting
2320 // When we get to the point of re-computing neighbors everytime this
2321 // changes, then start using the agent's drawdistance rather than the
2322 // region's draw distance.
2323 DrawDistance = agentData.Far;
2324 // DrawDistance = Scene.DefaultDrawDistance;
2325
2326 // Check if Client has camera in 'follow cam' or 'build' mode.
2327 Vector3 camdif = (Vector3.One * Rotation - Vector3.One * CameraRotation);
2328
2329 m_followCamAuto = ((CameraUpAxis.Z > 0.959f && CameraUpAxis.Z < 0.98f)
2330 && (Math.Abs(camdif.X) < 0.4f && Math.Abs(camdif.Y) < 0.4f)) ? true : false;
2331
2332
2333 //m_log.DebugFormat("[FollowCam]: {0}", m_followCamAuto);
2334 // Raycast from the avatar's head to the camera to see if there's anything blocking the view
2335 if ((m_movementUpdateCount % NumMovementsBetweenRayCast) == 0 && m_scene.PhysicsScene.SupportsRayCast())
2336 {
2337 if (m_followCamAuto)
2338 {
2339 Vector3 posAdjusted = m_pos + HEAD_ADJUSTMENT;
2340 m_scene.PhysicsScene.RaycastWorld(m_pos, Vector3.Normalize(CameraPosition - posAdjusted), Vector3.Distance(CameraPosition, posAdjusted) + 0.3f, RayCastCameraCallback);
2341 }
2342 }
2343
2344 TriggerScenePresenceUpdated();
2345 }
2346
1555 /// <summary> 2347 /// <summary>
1556 /// Calculate an update to move the presence to the set target. 2348 /// Calculate an update to move the presence to the set target.
1557 /// </summary> 2349 /// </summary>
@@ -1706,13 +2498,15 @@ namespace OpenSim.Region.Framework.Scenes
1706 if (regionCombinerModule != null) 2498 if (regionCombinerModule != null)
1707 regionSize = regionCombinerModule.GetSizeOfMegaregion(m_scene.RegionInfo.RegionID); 2499 regionSize = regionCombinerModule.GetSizeOfMegaregion(m_scene.RegionInfo.RegionID);
1708 else 2500 else
1709 regionSize = new Vector2(Constants.RegionSize); 2501 regionSize = new Vector2(m_scene.RegionInfo.RegionSizeX, m_scene.RegionInfo.RegionSizeY);
1710 2502
1711 if (pos.X < 0 || pos.X >= regionSize.X 2503 if (pos.X < 0 || pos.X >= regionSize.X
1712 || pos.Y < 0 || pos.Y >= regionSize.Y 2504 || pos.Y < 0 || pos.Y >= regionSize.Y
1713 || pos.Z < 0) 2505 || pos.Z < 0)
1714 return; 2506 return;
1715 2507
2508 Scene targetScene = m_scene;
2509
1716// Vector3 heightAdjust = new Vector3(0, 0, Appearance.AvatarHeight / 2); 2510// Vector3 heightAdjust = new Vector3(0, 0, Appearance.AvatarHeight / 2);
1717// pos += heightAdjust; 2511// pos += heightAdjust;
1718// 2512//
@@ -1724,15 +2518,23 @@ namespace OpenSim.Region.Framework.Scenes
1724// } 2518// }
1725 2519
1726 // Get terrain height for sub-region in a megaregion if necessary 2520 // Get terrain height for sub-region in a megaregion if necessary
1727 int X = (int)((m_scene.RegionInfo.RegionLocX * Constants.RegionSize) + pos.X);
1728 int Y = (int)((m_scene.RegionInfo.RegionLocY * Constants.RegionSize) + pos.Y);
1729 UUID target_regionID = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, X, Y).RegionID;
1730 Scene targetScene = m_scene;
1731 2521
1732 if (!SceneManager.Instance.TryGetScene(target_regionID, out targetScene)) 2522 //COMMENT: If its only nessesary in a megaregion, why do it on normal region's too?
1733 targetScene = m_scene; 2523
2524 if (regionCombinerModule != null)
2525 {
2526 int x = (int)((m_scene.RegionInfo.WorldLocX) + pos.X);
2527 int y = (int)((m_scene.RegionInfo.WorldLocY) + pos.Y);
2528 GridRegion target_region = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, x, y);
2529
2530 // If X and Y is NaN, target_region will be null
2531 if (target_region == null)
2532 return;
2533
2534 SceneManager.Instance.TryGetScene(target_region.RegionID, out targetScene);
2535 }
1734 2536
1735 float terrainHeight = (float)targetScene.Heightmap[(int)(pos.X % Constants.RegionSize), (int)(pos.Y % Constants.RegionSize)]; 2537 float terrainHeight = (float)targetScene.Heightmap[(int)(pos.X % regionSize.X), (int)(pos.Y % regionSize.Y)];
1736 pos.Z = Math.Max(terrainHeight, pos.Z); 2538 pos.Z = Math.Max(terrainHeight, pos.Z);
1737 2539
1738 // Fudge factor. It appears that if one clicks "go here" on a piece of ground, the go here request is 2540 // Fudge factor. It appears that if one clicks "go here" on a piece of ground, the go here request is
@@ -1741,15 +2543,18 @@ namespace OpenSim.Region.Framework.Scenes
1741 if (pos.Z - terrainHeight < 0.2) 2543 if (pos.Z - terrainHeight < 0.2)
1742 pos.Z = terrainHeight; 2544 pos.Z = terrainHeight;
1743 2545
1744// m_log.DebugFormat(
1745// "[SCENE PRESENCE]: Avatar {0} set move to target {1} (terrain height {2}) in {3}",
1746// Name, pos, terrainHeight, m_scene.RegionInfo.RegionName);
1747
1748 if (noFly) 2546 if (noFly)
1749 Flying = false; 2547 Flying = false;
1750 else if (pos.Z > terrainHeight) 2548 else if (pos.Z > terrainHeight)
1751 Flying = true; 2549 Flying = true;
1752 2550
2551// m_log.DebugFormat(
2552// "[SCENE PRESENCE]: Avatar {0} set move to target {1} (terrain height {2}) in {3}",
2553// Name, pos, terrainHeight, m_scene.RegionInfo.RegionName);
2554
2555 if (noFly)
2556 Flying = false;
2557
1753 LandAtTarget = landAtTarget; 2558 LandAtTarget = landAtTarget;
1754 MovingToTarget = true; 2559 MovingToTarget = true;
1755 MoveToPositionTarget = pos; 2560 MoveToPositionTarget = pos;
@@ -1782,7 +2587,8 @@ namespace OpenSim.Region.Framework.Scenes
1782// m_log.DebugFormat("[SCENE PRESENCE]: Resetting move to target for {0}", Name); 2587// m_log.DebugFormat("[SCENE PRESENCE]: Resetting move to target for {0}", Name);
1783 2588
1784 MovingToTarget = false; 2589 MovingToTarget = false;
1785 MoveToPositionTarget = Vector3.Zero; 2590// MoveToPositionTarget = Vector3.Zero;
2591 m_forceToApply = null; // cancel possible last action
1786 2592
1787 // We need to reset the control flag as the ScenePresenceAnimator uses this to determine the correct 2593 // We need to reset the control flag as the ScenePresenceAnimator uses this to determine the correct
1788 // resting animation (e.g. hover or stand). NPCs don't have a client that will quickly reset this flag. 2594 // resting animation (e.g. hover or stand). NPCs don't have a client that will quickly reset this flag.
@@ -1799,13 +2605,15 @@ namespace OpenSim.Region.Framework.Scenes
1799 { 2605 {
1800// m_log.DebugFormat("[SCENE PRESENCE]: StandUp() for {0}", Name); 2606// m_log.DebugFormat("[SCENE PRESENCE]: StandUp() for {0}", Name);
1801 2607
2608 bool satOnObject = IsSatOnObject;
2609 SceneObjectPart part = ParentPart;
1802 SitGround = false; 2610 SitGround = false;
1803 if (PhysicsActor == null)
1804 AddToPhysicalScene(false);
1805 2611
1806 if (ParentID != 0) 2612 if (satOnObject)
1807 { 2613 {
1808 SceneObjectPart part = ParentPart; 2614 PrevSitOffset = m_pos; // Save sit offset
2615 UnRegisterSeatControls(part.ParentGroup.UUID);
2616
1809 TaskInventoryDictionary taskIDict = part.TaskInventory; 2617 TaskInventoryDictionary taskIDict = part.TaskInventory;
1810 if (taskIDict != null) 2618 if (taskIDict != null)
1811 { 2619 {
@@ -1821,24 +2629,70 @@ namespace OpenSim.Region.Framework.Scenes
1821 } 2629 }
1822 } 2630 }
1823 2631
1824 ParentPosition = part.GetWorldPosition();
1825 ControllingClient.SendClearFollowCamProperties(part.ParentUUID); 2632 ControllingClient.SendClearFollowCamProperties(part.ParentUUID);
1826 2633
1827 m_pos += ParentPosition + new Vector3(0.0f, 0.0f, 2.0f * m_sitAvatarHeight);
1828 ParentPosition = Vector3.Zero;
1829
1830 ParentID = 0; 2634 ParentID = 0;
1831 ParentPart = null; 2635 ParentPart = null;
1832 SendAvatarDataToAllAgents(); 2636
2637 Quaternion standRotation;
2638
2639 if (part.SitTargetAvatar == UUID)
2640 {
2641 standRotation = part.GetWorldRotation();
2642
2643 if (!part.IsRoot)
2644 standRotation = standRotation * part.SitTargetOrientation;
2645// standRotation = part.RotationOffset * part.SitTargetOrientation;
2646// else
2647// standRotation = part.SitTargetOrientation;
2648
2649 }
2650 else
2651 {
2652 standRotation = Rotation;
2653 }
2654
2655 //Vector3 standPos = ParentPosition + new Vector3(0.0f, 0.0f, 2.0f * m_sitAvatarHeight);
2656 //Vector3 standPos = ParentPosition;
2657
2658// Vector3 standPositionAdjustment
2659// = part.SitTargetPosition + new Vector3(0.5f, 0f, m_sitAvatarHeight / 2f);
2660 Vector3 adjustmentForSitPosition = OffsetPosition * part.ParentGroup.GroupRotation - SIT_TARGET_ADJUSTMENT * part.GetWorldRotation();
2661
2662 // XXX: This is based on the physics capsule sizes. Need to find a better way to read this rather than
2663 // hardcoding here.
2664 Vector3 adjustmentForSitPose = new Vector3(0.74f, 0f, 0f) * standRotation;
2665
2666 Vector3 standPos = part.ParentGroup.AbsolutePosition + adjustmentForSitPosition + adjustmentForSitPose;
2667
2668// m_log.DebugFormat(
2669// "[SCENE PRESENCE]: Setting stand to pos {0}, (adjustmentForSitPosition {1}, adjustmentForSitPose {2}) rotation {3} for {4} in {5}",
2670// standPos, adjustmentForSitPosition, adjustmentForSitPose, standRotation, Name, Scene.Name);
2671
2672 Rotation = standRotation;
2673 AbsolutePosition = standPos;
2674 }
2675
2676 // We need to wait until we have calculated proper stand positions before sitting up the physical
2677 // avatar to avoid race conditions.
2678 if (PhysicsActor == null)
2679 AddToPhysicalScene(false);
2680
2681 if (satOnObject)
2682 {
2683 SendAvatarDataToAllClients();
1833 m_requestedSitTargetID = 0; 2684 m_requestedSitTargetID = 0;
1834 2685
1835 part.RemoveSittingAvatar(UUID); 2686 part.RemoveSittingAvatar(this);
1836 2687
1837 if (part != null) 2688 part.ParentGroup.TriggerScriptChangedEvent(Changed.LINK);
1838 part.ParentGroup.TriggerScriptChangedEvent(Changed.LINK);
1839 } 2689 }
1840 2690
2691 else if (PhysicsActor == null)
2692 AddToPhysicalScene(false);
2693
1841 Animator.TrySetMovementAnimation("STAND"); 2694 Animator.TrySetMovementAnimation("STAND");
2695 TriggerScenePresenceUpdated();
1842 } 2696 }
1843 2697
1844 private SceneObjectPart FindNextAvailableSitTarget(UUID targetID) 2698 private SceneObjectPart FindNextAvailableSitTarget(UUID targetID)
@@ -1885,14 +2739,10 @@ namespace OpenSim.Region.Framework.Scenes
1885 if (part == null) 2739 if (part == null)
1886 return; 2740 return;
1887 2741
1888 // TODO: determine position to sit at based on scene geometry; don't trust offset from client
1889 // see http://wiki.secondlife.com/wiki/User:Andrew_Linden/Office_Hours/2007_11_06 for details on how LL does it
1890
1891 if (PhysicsActor != null) 2742 if (PhysicsActor != null)
1892 m_sitAvatarHeight = PhysicsActor.Size.Z; 2743 m_sitAvatarHeight = PhysicsActor.Size.Z * 0.5f;
1893 2744
1894 bool canSit = false; 2745 bool canSit = false;
1895 Vector3 pos = part.AbsolutePosition + offset;
1896 2746
1897 if (part.IsSitTargetSet && part.SitTargetAvatar == UUID.Zero) 2747 if (part.IsSitTargetSet && part.SitTargetAvatar == UUID.Zero)
1898 { 2748 {
@@ -1902,45 +2752,88 @@ namespace OpenSim.Region.Framework.Scenes
1902 2752
1903 offset = part.SitTargetPosition; 2753 offset = part.SitTargetPosition;
1904 sitOrientation = part.SitTargetOrientation; 2754 sitOrientation = part.SitTargetOrientation;
2755
2756 if (!part.IsRoot)
2757 {
2758 // m_log.DebugFormat("Old sit orient {0}", sitOrientation);
2759 sitOrientation = part.RotationOffset * sitOrientation;
2760 // m_log.DebugFormat("New sit orient {0}", sitOrientation);
2761// m_log.DebugFormat("Old sit offset {0}", offset);
2762 offset = offset * part.RotationOffset;
2763// m_log.DebugFormat("New sit offset {0}", offset);
2764 }
2765
1905 canSit = true; 2766 canSit = true;
1906 } 2767 }
1907 else 2768 else
1908 { 2769 {
2770 if (PhysicsSit(part,offset)) // physics engine
2771 return;
2772
2773 Vector3 pos = part.AbsolutePosition + offset;
2774
1909 if (Util.GetDistanceTo(AbsolutePosition, pos) <= 10) 2775 if (Util.GetDistanceTo(AbsolutePosition, pos) <= 10)
1910 { 2776 {
1911// m_log.DebugFormat(
1912// "[SCENE PRESENCE]: Sitting {0} on {1} {2} because sit target is unset and within 10m",
1913// Name, part.Name, part.LocalId);
1914
1915 AbsolutePosition = pos + new Vector3(0.0f, 0.0f, m_sitAvatarHeight); 2777 AbsolutePosition = pos + new Vector3(0.0f, 0.0f, m_sitAvatarHeight);
1916 canSit = true; 2778 canSit = true;
1917 } 2779 }
1918// else
1919// {
1920// m_log.DebugFormat(
1921// "[SCENE PRESENCE]: Ignoring sit request of {0} on {1} {2} because sit target is unset and outside 10m",
1922// Name, part.Name, part.LocalId);
1923// }
1924 } 2780 }
1925 2781
1926 if (canSit) 2782 if (canSit)
1927 { 2783 {
2784
1928 if (PhysicsActor != null) 2785 if (PhysicsActor != null)
1929 { 2786 {
1930 // We can remove the physicsActor until they stand up. 2787 // We can remove the physicsActor until they stand up.
1931 RemoveFromPhysicalScene(); 2788 RemoveFromPhysicalScene();
1932 } 2789 }
1933 2790
1934 part.AddSittingAvatar(UUID); 2791 if (MovingToTarget)
2792 ResetMoveToTarget();
2793
2794 Velocity = Vector3.Zero;
2795
2796 part.AddSittingAvatar(this);
1935 2797
1936 cameraAtOffset = part.GetCameraAtOffset(); 2798 cameraAtOffset = part.GetCameraAtOffset();
2799
2800 if (!part.IsRoot && cameraAtOffset == Vector3.Zero)
2801 cameraAtOffset = part.ParentGroup.RootPart.GetCameraAtOffset();
2802
2803 bool cameraEyeOffsetFromRootForChild = false;
1937 cameraEyeOffset = part.GetCameraEyeOffset(); 2804 cameraEyeOffset = part.GetCameraEyeOffset();
2805
2806 if (!part.IsRoot && cameraEyeOffset == Vector3.Zero)
2807 {
2808 cameraEyeOffset = part.ParentGroup.RootPart.GetCameraEyeOffset();
2809 cameraEyeOffsetFromRootForChild = true;
2810 }
2811
2812 if ((cameraEyeOffset != Vector3.Zero && !cameraEyeOffsetFromRootForChild) || cameraAtOffset != Vector3.Zero)
2813 {
2814 if (!part.IsRoot)
2815 {
2816 cameraEyeOffset = cameraEyeOffset * part.RotationOffset;
2817 cameraAtOffset += part.OffsetPosition;
2818 }
2819
2820 cameraEyeOffset += part.OffsetPosition;
2821 }
2822
2823// m_log.DebugFormat(
2824// "[SCENE PRESENCE]: Using cameraAtOffset {0}, cameraEyeOffset {1} for sit on {2} by {3} in {4}",
2825// cameraAtOffset, cameraEyeOffset, part.Name, Name, Scene.Name);
2826
1938 forceMouselook = part.GetForceMouselook(); 2827 forceMouselook = part.GetForceMouselook();
1939 2828
2829 // An viewer expects to specify sit positions as offsets to the root prim, even if a child prim is
2830 // being sat upon.
2831 offset += part.OffsetPosition;
2832
1940 ControllingClient.SendSitResponse( 2833 ControllingClient.SendSitResponse(
1941 targetID, offset, sitOrientation, false, cameraAtOffset, cameraEyeOffset, forceMouselook); 2834 part.ParentGroup.UUID, offset, sitOrientation, false, cameraAtOffset, cameraEyeOffset, forceMouselook);
1942 2835
1943 m_requestedSitTargetUUID = targetID; 2836 m_requestedSitTargetUUID = part.UUID;
1944 2837
1945 HandleAgentSit(ControllingClient, UUID); 2838 HandleAgentSit(ControllingClient, UUID);
1946 2839
@@ -1952,6 +2845,9 @@ namespace OpenSim.Region.Framework.Scenes
1952 2845
1953 public void HandleAgentRequestSit(IClientAPI remoteClient, UUID agentID, UUID targetID, Vector3 offset) 2846 public void HandleAgentRequestSit(IClientAPI remoteClient, UUID agentID, UUID targetID, Vector3 offset)
1954 { 2847 {
2848 if (IsChildAgent)
2849 return;
2850
1955 if (ParentID != 0) 2851 if (ParentID != 0)
1956 { 2852 {
1957 if (ParentPart.UUID == targetID) 2853 if (ParentPart.UUID == targetID)
@@ -1965,16 +2861,8 @@ namespace OpenSim.Region.Framework.Scenes
1965 if (part != null) 2861 if (part != null)
1966 { 2862 {
1967 m_requestedSitTargetID = part.LocalId; 2863 m_requestedSitTargetID = part.LocalId;
1968 m_requestedSitTargetUUID = targetID; 2864 m_requestedSitTargetUUID = part.UUID;
1969
1970// m_log.DebugFormat("[SIT]: Client requested Sit Position: {0}", offset);
1971 2865
1972 if (m_scene.PhysicsScene.SupportsRayCast())
1973 {
1974 //m_scene.PhysicsScene.RaycastWorld(Vector3.Zero,Vector3.Zero, 0.01f,new RaycastCallback());
1975 //SitRayCastAvatarPosition(part);
1976 //return;
1977 }
1978 } 2866 }
1979 else 2867 else
1980 { 2868 {
@@ -1984,200 +2872,119 @@ namespace OpenSim.Region.Framework.Scenes
1984 SendSitResponse(targetID, offset, Quaternion.Identity); 2872 SendSitResponse(targetID, offset, Quaternion.Identity);
1985 } 2873 }
1986 2874
1987 /* 2875 // returns false if does not suport so older sit can be tried
1988 public void SitRayCastAvatarPosition(SceneObjectPart part) 2876 public bool PhysicsSit(SceneObjectPart part, Vector3 offset)
1989 {
1990 Vector3 EndRayCastPosition = part.AbsolutePosition + m_requestedSitOffset;
1991 Vector3 StartRayCastPosition = AbsolutePosition;
1992 Vector3 direction = Vector3.Normalize(EndRayCastPosition - StartRayCastPosition);
1993 float distance = Vector3.Distance(EndRayCastPosition, StartRayCastPosition);
1994 m_scene.PhysicsScene.RaycastWorld(StartRayCastPosition, direction, distance, SitRayCastAvatarPositionResponse);
1995 }
1996
1997 public void SitRayCastAvatarPositionResponse(bool hitYN, Vector3 collisionPoint, uint localid, float pdistance, Vector3 normal)
1998 { 2877 {
1999 SceneObjectPart part = FindNextAvailableSitTarget(m_requestedSitTargetUUID); 2878// TODO: Pull in these bits
2000 if (part != null) 2879 return false;
2001 { 2880/*
2002 if (hitYN) 2881 if (part == null || part.ParentGroup.IsAttachment)
2003 {
2004 if (collisionPoint.ApproxEquals(m_requestedSitOffset + part.AbsolutePosition, 0.2f))
2005 {
2006 SitRaycastFindEdge(collisionPoint, normal);
2007 m_log.DebugFormat("[SIT]: Raycast Avatar Position succeeded at point: {0}, normal:{1}", collisionPoint, normal);
2008 }
2009 else
2010 {
2011 SitRayCastAvatarPositionCameraZ(part);
2012 }
2013 }
2014 else
2015 {
2016 SitRayCastAvatarPositionCameraZ(part);
2017 }
2018 }
2019 else
2020 { 2882 {
2021 ControllingClient.SendAlertMessage("Sit position no longer exists"); 2883 return true;
2022 m_requestedSitTargetUUID = UUID.Zero;
2023 m_requestedSitTargetID = 0;
2024 m_requestedSitOffset = Vector3.Zero;
2025 } 2884 }
2026 2885
2027 } 2886 if ( m_scene.PhysicsScene == null)
2028 2887 return false;
2029 public void SitRayCastAvatarPositionCameraZ(SceneObjectPart part)
2030 {
2031 // Next, try to raycast from the camera Z position
2032 Vector3 EndRayCastPosition = part.AbsolutePosition + m_requestedSitOffset;
2033 Vector3 StartRayCastPosition = AbsolutePosition; StartRayCastPosition.Z = CameraPosition.Z;
2034 Vector3 direction = Vector3.Normalize(EndRayCastPosition - StartRayCastPosition);
2035 float distance = Vector3.Distance(EndRayCastPosition, StartRayCastPosition);
2036 m_scene.PhysicsScene.RaycastWorld(StartRayCastPosition, direction, distance, SitRayCastAvatarPositionCameraZResponse);
2037 }
2038 2888
2039 public void SitRayCastAvatarPositionCameraZResponse(bool hitYN, Vector3 collisionPoint, uint localid, float pdistance, Vector3 normal) 2889 if (part.PhysActor == null)
2040 {
2041 SceneObjectPart part = FindNextAvailableSitTarget(m_requestedSitTargetUUID);
2042 if (part != null)
2043 { 2890 {
2044 if (hitYN) 2891 // none physcis shape
2045 { 2892 if (part.PhysicsShapeType == (byte)PhysicsShapeType.None)
2046 if (collisionPoint.ApproxEquals(m_requestedSitOffset + part.AbsolutePosition, 0.2f)) 2893 ControllingClient.SendAlertMessage(" There is no suitable surface to sit on, try another spot.");
2047 {
2048 SitRaycastFindEdge(collisionPoint, normal);
2049 m_log.DebugFormat("[SIT]: Raycast Avatar Position + CameraZ succeeded at point: {0}, normal:{1}", collisionPoint, normal);
2050 }
2051 else
2052 {
2053 SitRayCastCameraPosition(part);
2054 }
2055 }
2056 else 2894 else
2057 { 2895 { // non physical phantom TODO
2058 SitRayCastCameraPosition(part); 2896 ControllingClient.SendAlertMessage(" There is no suitable surface to sit on, try another spot.");
2897 return false;
2059 } 2898 }
2060 } 2899 return true;
2061 else
2062 {
2063 ControllingClient.SendAlertMessage("Sit position no longer exists");
2064 m_requestedSitTargetUUID = UUID.Zero;
2065 m_requestedSitTargetID = 0;
2066 m_requestedSitOffset = Vector3.Zero;
2067 } 2900 }
2068 2901
2069 }
2070 2902
2071 public void SitRayCastCameraPosition(SceneObjectPart part) 2903 // not doing autopilot
2072 { 2904 m_requestedSitTargetID = 0;
2073 // Next, try to raycast from the camera position
2074 Vector3 EndRayCastPosition = part.AbsolutePosition + m_requestedSitOffset;
2075 Vector3 StartRayCastPosition = CameraPosition;
2076 Vector3 direction = Vector3.Normalize(EndRayCastPosition - StartRayCastPosition);
2077 float distance = Vector3.Distance(EndRayCastPosition, StartRayCastPosition);
2078 m_scene.PhysicsScene.RaycastWorld(StartRayCastPosition, direction, distance, SitRayCastCameraPositionResponse);
2079 }
2080 2905
2081 public void SitRayCastCameraPositionResponse(bool hitYN, Vector3 collisionPoint, uint localid, float pdistance, Vector3 normal) 2906 if (m_scene.PhysicsScene.SitAvatar(part.PhysActor, AbsolutePosition, CameraPosition, offset, new Vector3(0.35f, 0, 0.65f), PhysicsSitResponse) != 0)
2082 { 2907 return true;
2083 SceneObjectPart part = FindNextAvailableSitTarget(m_requestedSitTargetUUID);
2084 if (part != null)
2085 {
2086 if (hitYN)
2087 {
2088 if (collisionPoint.ApproxEquals(m_requestedSitOffset + part.AbsolutePosition, 0.2f))
2089 {
2090 SitRaycastFindEdge(collisionPoint, normal);
2091 m_log.DebugFormat("[SIT]: Raycast Camera Position succeeded at point: {0}, normal:{1}", collisionPoint, normal);
2092 }
2093 else
2094 {
2095 SitRayHorizontal(part);
2096 }
2097 }
2098 else
2099 {
2100 SitRayHorizontal(part);
2101 }
2102 }
2103 else
2104 {
2105 ControllingClient.SendAlertMessage("Sit position no longer exists");
2106 m_requestedSitTargetUUID = UUID.Zero;
2107 m_requestedSitTargetID = 0;
2108 m_requestedSitOffset = Vector3.Zero;
2109 }
2110 2908
2909 return false;
2910*/
2111 } 2911 }
2112 2912
2113 public void SitRayHorizontal(SceneObjectPart part) 2913
2914 private bool CanEnterLandPosition(Vector3 testPos)
2114 { 2915 {
2115 // Next, try to raycast from the avatar position to fwd 2916 ILandObject land = m_scene.LandChannel.GetLandObject(testPos.X, testPos.Y);
2116 Vector3 EndRayCastPosition = part.AbsolutePosition + m_requestedSitOffset; 2917
2117 Vector3 StartRayCastPosition = CameraPosition; 2918 if (land == null || land.LandData.Name == "NO_LAND")
2118 Vector3 direction = Vector3.Normalize(EndRayCastPosition - StartRayCastPosition); 2919 return true;
2119 float distance = Vector3.Distance(EndRayCastPosition, StartRayCastPosition); 2920
2120 m_scene.PhysicsScene.RaycastWorld(StartRayCastPosition, direction, distance, SitRayCastHorizontalResponse); 2921 return land.CanBeOnThisLand(UUID,testPos.Z);
2121 } 2922 }
2122 2923
2123 public void SitRayCastHorizontalResponse(bool hitYN, Vector3 collisionPoint, uint localid, float pdistance, Vector3 normal) 2924 // status
2925 // < 0 ignore
2926 // 0 bad sit spot
2927 public void PhysicsSitResponse(int status, uint partID, Vector3 offset, Quaternion Orientation)
2124 { 2928 {
2125 SceneObjectPart part = FindNextAvailableSitTarget(m_requestedSitTargetUUID); 2929 if (status < 0)
2126 if (part != null) 2930 return;
2931
2932 if (status == 0)
2127 { 2933 {
2128 if (hitYN) 2934 ControllingClient.SendAlertMessage(" There is no suitable surface to sit on, try another spot.");
2129 { 2935 return;
2130 if (collisionPoint.ApproxEquals(m_requestedSitOffset + part.AbsolutePosition, 0.2f))
2131 {
2132 SitRaycastFindEdge(collisionPoint, normal);
2133 m_log.DebugFormat("[SIT]: Raycast Horizontal Position succeeded at point: {0}, normal:{1}", collisionPoint, normal);
2134 // Next, try to raycast from the camera position
2135 Vector3 EndRayCastPosition = part.AbsolutePosition + m_requestedSitOffset;
2136 Vector3 StartRayCastPosition = CameraPosition;
2137 Vector3 direction = Vector3.Normalize(EndRayCastPosition - StartRayCastPosition);
2138 float distance = Vector3.Distance(EndRayCastPosition, StartRayCastPosition);
2139 //m_scene.PhysicsScene.RaycastWorld(StartRayCastPosition, direction, distance, SitRayCastResponseAvatarPosition);
2140 }
2141 else
2142 {
2143 ControllingClient.SendAlertMessage("Sit position not accessable.");
2144 m_requestedSitTargetUUID = UUID.Zero;
2145 m_requestedSitTargetID = 0;
2146 m_requestedSitOffset = Vector3.Zero;
2147 }
2148 }
2149 else
2150 {
2151 ControllingClient.SendAlertMessage("Sit position not accessable.");
2152 m_requestedSitTargetUUID = UUID.Zero;
2153 m_requestedSitTargetID = 0;
2154 m_requestedSitOffset = Vector3.Zero;
2155 }
2156 } 2936 }
2157 else 2937
2938 SceneObjectPart part = m_scene.GetSceneObjectPart(partID);
2939 if (part == null)
2940 return;
2941
2942 Vector3 targetPos = part.GetWorldPosition() + offset * part.GetWorldRotation();
2943 if(!CanEnterLandPosition(targetPos))
2158 { 2944 {
2159 ControllingClient.SendAlertMessage("Sit position no longer exists"); 2945 ControllingClient.SendAlertMessage(" Sit position on restricted land, try another spot");
2160 m_requestedSitTargetUUID = UUID.Zero; 2946 return;
2161 m_requestedSitTargetID = 0;
2162 m_requestedSitOffset = Vector3.Zero;
2163 } 2947 }
2164 2948
2165 } 2949 RemoveFromPhysicalScene();
2166 2950
2167 private void SitRaycastFindEdge(Vector3 collisionPoint, Vector3 collisionNormal) 2951 if (MovingToTarget)
2168 { 2952 ResetMoveToTarget();
2169 int i = 0; 2953
2170 //throw new NotImplementedException(); 2954 Velocity = Vector3.Zero;
2171 //m_requestedSitTargetUUID = UUID.Zero; 2955
2172 //m_requestedSitTargetID = 0; 2956 part.AddSittingAvatar(this);
2173 //m_requestedSitOffset = Vector3.Zero; 2957
2958 Vector3 cameraAtOffset = part.GetCameraAtOffset();
2959 Vector3 cameraEyeOffset = part.GetCameraEyeOffset();
2960 bool forceMouselook = part.GetForceMouselook();
2961
2962 ControllingClient.SendSitResponse(
2963 part.UUID, offset, Orientation, false, cameraAtOffset, cameraEyeOffset, forceMouselook);
2964
2965 // not using autopilot
2174 2966
2175 SendSitResponse(ControllingClient, m_requestedSitTargetUUID, collisionPoint - m_requestedSitOffset, Quaternion.Identity); 2967 Rotation = Orientation;
2968 m_pos = offset;
2969
2970 m_requestedSitTargetID = 0;
2971
2972 ParentPart = part;
2973 ParentID = part.LocalId;
2974 if(status == 3)
2975 Animator.TrySetMovementAnimation("SIT_GROUND");
2976 else
2977 Animator.TrySetMovementAnimation("SIT");
2978 SendAvatarDataToAllClients();
2979
2980 part.ParentGroup.TriggerScriptChangedEvent(Changed.LINK);
2176 } 2981 }
2177 */
2178 2982
2179 public void HandleAgentSit(IClientAPI remoteClient, UUID agentID) 2983 public void HandleAgentSit(IClientAPI remoteClient, UUID agentID)
2180 { 2984 {
2985 if (IsChildAgent)
2986 return;
2987
2181 SceneObjectPart part = m_scene.GetSceneObjectPart(m_requestedSitTargetID); 2988 SceneObjectPart part = m_scene.GetSceneObjectPart(m_requestedSitTargetID);
2182 2989
2183 if (part != null) 2990 if (part != null)
@@ -2205,23 +3012,75 @@ namespace OpenSim.Region.Framework.Scenes
2205 3012
2206 //Quaternion result = (sitTargetOrient * vq) * nq; 3013 //Quaternion result = (sitTargetOrient * vq) * nq;
2207 3014
2208 m_pos = sitTargetPos + SIT_TARGET_ADJUSTMENT; 3015 double x, y, z, m1, m2;
2209 Rotation = sitTargetOrient; 3016
2210 ParentPosition = part.AbsolutePosition; 3017 Quaternion r = sitTargetOrient;
3018 m1 = r.X * r.X + r.Y * r.Y;
3019 m2 = r.Z * r.Z + r.W * r.W;
3020
3021 // Rotate the vector <0, 0, 1>
3022 x = 2 * (r.X * r.Z + r.Y * r.W);
3023 y = 2 * (-r.X * r.W + r.Y * r.Z);
3024 z = m2 - m1;
3025
3026 // Set m to be the square of the norm of r.
3027 double m = m1 + m2;
3028
3029 // This constant is emperically determined to be what is used in SL.
3030 // See also http://opensimulator.org/mantis/view.php?id=7096
3031 double offset = 0.05;
3032
3033 // Normally m will be ~ 1, but if someone passed a handcrafted quaternion
3034 // to llSitTarget with values so small that squaring them is rounded off
3035 // to zero, then m could be zero. The result of this floating point
3036 // round off error (causing us to skip this impossible normalization)
3037 // is only 5 cm.
3038 if (m > 0.000001)
3039 {
3040 offset /= m;
3041 }
3042
3043 Vector3 up = new Vector3((float)x, (float)y, (float)z);
3044 Vector3 sitOffset = up * (float)offset;
3045
3046 // sitOffset is in Avatar Center coordinates: from origin to 'sitTargetPos + SIT_TARGET_ADJUSTMENT'.
3047 // So, we need to _substract_ it to get to the origin of the Avatar Center.
3048 Vector3 newPos = sitTargetPos + SIT_TARGET_ADJUSTMENT - sitOffset;
3049 Quaternion newRot;
3050
3051 if (part.IsRoot)
3052 {
3053 newRot = sitTargetOrient;
3054 }
3055 else
3056 {
3057 newPos = newPos * part.RotationOffset;
3058 newRot = part.RotationOffset * sitTargetOrient;
3059 }
3060
3061 newPos += part.OffsetPosition;
3062
3063 m_pos = newPos;
3064 Rotation = newRot;
3065
3066// ParentPosition = part.AbsolutePosition;
2211 } 3067 }
2212 else 3068 else
2213 { 3069 {
2214 m_pos -= part.AbsolutePosition; 3070 // An viewer expects to specify sit positions as offsets to the root prim, even if a child prim is
2215 ParentPosition = part.AbsolutePosition; 3071 // being sat upon.
3072 m_pos -= part.GroupPosition;
3073
3074// ParentPosition = part.AbsolutePosition;
2216 3075
2217// m_log.DebugFormat( 3076// m_log.DebugFormat(
2218// "[SCENE PRESENCE]: Sitting {0} at position {1} ({2} + {3}) on part {4} {5} without sit target", 3077// "[SCENE PRESENCE]: Sitting {0} at position {1} ({2} + {3}) on part {4} {5} without sit target",
2219// Name, part.AbsolutePosition, m_pos, ParentPosition, part.Name, part.LocalId); 3078// Name, part.AbsolutePosition, m_pos, ParentPosition, part.Name, part.LocalId);
2220 } 3079 }
2221 3080
2222 ParentPart = m_scene.GetSceneObjectPart(m_requestedSitTargetID); 3081 ParentPart = part;
2223 ParentID = m_requestedSitTargetID; 3082 ParentID = m_requestedSitTargetID;
2224 3083 m_AngularVelocity = Vector3.Zero;
2225 Velocity = Vector3.Zero; 3084 Velocity = Vector3.Zero;
2226 RemoveFromPhysicalScene(); 3085 RemoveFromPhysicalScene();
2227 3086
@@ -2231,14 +3090,20 @@ namespace OpenSim.Region.Framework.Scenes
2231 sitAnimation = part.SitAnimation; 3090 sitAnimation = part.SitAnimation;
2232 } 3091 }
2233 Animator.TrySetMovementAnimation(sitAnimation); 3092 Animator.TrySetMovementAnimation(sitAnimation);
2234 SendAvatarDataToAllAgents(); 3093 SendAvatarDataToAllClients();
3094 TriggerScenePresenceUpdated();
2235 } 3095 }
2236 } 3096 }
2237 3097
2238 public void HandleAgentSitOnGround() 3098 public void HandleAgentSitOnGround()
2239 { 3099 {
2240// m_updateCount = 0; // Kill animation update burst so that the SIT_G.. will stick. 3100 if (IsChildAgent)
3101 return;
3102
3103// m_updateCount = 0; // Kill animation update burst so that the SIT_G.. will stick..
3104 m_AngularVelocity = Vector3.Zero;
2241 Animator.TrySetMovementAnimation("SIT_GROUND_CONSTRAINED"); 3105 Animator.TrySetMovementAnimation("SIT_GROUND_CONSTRAINED");
3106 TriggerScenePresenceUpdated();
2242 SitGround = true; 3107 SitGround = true;
2243 RemoveFromPhysicalScene(); 3108 RemoveFromPhysicalScene();
2244 } 3109 }
@@ -2255,22 +3120,39 @@ namespace OpenSim.Region.Framework.Scenes
2255 public void HandleStartAnim(IClientAPI remoteClient, UUID animID) 3120 public void HandleStartAnim(IClientAPI remoteClient, UUID animID)
2256 { 3121 {
2257 Animator.AddAnimation(animID, UUID.Zero); 3122 Animator.AddAnimation(animID, UUID.Zero);
3123 TriggerScenePresenceUpdated();
2258 } 3124 }
2259 3125
2260 public void HandleStopAnim(IClientAPI remoteClient, UUID animID) 3126 public void HandleStopAnim(IClientAPI remoteClient, UUID animID)
2261 { 3127 {
2262 Animator.RemoveAnimation(animID, false); 3128 Animator.RemoveAnimation(animID, false);
3129 TriggerScenePresenceUpdated();
2263 } 3130 }
2264 3131
2265 /// <summary> 3132 /// <summary>
2266 /// Rotate the avatar to the given rotation and apply a movement in the given relative vector 3133 /// Rotate the avatar to the given rotation and apply a movement in the given relative vector
2267 /// </summary> 3134 /// </summary>
2268 /// <param name="vec">The vector in which to move. This is relative to the rotation argument</param> 3135 /// <param name="vec">The vector in which to move. This is relative to the rotation argument</param>
2269 public void AddNewMovement(Vector3 vec) 3136 /// <param name="thisAddSpeedModifier">
3137 /// Optional additional speed modifier for this particular add. Default is 1</param>
3138 public void AddNewMovement(Vector3 vec, float thisAddSpeedModifier = 1)
2270 { 3139 {
2271// m_log.DebugFormat("[SCENE PRESENCE]: Adding new movement {0} for {1}", vec, Name); 3140// m_log.DebugFormat(
3141// "[SCENE PRESENCE]: Adding new movement {0} with rotation {1}, thisAddSpeedModifier {2} for {3}",
3142// vec, Rotation, thisAddSpeedModifier, Name);
2272 3143
2273 Vector3 direc = vec * Rotation; 3144 Quaternion rot = Rotation;
3145 if (!Flying && PresenceType != PresenceType.Npc)
3146 {
3147 // The only situation in which we care about X and Y is avatar flying. The rest of the time
3148 // these parameters are not relevant for determining avatar movement direction and cause issues such
3149 // as wrong walk speed if the camera is rotated.
3150 rot.X = 0;
3151 rot.Y = 0;
3152 rot.Normalize();
3153 }
3154
3155 Vector3 direc = vec * rot;
2274 direc.Normalize(); 3156 direc.Normalize();
2275 3157
2276 if (Flying != FlyingOld) // add for fly velocity control 3158 if (Flying != FlyingOld) // add for fly velocity control
@@ -2286,7 +3168,9 @@ namespace OpenSim.Region.Framework.Scenes
2286 if ((vec.Z == 0f) && !Flying) 3168 if ((vec.Z == 0f) && !Flying)
2287 direc.Z = 0f; // Prevent camera WASD up. 3169 direc.Z = 0f; // Prevent camera WASD up.
2288 3170
2289 direc *= 0.03f * 128f * SpeedModifier; 3171 direc *= 0.03f * 128f * SpeedModifier * thisAddSpeedModifier;
3172
3173// m_log.DebugFormat("[SCENE PRESENCE]: Force to apply before modification was {0} for {1}", direc, Name);
2290 3174
2291 if (PhysicsActor != null) 3175 if (PhysicsActor != null)
2292 { 3176 {
@@ -2315,14 +3199,17 @@ namespace OpenSim.Region.Framework.Scenes
2315 direc.Z *= 2.6f; 3199 direc.Z *= 2.6f;
2316 3200
2317 // TODO: PreJump and jump happen too quickly. Many times prejump gets ignored. 3201 // TODO: PreJump and jump happen too quickly. Many times prejump gets ignored.
2318 Animator.TrySetMovementAnimation("PREJUMP"); 3202// Animator.TrySetMovementAnimation("PREJUMP");
2319 Animator.TrySetMovementAnimation("JUMP"); 3203// Animator.TrySetMovementAnimation("JUMP");
2320 } 3204 }
2321 } 3205 }
2322 } 3206 }
2323 3207
3208// m_log.DebugFormat("[SCENE PRESENCE]: Setting force to apply to {0} for {1}", direc, Name);
3209
2324 // TODO: Add the force instead of only setting it to support multiple forces per frame? 3210 // TODO: Add the force instead of only setting it to support multiple forces per frame?
2325 m_forceToApply = direc; 3211 m_forceToApply = direc;
3212 Animator.UpdateMovementAnimations();
2326 } 3213 }
2327 3214
2328 #endregion 3215 #endregion
@@ -2331,25 +3218,27 @@ namespace OpenSim.Region.Framework.Scenes
2331 3218
2332 public override void Update() 3219 public override void Update()
2333 { 3220 {
2334 const float ROTATION_TOLERANCE = 0.01f;
2335 const float VELOCITY_TOLERANCE = 0.001f;
2336 const float POSITION_TOLERANCE = 0.05f;
2337
2338 if (IsChildAgent == false) 3221 if (IsChildAgent == false)
2339 { 3222 {
2340 // NOTE: Velocity is not the same as m_velocity. Velocity will attempt to 3223 // NOTE: Velocity is not the same as m_velocity. Velocity will attempt to
2341 // grab the latest PhysicsActor velocity, whereas m_velocity is often 3224 // grab the latest PhysicsActor velocity, whereas m_velocity is often
2342 // storing a requested force instead of an actual traveling velocity 3225 // storing a requested force instead of an actual traveling velocity
2343 3226 if (Appearance.AvatarSize != m_lastSize && !IsLoggingIn)
2344 // Throw away duplicate or insignificant updates 3227 SendAvatarDataToAllClients();
2345 if ( 3228
2346 // If the velocity has become zero, send it no matter what. 3229 // Allow any updates for sitting avatars to that llSetPrimitiveLinkParams() can work for very
2347 (Velocity != m_lastVelocity && Velocity == Vector3.Zero) 3230 // small increments (e.g. sit position adjusters). An alternative may be to eliminate the tolerance
2348 // otherwise, if things have changed reasonably, send the update 3231 // checks on all updates but the ramifications of this would need careful consideration.
2349 || (!Rotation.ApproxEquals(m_lastRotation, ROTATION_TOLERANCE) 3232 bool updateClients
2350 || !Velocity.ApproxEquals(m_lastVelocity, VELOCITY_TOLERANCE) 3233 = IsSatOnObject && (Rotation != m_lastRotation || Velocity != m_lastVelocity || m_pos != m_lastPosition);
2351 || !m_pos.ApproxEquals(m_lastPosition, POSITION_TOLERANCE))) 3234
2352 3235 if (!updateClients)
3236 updateClients
3237 = !Rotation.ApproxEquals(m_lastRotation, Scene.RootRotationUpdateTolerance)
3238 || !Velocity.ApproxEquals(m_lastVelocity, Scene.RootVelocityUpdateTolerance)
3239 || !m_pos.ApproxEquals(m_lastPosition, Scene.RootPositionUpdateTolerance);
3240
3241 if (updateClients)
2353 { 3242 {
2354 SendTerseUpdateToAllClients(); 3243 SendTerseUpdateToAllClients();
2355 3244
@@ -2359,7 +3248,8 @@ namespace OpenSim.Region.Framework.Scenes
2359 m_lastVelocity = Velocity; 3248 m_lastVelocity = Velocity;
2360 } 3249 }
2361 3250
2362 CheckForBorderCrossing(); 3251 if (Scene.AllowAvatarCrossing)
3252 CheckForBorderCrossing();
2363 3253
2364 CheckForSignificantMovement(); // sends update to the modules. 3254 CheckForSignificantMovement(); // sends update to the modules.
2365 } 3255 }
@@ -2369,7 +3259,6 @@ namespace OpenSim.Region.Framework.Scenes
2369 3259
2370 #region Update Client(s) 3260 #region Update Client(s)
2371 3261
2372
2373 /// <summary> 3262 /// <summary>
2374 /// Sends a location update to the client connected to this scenePresence 3263 /// Sends a location update to the client connected to this scenePresence
2375 /// </summary> 3264 /// </summary>
@@ -2380,6 +3269,29 @@ namespace OpenSim.Region.Framework.Scenes
2380 // server. 3269 // server.
2381 if (remoteClient.IsActive) 3270 if (remoteClient.IsActive)
2382 { 3271 {
3272 if (Scene.RootTerseUpdatePeriod > 1)
3273 {
3274// Console.WriteLine(
3275// "{0} {1} {2} {3} {4} {5} for {6} to {7}",
3276// remoteClient.AgentId, UUID, remoteClient.SceneAgent.IsChildAgent, m_terseUpdateCount, Scene.RootTerseUpdatePeriod, Velocity.ApproxEquals(Vector3.Zero, 0.001f), Name, remoteClient.Name);
3277 if (remoteClient.AgentId != UUID
3278 && !remoteClient.SceneAgent.IsChildAgent
3279 && m_terseUpdateCount % Scene.RootTerseUpdatePeriod != 0
3280 && !Velocity.ApproxEquals(Vector3.Zero, 0.001f))
3281 {
3282// m_log.DebugFormat("[SCENE PRESENCE]: Discarded update from {0} to {1}, args {2} {3} {4} {5} {6} {7}",
3283// Name, remoteClient.Name, remoteClient.AgentId, UUID, remoteClient.SceneAgent.IsChildAgent, m_terseUpdateCount, Scene.RootTerseUpdatePeriod, Velocity.ApproxEquals(Vector3.Zero, 0.001f));
3284
3285 return;
3286 }
3287 }
3288
3289 if (Scene.ChildTerseUpdatePeriod > 1
3290 && remoteClient.SceneAgent.IsChildAgent
3291 && m_terseUpdateCount % Scene.ChildTerseUpdatePeriod != 0
3292 && !Velocity.ApproxEquals(Vector3.Zero, 0.001f))
3293 return;
3294
2383 //m_log.DebugFormat("[SCENE PRESENCE]: " + Name + " sending TerseUpdate to " + remoteClient.Name + " : Pos={0} Rot={1} Vel={2}", m_pos, Rotation, m_velocity); 3295 //m_log.DebugFormat("[SCENE PRESENCE]: " + Name + " sending TerseUpdate to " + remoteClient.Name + " : Pos={0} Rot={1} Vel={2}", m_pos, Rotation, m_velocity);
2384 3296
2385 remoteClient.SendEntityUpdate( 3297 remoteClient.SendEntityUpdate(
@@ -2417,7 +3329,11 @@ namespace OpenSim.Region.Framework.Scenes
2417 float distanceError = Vector3.Distance(OffsetPosition, expectedPosition); 3329 float distanceError = Vector3.Distance(OffsetPosition, expectedPosition);
2418 3330
2419 float speed = Velocity.Length(); 3331 float speed = Velocity.Length();
2420 float velocidyDiff = Vector3.Distance(lastVelocitySentToAllClients, Velocity); 3332 float velocityDiff = Vector3.Distance(lastVelocitySentToAllClients, Velocity);
3333
3334// m_log.DebugFormat(
3335// "[SCENE PRESENCE]: Delta-v {0}, lastVelocity {1}, Velocity {2} for {3} in {4}",
3336// velocidyDiff, lastVelocitySentToAllClients, Velocity, Name, Scene.Name);
2421 3337
2422 // assuming 5 ms. worst case precision for timer, use 2x that 3338 // assuming 5 ms. worst case precision for timer, use 2x that
2423 // for distance error threshold 3339 // for distance error threshold
@@ -2425,12 +3341,19 @@ namespace OpenSim.Region.Framework.Scenes
2425 3341
2426 if (speed < 0.01f // allow rotation updates if avatar position is unchanged 3342 if (speed < 0.01f // allow rotation updates if avatar position is unchanged
2427 || Math.Abs(distanceError) > distanceErrorThreshold 3343 || Math.Abs(distanceError) > distanceErrorThreshold
2428 || velocidyDiff > 0.01f) // did velocity change from last update? 3344 || velocityDiff > 0.01f) // did velocity change from last update?
2429 { 3345 {
3346// m_log.DebugFormat(
3347// "[SCENE PRESENCE]: Update triggered with speed {0}, distanceError {1}, distanceThreshold {2}, delta-v {3} for {4} in {5}",
3348// speed, distanceError, distanceErrorThreshold, velocidyDiff, Name, Scene.Name);
3349
2430 lastVelocitySentToAllClients = Velocity; 3350 lastVelocitySentToAllClients = Velocity;
2431 lastTerseUpdateToAllClientsTick = currentTick; 3351 lastTerseUpdateToAllClientsTick = currentTick;
2432 lastPositionSentToAllClients = OffsetPosition; 3352 lastPositionSentToAllClients = OffsetPosition;
2433 3353
3354 m_terseUpdateCount++;
3355
3356// Console.WriteLine("Scheduled update for {0} in {1}", Name, Scene.Name);
2434 m_scene.ForEachClient(SendTerseUpdateToClient); 3357 m_scene.ForEachClient(SendTerseUpdateToClient);
2435 } 3358 }
2436 TriggerScenePresenceUpdated(); 3359 TriggerScenePresenceUpdated();
@@ -2456,24 +3379,30 @@ namespace OpenSim.Region.Framework.Scenes
2456 ControllingClient.SendCoarseLocationUpdate(avatarUUIDs, coarseLocations); 3379 ControllingClient.SendCoarseLocationUpdate(avatarUUIDs, coarseLocations);
2457 } 3380 }
2458 3381
2459 public void SendInitialDataToMe() 3382 public void SendInitialDataToClient()
2460 { 3383 {
3384 SentInitialDataToClient = true;
3385
2461 // Send all scene object to the new client 3386 // Send all scene object to the new client
2462 Util.FireAndForget(delegate 3387 WorkManager.RunJob("SendInitialDataToClient", delegate
2463 { 3388 {
3389// m_log.DebugFormat(
3390// "[SCENE PRESENCE]: Sending initial data to {0} agent {1} in {2}, tp flags {3}",
3391// IsChildAgent ? "child" : "root", Name, Scene.Name, m_teleportFlags);
3392
2464 // we created a new ScenePresence (a new child agent) in a fresh region. 3393 // we created a new ScenePresence (a new child agent) in a fresh region.
2465 // Request info about all the (root) agents in this region 3394 // Request info about all the (root) agents in this region
2466 // Note: This won't send data *to* other clients in that region (children don't send) 3395 // Note: This won't send data *to* other clients in that region (children don't send)
2467 SendOtherAgentsAvatarDataToMe(); 3396 SendOtherAgentsAvatarDataToClient();
2468 SendOtherAgentsAppearanceToMe(); 3397 SendOtherAgentsAppearanceToClient();
2469 3398
2470 EntityBase[] entities = Scene.Entities.GetEntities(); 3399 EntityBase[] entities = Scene.Entities.GetEntities();
2471 foreach(EntityBase e in entities) 3400 foreach (EntityBase e in entities)
2472 { 3401 {
2473 if (e != null && e is SceneObjectGroup) 3402 if (e != null && e is SceneObjectGroup)
2474 ((SceneObjectGroup)e).SendFullUpdateToClient(ControllingClient); 3403 ((SceneObjectGroup)e).SendFullUpdateToClient(ControllingClient);
2475 } 3404 }
2476 }); 3405 }, null, string.Format("SendInitialDataToClient ({0} in {1})", Name, Scene.Name), false, true);
2477 } 3406 }
2478 3407
2479 /// <summary> 3408 /// <summary>
@@ -2506,26 +3435,33 @@ namespace OpenSim.Region.Framework.Scenes
2506 // getting other avatars information was initiated elsewhere immediately after the child circuit connected... don't do it 3435 // getting other avatars information was initiated elsewhere immediately after the child circuit connected... don't do it
2507 // again here... this comes after the cached appearance check because the avatars 3436 // again here... this comes after the cached appearance check because the avatars
2508 // appearance goes into the avatar update packet 3437 // appearance goes into the avatar update packet
2509 SendAvatarDataToAllAgents(); 3438 SendAvatarDataToAllClients();
2510 SendAppearanceToAgent(this); 3439
3440 // This invocation always shows up in the viewer logs as an error. Is it needed?
3441 SendAppearanceToClient(this);
2511 3442
2512 // If we are using the the cached appearance then send it out to everyone 3443 // If we are using the the cached appearance then send it out to everyone
2513 if (cachedappearance) 3444 if (cachedappearance)
2514 { 3445 {
2515 m_log.DebugFormat("[SCENE PRESENCE]: baked textures are in the cache for {0}", Name); 3446 m_log.DebugFormat("[SCENE PRESENCE]: Baked textures are in the cache for {0} in {1}", Name, m_scene.Name);
2516 3447
2517 // If the avatars baked textures are all in the cache, then we have a 3448 // If the avatars baked textures are all in the cache, then we have a
2518 // complete appearance... send it out, if not, then we'll send it when 3449 // complete appearance... send it out, if not, then we'll send it when
2519 // the avatar finishes updating its appearance 3450 // the avatar finishes updating its appearance
2520 SendAppearanceToAllOtherAgents(); 3451 SendAppearanceToAllOtherClients();
2521 } 3452 }
2522 } 3453 }
2523 3454
3455 public void SendAvatarDataToAllClients()
3456 {
3457 SendAvatarDataToAllClients(true);
3458 }
3459
2524 /// <summary> 3460 /// <summary>
2525 /// Send this agent's avatar data to all other root and child agents in the scene 3461 /// Send this agent's avatar data to all other root and child agents in the scene
2526 /// This agent must be root. This avatar will receive its own update. 3462 /// This agent must be root. This avatar will receive its own update.
2527 /// </summary> 3463 /// </summary>
2528 public void SendAvatarDataToAllAgents() 3464 public void SendAvatarDataToAllClients(bool full)
2529 { 3465 {
2530 //m_log.DebugFormat("[SCENE PRESENCE] SendAvatarDataToAllAgents: {0} ({1})", Name, UUID); 3466 //m_log.DebugFormat("[SCENE PRESENCE] SendAvatarDataToAllAgents: {0} ({1})", Name, UUID);
2531 // only send update from root agents to other clients; children are only "listening posts" 3467 // only send update from root agents to other clients; children are only "listening posts"
@@ -2538,12 +3474,17 @@ namespace OpenSim.Region.Framework.Scenes
2538 return; 3474 return;
2539 } 3475 }
2540 3476
3477 m_lastSize = Appearance.AvatarSize;
3478
2541 int count = 0; 3479 int count = 0;
2542 m_scene.ForEachScenePresence(delegate(ScenePresence scenePresence) 3480 m_scene.ForEachScenePresence(delegate(ScenePresence scenePresence)
2543 { 3481 {
2544 SendAvatarDataToAgent(scenePresence); 3482 if (full)
2545 count++; 3483 SendAvatarDataToClient(scenePresence);
2546 }); 3484 else
3485 scenePresence.ControllingClient.SendAvatarDataImmediate(this);
3486 count++;
3487 });
2547 3488
2548 m_scene.StatsReporter.AddAgentUpdates(count); 3489 m_scene.StatsReporter.AddAgentUpdates(count);
2549 } 3490 }
@@ -2552,7 +3493,7 @@ namespace OpenSim.Region.Framework.Scenes
2552 /// Send avatar data for all other root agents to this agent, this agent 3493 /// Send avatar data for all other root agents to this agent, this agent
2553 /// can be either a child or root 3494 /// can be either a child or root
2554 /// </summary> 3495 /// </summary>
2555 public void SendOtherAgentsAvatarDataToMe() 3496 public void SendOtherAgentsAvatarDataToClient()
2556 { 3497 {
2557 int count = 0; 3498 int count = 0;
2558 m_scene.ForEachRootScenePresence(delegate(ScenePresence scenePresence) 3499 m_scene.ForEachRootScenePresence(delegate(ScenePresence scenePresence)
@@ -2561,7 +3502,7 @@ namespace OpenSim.Region.Framework.Scenes
2561 if (scenePresence.UUID == UUID) 3502 if (scenePresence.UUID == UUID)
2562 return; 3503 return;
2563 3504
2564 scenePresence.SendAvatarDataToAgent(this); 3505 scenePresence.SendAvatarDataToClient(this);
2565 count++; 3506 count++;
2566 }); 3507 });
2567 3508
@@ -2572,9 +3513,9 @@ namespace OpenSim.Region.Framework.Scenes
2572 /// Send avatar data to an agent. 3513 /// Send avatar data to an agent.
2573 /// </summary> 3514 /// </summary>
2574 /// <param name="avatar"></param> 3515 /// <param name="avatar"></param>
2575 public void SendAvatarDataToAgent(ScenePresence avatar) 3516 public void SendAvatarDataToClient(ScenePresence avatar)
2576 { 3517 {
2577 //m_log.DebugFormat("[SCENE PRESENCE] SendAvatarDataToAgent from {0} ({1}) to {2} ({3})", Name, UUID, avatar.Name, avatar.UUID); 3518 //m_log.DebugFormat("[SCENE PRESENCE] SendAvatarDataToClient from {0} ({1}) to {2} ({3})", Name, UUID, avatar.Name, avatar.UUID);
2578 3519
2579 avatar.ControllingClient.SendAvatarDataImmediate(this); 3520 avatar.ControllingClient.SendAvatarDataImmediate(this);
2580 Animator.SendAnimPackToClient(avatar.ControllingClient); 3521 Animator.SendAnimPackToClient(avatar.ControllingClient);
@@ -2584,9 +3525,9 @@ namespace OpenSim.Region.Framework.Scenes
2584 /// Send this agent's appearance to all other root and child agents in the scene 3525 /// Send this agent's appearance to all other root and child agents in the scene
2585 /// This agent must be root. 3526 /// This agent must be root.
2586 /// </summary> 3527 /// </summary>
2587 public void SendAppearanceToAllOtherAgents() 3528 public void SendAppearanceToAllOtherClients()
2588 { 3529 {
2589// m_log.DebugFormat("[SCENE PRESENCE] SendAppearanceToAllOtherAgents: {0} {1}", Name, UUID); 3530// m_log.DebugFormat("[SCENE PRESENCE] SendAppearanceToAllOtherClients: {0} {1}", Name, UUID);
2590 3531
2591 // only send update from root agents to other clients; children are only "listening posts" 3532 // only send update from root agents to other clients; children are only "listening posts"
2592 if (IsChildAgent) 3533 if (IsChildAgent)
@@ -2605,7 +3546,7 @@ namespace OpenSim.Region.Framework.Scenes
2605 if (scenePresence.UUID == UUID) 3546 if (scenePresence.UUID == UUID)
2606 return; 3547 return;
2607 3548
2608 SendAppearanceToAgent(scenePresence); 3549 SendAppearanceToClient(scenePresence);
2609 count++; 3550 count++;
2610 }); 3551 });
2611 3552
@@ -2616,9 +3557,9 @@ namespace OpenSim.Region.Framework.Scenes
2616 /// Send appearance from all other root agents to this agent. this agent 3557 /// Send appearance from all other root agents to this agent. this agent
2617 /// can be either root or child 3558 /// can be either root or child
2618 /// </summary> 3559 /// </summary>
2619 public void SendOtherAgentsAppearanceToMe() 3560 public void SendOtherAgentsAppearanceToClient()
2620 { 3561 {
2621// m_log.DebugFormat("[SCENE PRESENCE] SendOtherAgentsAppearanceToMe: {0} {1}", Name, UUID); 3562// m_log.DebugFormat("[SCENE PRESENCE] SendOtherAgentsAppearanceToClient {0} {1}", Name, UUID);
2622 3563
2623 int count = 0; 3564 int count = 0;
2624 m_scene.ForEachRootScenePresence(delegate(ScenePresence scenePresence) 3565 m_scene.ForEachRootScenePresence(delegate(ScenePresence scenePresence)
@@ -2627,7 +3568,7 @@ namespace OpenSim.Region.Framework.Scenes
2627 if (scenePresence.UUID == UUID) 3568 if (scenePresence.UUID == UUID)
2628 return; 3569 return;
2629 3570
2630 scenePresence.SendAppearanceToAgent(this); 3571 scenePresence.SendAppearanceToClient(this);
2631 count++; 3572 count++;
2632 }); 3573 });
2633 3574
@@ -2638,13 +3579,15 @@ namespace OpenSim.Region.Framework.Scenes
2638 /// Send appearance data to an agent. 3579 /// Send appearance data to an agent.
2639 /// </summary> 3580 /// </summary>
2640 /// <param name="avatar"></param> 3581 /// <param name="avatar"></param>
2641 public void SendAppearanceToAgent(ScenePresence avatar) 3582 public void SendAppearanceToClient(ScenePresence avatar)
2642 { 3583 {
2643// m_log.DebugFormat( 3584// m_log.DebugFormat(
2644// "[SCENE PRESENCE]: Sending appearance data from {0} {1} to {2} {3}", Name, m_uuid, avatar.Name, avatar.UUID); 3585// "[SCENE PRESENCE]: Sending appearance data from {0} {1} to {2} {3}", Name, m_uuid, avatar.Name, avatar.UUID);
2645 3586
2646 avatar.ControllingClient.SendAppearance( 3587 avatar.ControllingClient.SendAppearance(
2647 UUID, Appearance.VisualParams, Appearance.Texture.GetBytes()); 3588 UUID, Appearance.VisualParams, Appearance.Texture.GetBytes());
3589
3590
2648 } 3591 }
2649 3592
2650 #endregion 3593 #endregion
@@ -2663,11 +3606,10 @@ namespace OpenSim.Region.Framework.Scenes
2663 } 3606 }
2664 3607
2665 // Minimum Draw distance is 64 meters, the Radius of the draw distance sphere is 32m 3608 // Minimum Draw distance is 64 meters, the Radius of the draw distance sphere is 32m
2666 if (Util.GetDistanceTo(AbsolutePosition, m_lastChildAgentUpdatePosition) >= Scene.ChildReprioritizationDistance || 3609 if (Util.GetDistanceTo(AbsolutePosition, m_lastChildAgentUpdatePosition) >= Scene.ChildReprioritizationDistance)
2667 Util.GetDistanceTo(CameraPosition, m_lastChildAgentUpdateCamPosition) >= Scene.ChildReprioritizationDistance)
2668 { 3610 {
2669 m_lastChildAgentUpdatePosition = AbsolutePosition; 3611 m_lastChildAgentUpdatePosition = AbsolutePosition;
2670 m_lastChildAgentUpdateCamPosition = CameraPosition; 3612// m_lastChildAgentUpdateCamPosition = CameraPosition;
2671 3613
2672 ChildAgentDataUpdate cadu = new ChildAgentDataUpdate(); 3614 ChildAgentDataUpdate cadu = new ChildAgentDataUpdate();
2673 cadu.ActiveGroupID = UUID.Zero.Guid; 3615 cadu.ActiveGroupID = UUID.Zero.Guid;
@@ -2694,10 +3636,11 @@ namespace OpenSim.Region.Framework.Scenes
2694 cadu.Velocity = Velocity; 3636 cadu.Velocity = Velocity;
2695 3637
2696 AgentPosition agentpos = new AgentPosition(); 3638 AgentPosition agentpos = new AgentPosition();
2697 agentpos.CopyFrom(cadu); 3639 agentpos.CopyFrom(cadu, ControllingClient.SessionId);
2698 3640
2699 // Let's get this out of the update loop 3641 // Let's get this out of the update loop
2700 Util.FireAndForget(delegate { m_scene.SendOutChildAgentUpdates(agentpos, this); }); 3642 Util.FireAndForget(
3643 o => m_scene.SendOutChildAgentUpdates(agentpos, this), null, "ScenePresence.SendOutChildAgentUpdates");
2701 } 3644 }
2702 } 3645 }
2703 3646
@@ -2719,140 +3662,84 @@ namespace OpenSim.Region.Framework.Scenes
2719 3662
2720 // If we don't have a PhysActor, we can't cross anyway 3663 // If we don't have a PhysActor, we can't cross anyway
2721 // Also don't do this while sat, sitting avatars cross with the 3664 // Also don't do this while sat, sitting avatars cross with the
2722 // object they sit on. 3665 // object they sit on. ParentUUID denoted a pending sit, don't
2723 if (ParentID != 0 || PhysicsActor == null) 3666 // interfere with it.
3667 if (ParentID != 0 || PhysicsActor == null || ParentUUID != UUID.Zero)
2724 return; 3668 return;
2725 3669
2726 if (!IsInTransit) 3670 if (IsInTransit)
2727 { 3671 return;
2728 Vector3 pos2 = AbsolutePosition;
2729 Vector3 vel = Velocity;
2730 int neighbor = 0;
2731 int[] fix = new int[2];
2732 3672
2733 float timeStep = 0.1f; 3673 Vector3 pos2 = AbsolutePosition;
2734 pos2.X = pos2.X + (vel.X * timeStep); 3674 Vector3 origPosition = pos2;
2735 pos2.Y = pos2.Y + (vel.Y * timeStep); 3675 Vector3 vel = Velocity;
2736 pos2.Z = pos2.Z + (vel.Z * timeStep);
2737 3676
2738 if (!IsInTransit) 3677 // Compute the future avatar position.
2739 { 3678 // If the avatar will be crossing, we force the crossing to happen now
2740 // Checks if where it's headed exists a region 3679 // in the hope that this will make the avatar movement smoother when crossing.
2741 bool needsTransit = false; 3680 pos2 += vel * 0.05f;
2742 if (m_scene.TestBorderCross(pos2, Cardinals.W))
2743 {
2744 if (m_scene.TestBorderCross(pos2, Cardinals.S))
2745 {
2746 needsTransit = true;
2747 neighbor = m_scene.HaveNeighbor(Cardinals.SW, ref fix);
2748 }
2749 else if (m_scene.TestBorderCross(pos2, Cardinals.N))
2750 {
2751 needsTransit = true;
2752 neighbor = m_scene.HaveNeighbor(Cardinals.NW, ref fix);
2753 }
2754 else
2755 {
2756 needsTransit = true;
2757 neighbor = m_scene.HaveNeighbor(Cardinals.W, ref fix);
2758 }
2759 }
2760 else if (m_scene.TestBorderCross(pos2, Cardinals.E))
2761 {
2762 if (m_scene.TestBorderCross(pos2, Cardinals.S))
2763 {
2764 needsTransit = true;
2765 neighbor = m_scene.HaveNeighbor(Cardinals.SE, ref fix);
2766 }
2767 else if (m_scene.TestBorderCross(pos2, Cardinals.N))
2768 {
2769 needsTransit = true;
2770 neighbor = m_scene.HaveNeighbor(Cardinals.NE, ref fix);
2771 }
2772 else
2773 {
2774 needsTransit = true;
2775 neighbor = m_scene.HaveNeighbor(Cardinals.E, ref fix);
2776 }
2777 }
2778 else if (m_scene.TestBorderCross(pos2, Cardinals.S))
2779 {
2780 needsTransit = true;
2781 neighbor = m_scene.HaveNeighbor(Cardinals.S, ref fix);
2782 }
2783 else if (m_scene.TestBorderCross(pos2, Cardinals.N))
2784 {
2785 needsTransit = true;
2786 neighbor = m_scene.HaveNeighbor(Cardinals.N, ref fix);
2787 }
2788 3681
2789 // Makes sure avatar does not end up outside region 3682 if (m_scene.PositionIsInCurrentRegion(pos2))
2790 if (neighbor <= 0) 3683 return;
2791 { 3684
2792 if (needsTransit) 3685 m_log.DebugFormat("{0} CheckForBorderCrossing: position outside region. {1} in {2} at pos {3}",
2793 { 3686 LogHeader, Name, Scene.Name, pos2);
2794 if (m_requestedSitTargetUUID == UUID.Zero) 3687
2795 { 3688 // Disconnect from the current region
2796 bool isFlying = Flying; 3689 bool isFlying = Flying;
2797 RemoveFromPhysicalScene(); 3690 RemoveFromPhysicalScene();
2798 3691
2799 Vector3 pos = AbsolutePosition; 3692 // pos2 is the forcasted position so make that the 'current' position so the crossing
2800 if (AbsolutePosition.X < 0) 3693 // code will move us into the newly addressed region.
2801 pos.X += Velocity.X * 2; 3694 m_pos = pos2;
2802 else if (AbsolutePosition.X > Constants.RegionSize) 3695
2803 pos.X -= Velocity.X * 2; 3696 if (CrossToNewRegion())
2804 if (AbsolutePosition.Y < 0) 3697 {
2805 pos.Y += Velocity.Y * 2; 3698 AddToPhysicalScene(isFlying);
2806 else if (AbsolutePosition.Y > Constants.RegionSize) 3699 }
2807 pos.Y -= Velocity.Y * 2; 3700 else
2808 Velocity = Vector3.Zero; 3701 {
2809 AbsolutePosition = pos; 3702 // Tried to make crossing happen but it failed.
2810 3703 if (m_requestedSitTargetUUID == UUID.Zero)
2811// m_log.DebugFormat("[SCENE PRESENCE]: Prevented flyoff for {0} at {1}", Name, AbsolutePosition);
2812
2813 AddToPhysicalScene(isFlying);
2814 }
2815 }
2816 }
2817 else if (neighbor > 0)
2818 {
2819 if (!CrossToNewRegion())
2820 {
2821 if (m_requestedSitTargetUUID == UUID.Zero)
2822 {
2823 bool isFlying = Flying;
2824 RemoveFromPhysicalScene();
2825
2826 Vector3 pos = AbsolutePosition;
2827 if (AbsolutePosition.X < 0)
2828 pos.X += Velocity.X * 2;
2829 else if (AbsolutePosition.X > Constants.RegionSize)
2830 pos.X -= Velocity.X * 2;
2831 if (AbsolutePosition.Y < 0)
2832 pos.Y += Velocity.Y * 2;
2833 else if (AbsolutePosition.Y > Constants.RegionSize)
2834 pos.Y -= Velocity.Y * 2;
2835 Velocity = Vector3.Zero;
2836 AbsolutePosition = pos;
2837
2838 AddToPhysicalScene(isFlying);
2839 }
2840 }
2841 }
2842 }
2843 else
2844 { 3704 {
2845 // This constant has been inferred from experimentation 3705 m_log.DebugFormat("{0} CheckForBorderCrossing: Crossing failed. Restoring old position.", LogHeader);
2846 // I'm not sure what this value should be, so I tried a few values. 3706
2847 timeStep = 0.04f; 3707 Velocity = Vector3.Zero;
2848 pos2 = AbsolutePosition; 3708 AbsolutePosition = EnforceSanityOnPosition(origPosition);
2849 pos2.X = pos2.X + (vel.X * timeStep); 3709
2850 pos2.Y = pos2.Y + (vel.Y * timeStep); 3710 AddToPhysicalScene(isFlying);
2851 // Don't touch the Z
2852 m_pos = pos2;
2853 m_log.DebugFormat("[SCENE PRESENCE]: In transit m_pos={0}", m_pos);
2854 } 3711 }
2855 } 3712 }
3713 }
3714
3715 // Given a position, make sure it is within the current region.
3716 // If just outside some border, the returned position will be just inside the border on that side.
3717 private Vector3 EnforceSanityOnPosition(Vector3 origPosition)
3718 {
3719 const float borderFudge = 0.1f;
3720 Vector3 ret = origPosition;
3721
3722 // Sanity checking on the position to make sure it is in the region we couldn't cross from
3723 float extentX = (float)m_scene.RegionInfo.RegionSizeX;
3724 float extentY = (float)m_scene.RegionInfo.RegionSizeY;
3725 IRegionCombinerModule combiner = m_scene.RequestModuleInterface<IRegionCombinerModule>();
3726 if (combiner != null)
3727 {
3728 // If a mega-region, the size could be much bigger
3729 Vector2 megaExtent = combiner.GetSizeOfMegaregion(m_scene.RegionInfo.RegionID);
3730 extentX = megaExtent.X;
3731 extentY = megaExtent.Y;
3732 }
3733 if (ret.X < 0)
3734 ret.X = borderFudge;
3735 else if (ret.X >= extentX)
3736 ret.X = extentX - borderFudge;
3737 if (ret.Y < 0)
3738 ret.Y = borderFudge;
3739 else if (ret.Y >= extentY)
3740 ret.Y = extentY - borderFudge;
3741
3742 return ret;
2856 } 3743 }
2857 3744
2858 /// <summary> 3745 /// <summary>
@@ -2873,18 +3760,13 @@ namespace OpenSim.Region.Framework.Scenes
2873 } 3760 }
2874 } 3761 }
2875 3762
2876 public void RestoreInCurrentScene()
2877 {
2878 AddToPhysicalScene(false); // not exactly false
2879 }
2880
2881 public void Reset() 3763 public void Reset()
2882 { 3764 {
2883// m_log.DebugFormat("[SCENE PRESENCE]: Resetting {0} in {1}", Name, Scene.RegionInfo.RegionName); 3765// m_log.DebugFormat("[SCENE PRESENCE]: Resetting {0} in {1}", Name, Scene.RegionInfo.RegionName);
2884 3766
2885 // Put the child agent back at the center 3767 // Put the child agent back at the center
2886 AbsolutePosition 3768 AbsolutePosition
2887 = new Vector3(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f), 70); 3769 = new Vector3(((float)m_scene.RegionInfo.RegionSizeX * 0.5f), ((float)m_scene.RegionInfo.RegionSizeY * 0.5f), 70);
2888 3770
2889 Animator.ResetAnimations(); 3771 Animator.ResetAnimations();
2890 } 3772 }
@@ -2911,13 +3793,13 @@ namespace OpenSim.Region.Framework.Scenes
2911 if (handle != Scene.RegionInfo.RegionHandle) 3793 if (handle != Scene.RegionInfo.RegionHandle)
2912 { 3794 {
2913 uint x, y; 3795 uint x, y;
2914 Utils.LongToUInts(handle, out x, out y); 3796 Util.RegionHandleToRegionLoc(handle, out x, out y);
2915 x = x / Constants.RegionSize;
2916 y = y / Constants.RegionSize;
2917 3797
2918// m_log.Debug("---> x: " + x + "; newx:" + newRegionX + "; Abs:" + (int)Math.Abs((int)(x - newRegionX))); 3798// m_log.Debug("---> x: " + x + "; newx:" + newRegionX + "; Abs:" + (int)Math.Abs((int)(x - newRegionX)));
2919// m_log.Debug("---> y: " + y + "; newy:" + newRegionY + "; Abs:" + (int)Math.Abs((int)(y - newRegionY))); 3799// m_log.Debug("---> y: " + y + "; newy:" + newRegionY + "; Abs:" + (int)Math.Abs((int)(y - newRegionY)));
2920 if (Util.IsOutsideView(DrawDistance, x, newRegionX, y, newRegionY)) 3800 float dist = (float)Math.Max(Scene.DefaultDrawDistance,
3801 (float)Math.Max(Scene.RegionInfo.RegionSizeX, Scene.RegionInfo.RegionSizeY));
3802 if (Util.IsOutsideView(dist, x, newRegionX, y, newRegionY))
2921 { 3803 {
2922 byebyeRegions.Add(handle); 3804 byebyeRegions.Add(handle);
2923 } 3805 }
@@ -2927,10 +3809,12 @@ namespace OpenSim.Region.Framework.Scenes
2927 if (byebyeRegions.Count > 0) 3809 if (byebyeRegions.Count > 0)
2928 { 3810 {
2929 m_log.Debug("[SCENE PRESENCE]: Closing " + byebyeRegions.Count + " child agents"); 3811 m_log.Debug("[SCENE PRESENCE]: Closing " + byebyeRegions.Count + " child agents");
2930 Util.FireAndForget(delegate 3812
2931 { 3813 AgentCircuitData acd = Scene.AuthenticateHandler.GetAgentCircuitData(UUID);
2932 m_scene.SceneGridService.SendCloseChildAgentConnections(ControllingClient.AgentId, byebyeRegions); 3814 string auth = string.Empty;
2933 }); 3815 if (acd != null)
3816 auth = acd.SessionID.ToString();
3817 m_scene.SceneGridService.SendCloseChildAgentConnections(ControllingClient.AgentId, auth, byebyeRegions);
2934 } 3818 }
2935 3819
2936 foreach (ulong handle in byebyeRegions) 3820 foreach (ulong handle in byebyeRegions)
@@ -2971,36 +3855,45 @@ namespace OpenSim.Region.Framework.Scenes
2971 3855
2972 #region Child Agent Updates 3856 #region Child Agent Updates
2973 3857
2974 public void ChildAgentDataUpdate(AgentData cAgentData) 3858 public void UpdateChildAgent(AgentData cAgentData)
2975 { 3859 {
2976// m_log.Debug(" >>> ChildAgentDataUpdate <<< " + Scene.RegionInfo.RegionName); 3860// m_log.Debug(" >>> ChildAgentDataUpdate <<< " + Scene.RegionInfo.RegionName);
2977 if (!IsChildAgent) 3861 if (!IsChildAgent)
2978 return; 3862 return;
2979 3863
2980 CopyFrom(cAgentData); 3864 CopyFrom(cAgentData);
3865
3866 m_updateAgentReceivedAfterTransferEvent.Set();
2981 } 3867 }
2982 3868
2983 private static Vector3 marker = new Vector3(-1f, -1f, -1f); 3869 private static Vector3 marker = new Vector3(-1f, -1f, -1f);
3870
2984 /// <summary> 3871 /// <summary>
2985 /// This updates important decision making data about a child agent 3872 /// This updates important decision making data about a child agent
2986 /// The main purpose is to figure out what objects to send to a child agent that's in a neighboring region 3873 /// The main purpose is to figure out what objects to send to a child agent that's in a neighboring region
2987 /// </summary> 3874 /// </summary>
2988 public void ChildAgentDataUpdate(AgentPosition cAgentData, uint tRegionX, uint tRegionY, uint rRegionX, uint rRegionY) 3875 public void UpdateChildAgent(AgentPosition cAgentData, uint tRegionX, uint tRegionY, uint rRegionX, uint rRegionY)
2989 { 3876 {
2990 if (!IsChildAgent) 3877 if (!IsChildAgent)
2991 return; 3878 return;
2992 3879
2993 //m_log.Debug(" >>> ChildAgentPositionUpdate <<< " + rRegionX + "-" + rRegionY); 3880// m_log.DebugFormat(
2994 int shiftx = ((int)rRegionX - (int)tRegionX) * (int)Constants.RegionSize; 3881// "[SCENE PRESENCE]: ChildAgentPositionUpdate for {0} in {1}, tRegion {2},{3}, rRegion {4},{5}, pos {6}",
2995 int shifty = ((int)rRegionY - (int)tRegionY) * (int)Constants.RegionSize; 3882// Name, Scene.Name, tRegionX, tRegionY, rRegionX, rRegionY, cAgentData.Position);
3883
3884 // Find the distance (in meters) between the two regions
3885 // XXX: We cannot use Util.RegionLocToHandle() here because a negative value will silently overflow the
3886 // uint
3887 int shiftx = (int)(((int)rRegionX - (int)tRegionX) * Constants.RegionSize);
3888 int shifty = (int)(((int)rRegionY - (int)tRegionY) * Constants.RegionSize);
2996 3889
2997 Vector3 offset = new Vector3(shiftx, shifty, 0f); 3890 Vector3 offset = new Vector3(shiftx, shifty, 0f);
2998 3891
2999 // When we get to the point of re-computing neighbors everytime this 3892 // When we get to the point of re-computing neighbors everytime this
3000 // changes, then start using the agent's drawdistance rather than the 3893 // changes, then start using the agent's drawdistance rather than the
3001 // region's draw distance. 3894 // region's draw distance.
3002 // DrawDistance = cAgentData.Far; 3895 DrawDistance = cAgentData.Far;
3003 DrawDistance = Scene.DefaultDrawDistance; 3896 // DrawDistance = Scene.DefaultDrawDistance;
3004 3897
3005 if (cAgentData.Position != marker) // UGH!! 3898 if (cAgentData.Position != marker) // UGH!!
3006 m_pos = cAgentData.Position + offset; 3899 m_pos = cAgentData.Position + offset;
@@ -3027,6 +3920,7 @@ namespace OpenSim.Region.Framework.Scenes
3027 3920
3028 cAgent.AgentID = UUID; 3921 cAgent.AgentID = UUID;
3029 cAgent.RegionID = Scene.RegionInfo.RegionID; 3922 cAgent.RegionID = Scene.RegionInfo.RegionID;
3923 cAgent.SessionID = ControllingClient.SessionId;
3030 3924
3031 cAgent.Position = AbsolutePosition; 3925 cAgent.Position = AbsolutePosition;
3032 cAgent.Velocity = m_velocity; 3926 cAgent.Velocity = m_velocity;
@@ -3061,6 +3955,9 @@ namespace OpenSim.Region.Framework.Scenes
3061 cAgent.AlwaysRun = SetAlwaysRun; 3955 cAgent.AlwaysRun = SetAlwaysRun;
3062 3956
3063 cAgent.Appearance = new AvatarAppearance(Appearance); 3957 cAgent.Appearance = new AvatarAppearance(Appearance);
3958
3959 cAgent.ParentPart = ParentUUID;
3960 cAgent.SitOffset = PrevSitOffset;
3064 3961
3065 lock (scriptedcontrols) 3962 lock (scriptedcontrols)
3066 { 3963 {
@@ -3069,7 +3966,7 @@ namespace OpenSim.Region.Framework.Scenes
3069 3966
3070 foreach (ScriptControllers c in scriptedcontrols.Values) 3967 foreach (ScriptControllers c in scriptedcontrols.Values)
3071 { 3968 {
3072 controls[i++] = new ControllerData(c.itemID, (uint)c.ignoreControls, (uint)c.eventControls); 3969 controls[i++] = new ControllerData(c.objectID, c.itemID, (uint)c.ignoreControls, (uint)c.eventControls);
3073 } 3970 }
3074 cAgent.Controllers = controls; 3971 cAgent.Controllers = controls;
3075 } 3972 }
@@ -3089,8 +3986,6 @@ namespace OpenSim.Region.Framework.Scenes
3089 3986
3090 private void CopyFrom(AgentData cAgent) 3987 private void CopyFrom(AgentData cAgent)
3091 { 3988 {
3092 m_originRegionID = cAgent.RegionID;
3093
3094 m_callbackURI = cAgent.CallbackURI; 3989 m_callbackURI = cAgent.CallbackURI;
3095// m_log.DebugFormat( 3990// m_log.DebugFormat(
3096// "[SCENE PRESENCE]: Set callback for {0} in {1} to {2} in CopyFrom()", 3991// "[SCENE PRESENCE]: Set callback for {0} in {1} to {2} in CopyFrom()",
@@ -3102,12 +3997,14 @@ namespace OpenSim.Region.Framework.Scenes
3102 CameraAtAxis = cAgent.AtAxis; 3997 CameraAtAxis = cAgent.AtAxis;
3103 CameraLeftAxis = cAgent.LeftAxis; 3998 CameraLeftAxis = cAgent.LeftAxis;
3104 CameraUpAxis = cAgent.UpAxis; 3999 CameraUpAxis = cAgent.UpAxis;
4000 ParentUUID = cAgent.ParentPart;
4001 PrevSitOffset = cAgent.SitOffset;
3105 4002
3106 // When we get to the point of re-computing neighbors everytime this 4003 // When we get to the point of re-computing neighbors everytime this
3107 // changes, then start using the agent's drawdistance rather than the 4004 // changes, then start using the agent's drawdistance rather than the
3108 // region's draw distance. 4005 // region's draw distance.
3109 // DrawDistance = cAgent.Far; 4006 DrawDistance = cAgent.Far;
3110 DrawDistance = Scene.DefaultDrawDistance; 4007 // DrawDistance = Scene.DefaultDrawDistance;
3111 4008
3112 if ((cAgent.Throttles != null) && cAgent.Throttles.Length > 0) 4009 if ((cAgent.Throttles != null) && cAgent.Throttles.Length > 0)
3113 ControllingClient.SetChildAgentThrottle(cAgent.Throttles); 4010 ControllingClient.SetChildAgentThrottle(cAgent.Throttles);
@@ -3139,6 +4036,7 @@ namespace OpenSim.Region.Framework.Scenes
3139 foreach (ControllerData c in cAgent.Controllers) 4036 foreach (ControllerData c in cAgent.Controllers)
3140 { 4037 {
3141 ScriptControllers sc = new ScriptControllers(); 4038 ScriptControllers sc = new ScriptControllers();
4039 sc.objectID = c.ObjectID;
3142 sc.itemID = c.ItemID; 4040 sc.itemID = c.ItemID;
3143 sc.ignoreControls = (ScriptControlled)c.IgnoreControls; 4041 sc.ignoreControls = (ScriptControlled)c.IgnoreControls;
3144 sc.eventControls = (ScriptControlled)c.EventControls; 4042 sc.eventControls = (ScriptControlled)c.EventControls;
@@ -3159,7 +4057,27 @@ namespace OpenSim.Region.Framework.Scenes
3159 Animator.Animations.SetImplicitDefaultAnimation(cAgent.AnimState.AnimID, cAgent.AnimState.SequenceNum, UUID.Zero); 4057 Animator.Animations.SetImplicitDefaultAnimation(cAgent.AnimState.AnimID, cAgent.AnimState.SequenceNum, UUID.Zero);
3160 4058
3161 if (Scene.AttachmentsModule != null) 4059 if (Scene.AttachmentsModule != null)
3162 Scene.AttachmentsModule.CopyAttachments(cAgent, this); 4060 {
4061 // If the JobEngine is running we can schedule this job now and continue rather than waiting for all
4062 // attachments to copy, which might take a long time in the Hypergrid case as the entire inventory
4063 // graph is inspected for each attachments and assets possibly fetched.
4064 //
4065 // We don't need to worry about a race condition as the job to later start the scripts is also
4066 // JobEngine scheduled and so will always occur after this task.
4067 // XXX: This will not be true if JobEngine ever gets more than one thread.
4068 WorkManager.RunJob(
4069 "CopyAttachments",
4070 o => Scene.AttachmentsModule.CopyAttachments(cAgent, this),
4071 null,
4072 string.Format("Copy attachments for {0} entering {1}", Name, Scene.Name),
4073 true);
4074 }
4075
4076 // This must occur after attachments are copied or scheduled to be copied, as it releases the CompleteMovement() calling thread
4077 // originating from the client completing a teleport. Otherwise, CompleteMovement() code to restart
4078 // script attachments can outrace this thread.
4079 lock (m_originRegionIDAccessLock)
4080 m_originRegionID = cAgent.RegionID;
3163 } 4081 }
3164 4082
3165 public bool CopyAgent(out IAgentData agent) 4083 public bool CopyAgent(out IAgentData agent)
@@ -3180,8 +4098,6 @@ namespace OpenSim.Region.Framework.Scenes
3180 { 4098 {
3181 Vector3 force = m_forceToApply.Value; 4099 Vector3 force = m_forceToApply.Value;
3182 4100
3183 Updated = true;
3184
3185 Velocity = force; 4101 Velocity = force;
3186 4102
3187 m_forceToApply = null; 4103 m_forceToApply = null;
@@ -3206,20 +4122,23 @@ namespace OpenSim.Region.Framework.Scenes
3206 } 4122 }
3207 4123
3208 if (Appearance.AvatarHeight == 0) 4124 if (Appearance.AvatarHeight == 0)
3209 Appearance.SetHeight(); 4125// Appearance.SetHeight();
3210 4126 Appearance.SetSize(new Vector3(0.45f,0.6f,1.9f));
3211 PhysicsScene scene = m_scene.PhysicsScene; 4127
3212 4128/*
3213 Vector3 pVec = AbsolutePosition;
3214
3215 PhysicsActor = scene.AddAvatar( 4129 PhysicsActor = scene.AddAvatar(
3216 LocalId, Firstname + "." + Lastname, pVec, 4130 LocalId, Firstname + "." + Lastname, pVec,
3217 new Vector3(0f, 0f, Appearance.AvatarHeight), isFlying); 4131 new Vector3(0.45f, 0.6f, Appearance.AvatarHeight), isFlying);
4132*/
4133
4134 PhysicsActor = m_scene.PhysicsScene.AddAvatar(
4135 LocalId, Firstname + "." + Lastname, AbsolutePosition, Velocity,
4136 Appearance.AvatarBoxSize, isFlying);
3218 4137
3219 //PhysicsActor.OnRequestTerseUpdate += SendTerseUpdateToAllClients; 4138 //PhysicsActor.OnRequestTerseUpdate += SendTerseUpdateToAllClients;
3220 PhysicsActor.OnCollisionUpdate += PhysicsCollisionUpdate; 4139 PhysicsActor.OnCollisionUpdate += PhysicsCollisionUpdate;
3221 PhysicsActor.OnOutOfBounds += OutOfBoundsCall; // Called for PhysicsActors when there's something wrong 4140 PhysicsActor.OnOutOfBounds += OutOfBoundsCall; // Called for PhysicsActors when there's something wrong
3222 PhysicsActor.SubscribeEvents(500); 4141 PhysicsActor.SubscribeEvents(100);
3223 PhysicsActor.LocalID = LocalId; 4142 PhysicsActor.LocalID = LocalId;
3224 } 4143 }
3225 4144
@@ -3233,6 +4152,7 @@ namespace OpenSim.Region.Framework.Scenes
3233 ControllingClient.SendAgentAlertMessage("Physics is having a problem with your avatar. You may not be able to move until you relog.", true); 4152 ControllingClient.SendAgentAlertMessage("Physics is having a problem with your avatar. You may not be able to move until you relog.", true);
3234 } 4153 }
3235 4154
4155
3236 /// <summary> 4156 /// <summary>
3237 /// Event called by the physics plugin to tell the avatar about a collision. 4157 /// Event called by the physics plugin to tell the avatar about a collision.
3238 /// </summary> 4158 /// </summary>
@@ -3246,7 +4166,7 @@ namespace OpenSim.Region.Framework.Scenes
3246 /// <param name="e"></param> 4166 /// <param name="e"></param>
3247 public void PhysicsCollisionUpdate(EventArgs e) 4167 public void PhysicsCollisionUpdate(EventArgs e)
3248 { 4168 {
3249 if (IsChildAgent) 4169 if (IsChildAgent || Animator == null)
3250 return; 4170 return;
3251 4171
3252 //if ((Math.Abs(Velocity.X) > 0.1e-9f) || (Math.Abs(Velocity.Y) > 0.1e-9f)) 4172 //if ((Math.Abs(Velocity.X) > 0.1e-9f) || (Math.Abs(Velocity.Y) > 0.1e-9f))
@@ -3255,14 +4175,14 @@ namespace OpenSim.Region.Framework.Scenes
3255 4175
3256// if (m_updateCount > 0) 4176// if (m_updateCount > 0)
3257// { 4177// {
3258 Animator.UpdateMovementAnimations(); 4178 if (Animator.UpdateMovementAnimations())
4179 TriggerScenePresenceUpdated();
3259// m_updateCount--; 4180// m_updateCount--;
3260// } 4181// }
3261 4182
3262 CollisionEventUpdate collisionData = (CollisionEventUpdate)e; 4183 CollisionEventUpdate collisionData = (CollisionEventUpdate)e;
3263 Dictionary<uint, ContactPoint> coldata = collisionData.m_objCollisionList; 4184 Dictionary<uint, ContactPoint> coldata = collisionData.m_objCollisionList;
3264 4185
3265 CollisionPlane = Vector4.UnitW;
3266 4186
3267// // No collisions at all means we may be flying. Update always 4187// // No collisions at all means we may be flying. Update always
3268// // to make falling work 4188// // to make falling work
@@ -3272,34 +4192,7 @@ namespace OpenSim.Region.Framework.Scenes
3272// m_lastColCount = coldata.Count; 4192// m_lastColCount = coldata.Count;
3273// } 4193// }
3274 4194
3275 if (coldata.Count != 0) 4195 CollisionPlane = Vector4.UnitW;
3276 {
3277 switch (Animator.CurrentMovementAnimation)
3278 {
3279 case "STAND":
3280 case "WALK":
3281 case "RUN":
3282 case "CROUCH":
3283 case "CROUCHWALK":
3284 {
3285 ContactPoint lowest;
3286 lowest.SurfaceNormal = Vector3.Zero;
3287 lowest.Position = Vector3.Zero;
3288 lowest.Position.Z = Single.NaN;
3289
3290 foreach (ContactPoint contact in coldata.Values)
3291 {
3292 if (Single.IsNaN(lowest.Position.Z) || contact.Position.Z < lowest.Position.Z)
3293 {
3294 lowest = contact;
3295 }
3296 }
3297
3298 CollisionPlane = new Vector4(-lowest.SurfaceNormal, -Vector3.Dot(lowest.Position, lowest.SurfaceNormal));
3299 }
3300 break;
3301 }
3302 }
3303 4196
3304 // Gods do not take damage and Invulnerable is set depending on parcel/region flags 4197 // Gods do not take damage and Invulnerable is set depending on parcel/region flags
3305 if (Invulnerable || GodLevel > 0) 4198 if (Invulnerable || GodLevel > 0)
@@ -3398,6 +4291,14 @@ namespace OpenSim.Region.Framework.Scenes
3398 // m_reprioritizationTimer.Dispose(); 4291 // m_reprioritizationTimer.Dispose();
3399 4292
3400 RemoveFromPhysicalScene(); 4293 RemoveFromPhysicalScene();
4294
4295 m_scene.EventManager.OnRegionHeartbeatEnd -= RegionHeartbeatEnd;
4296
4297// if (Animator != null)
4298// Animator.Close();
4299 Animator = null;
4300
4301 LifecycleState = ScenePresenceState.Removed;
3401 } 4302 }
3402 4303
3403 public void AddAttachment(SceneObjectGroup gobj) 4304 public void AddAttachment(SceneObjectGroup gobj)
@@ -3602,7 +4503,7 @@ namespace OpenSim.Region.Framework.Scenes
3602 } 4503 }
3603 } 4504 }
3604 } 4505 }
3605 }); 4506 }, null, "ScenePresence.SendScriptEventToAttachments");
3606 } 4507 }
3607 4508
3608 /// <summary> 4509 /// <summary>
@@ -3631,10 +4532,18 @@ namespace OpenSim.Region.Framework.Scenes
3631 4532
3632 public void RegisterControlEventsToScript(int controls, int accept, int pass_on, uint Obj_localID, UUID Script_item_UUID) 4533 public void RegisterControlEventsToScript(int controls, int accept, int pass_on, uint Obj_localID, UUID Script_item_UUID)
3633 { 4534 {
4535 SceneObjectPart p = m_scene.GetSceneObjectPart(Obj_localID);
4536 if (p == null)
4537 return;
4538
4539 ControllingClient.SendTakeControls(controls, false, false);
4540 ControllingClient.SendTakeControls(controls, true, false);
4541
3634 ScriptControllers obj = new ScriptControllers(); 4542 ScriptControllers obj = new ScriptControllers();
3635 obj.ignoreControls = ScriptControlled.CONTROL_ZERO; 4543 obj.ignoreControls = ScriptControlled.CONTROL_ZERO;
3636 obj.eventControls = ScriptControlled.CONTROL_ZERO; 4544 obj.eventControls = ScriptControlled.CONTROL_ZERO;
3637 4545
4546 obj.objectID = p.ParentGroup.UUID;
3638 obj.itemID = Script_item_UUID; 4547 obj.itemID = Script_item_UUID;
3639 if (pass_on == 0 && accept == 0) 4548 if (pass_on == 0 && accept == 0)
3640 { 4549 {
@@ -3683,6 +4592,21 @@ namespace OpenSim.Region.Framework.Scenes
3683 ControllingClient.SendTakeControls(int.MaxValue, false, false); 4592 ControllingClient.SendTakeControls(int.MaxValue, false, false);
3684 } 4593 }
3685 4594
4595 private void UnRegisterSeatControls(UUID obj)
4596 {
4597 List<UUID> takers = new List<UUID>();
4598
4599 foreach (ScriptControllers c in scriptedcontrols.Values)
4600 {
4601 if (c.objectID == obj)
4602 takers.Add(c.itemID);
4603 }
4604 foreach (UUID t in takers)
4605 {
4606 UnRegisterControlEventsToScript(0, t);
4607 }
4608 }
4609
3686 public void UnRegisterControlEventsToScript(uint Obj_localID, UUID Script_item_UUID) 4610 public void UnRegisterControlEventsToScript(uint Obj_localID, UUID Script_item_UUID)
3687 { 4611 {
3688 ScriptControllers takecontrols; 4612 ScriptControllers takecontrols;
@@ -3899,6 +4823,7 @@ namespace OpenSim.Region.Framework.Scenes
3899 (m_teleportFlags & TeleportFlags.ViaLocation) != 0 || 4823 (m_teleportFlags & TeleportFlags.ViaLocation) != 0 ||
3900 (m_teleportFlags & Constants.TeleportFlags.ViaHGLogin) != 0) 4824 (m_teleportFlags & Constants.TeleportFlags.ViaHGLogin) != 0)
3901 { 4825 {
4826
3902 if (GodLevel < 200 && 4827 if (GodLevel < 200 &&
3903 ((!m_scene.Permissions.IsGod(m_uuid) && 4828 ((!m_scene.Permissions.IsGod(m_uuid) &&
3904 !m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_uuid)) || 4829 !m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_uuid)) ||
@@ -3907,7 +4832,14 @@ namespace OpenSim.Region.Framework.Scenes
3907 { 4832 {
3908 SpawnPoint[] spawnPoints = m_scene.RegionInfo.RegionSettings.SpawnPoints().ToArray(); 4833 SpawnPoint[] spawnPoints = m_scene.RegionInfo.RegionSettings.SpawnPoints().ToArray();
3909 if (spawnPoints.Length == 0) 4834 if (spawnPoints.Length == 0)
4835 {
4836 if(m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_uuid))
4837 {
4838 pos.X = 128.0f;
4839 pos.Y = 128.0f;
4840 }
3910 return; 4841 return;
4842 }
3911 4843
3912 int index; 4844 int index;
3913 bool selected = false; 4845 bool selected = false;
@@ -3916,6 +4848,8 @@ namespace OpenSim.Region.Framework.Scenes
3916 { 4848 {
3917 case "random": 4849 case "random":
3918 4850
4851 if (spawnPoints.Length == 0)
4852 return;
3919 do 4853 do
3920 { 4854 {
3921 index = Util.RandomClass.Next(spawnPoints.Length - 1); 4855 index = Util.RandomClass.Next(spawnPoints.Length - 1);
@@ -3927,6 +4861,7 @@ namespace OpenSim.Region.Framework.Scenes
3927 // SpawnPoint sp = spawnPoints[index]; 4861 // SpawnPoint sp = spawnPoints[index];
3928 4862
3929 ILandObject land = m_scene.LandChannel.GetLandObject(spawnPosition.X, spawnPosition.Y); 4863 ILandObject land = m_scene.LandChannel.GetLandObject(spawnPosition.X, spawnPosition.Y);
4864
3930 if (land == null || land.IsEitherBannedOrRestricted(UUID)) 4865 if (land == null || land.IsEitherBannedOrRestricted(UUID))
3931 selected = false; 4866 selected = false;
3932 else 4867 else
@@ -3999,8 +4934,15 @@ namespace OpenSim.Region.Framework.Scenes
3999 } 4934 }
4000 } 4935 }
4001 4936
4937 // Modify landing point based on possible banning, telehubs or parcel restrictions.
4002 private void CheckAndAdjustLandingPoint(ref Vector3 pos) 4938 private void CheckAndAdjustLandingPoint(ref Vector3 pos)
4003 { 4939 {
4940 string reason;
4941
4942 // Honor bans
4943 if (!m_scene.TestLandRestrictions(UUID, out reason, ref pos.X, ref pos.Y))
4944 return;
4945
4004 SceneObjectGroup telehub = null; 4946 SceneObjectGroup telehub = null;
4005 if (m_scene.RegionInfo.RegionSettings.TelehubObject != UUID.Zero && (telehub = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject)) != null) 4947 if (m_scene.RegionInfo.RegionSettings.TelehubObject != UUID.Zero && (telehub = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject)) != null)
4006 { 4948 {
@@ -4040,11 +4982,119 @@ namespace OpenSim.Region.Framework.Scenes
4040 pos = land.LandData.UserLocation; 4982 pos = land.LandData.UserLocation;
4041 } 4983 }
4042 } 4984 }
4043 4985
4044 land.SendLandUpdateToClient(ControllingClient); 4986 land.SendLandUpdateToClient(ControllingClient);
4045 } 4987 }
4046 } 4988 }
4047 4989
4990 private DetectedObject CreateDetObject(SceneObjectPart obj)
4991 {
4992 DetectedObject detobj = new DetectedObject();
4993 detobj.keyUUID = obj.UUID;
4994 detobj.nameStr = obj.Name;
4995 detobj.ownerUUID = obj.OwnerID;
4996 detobj.posVector = obj.AbsolutePosition;
4997 detobj.rotQuat = obj.GetWorldRotation();
4998 detobj.velVector = obj.Velocity;
4999 detobj.colliderType = 0;
5000 detobj.groupUUID = obj.GroupID;
5001
5002 return detobj;
5003 }
5004
5005 private DetectedObject CreateDetObject(ScenePresence av)
5006 {
5007 DetectedObject detobj = new DetectedObject();
5008 detobj.keyUUID = av.UUID;
5009 detobj.nameStr = av.ControllingClient.Name;
5010 detobj.ownerUUID = av.UUID;
5011 detobj.posVector = av.AbsolutePosition;
5012 detobj.rotQuat = av.Rotation;
5013 detobj.velVector = av.Velocity;
5014 detobj.colliderType = 0;
5015 detobj.groupUUID = av.ControllingClient.ActiveGroupId;
5016
5017 return detobj;
5018 }
5019
5020 private DetectedObject CreateDetObjectForGround()
5021 {
5022 DetectedObject detobj = new DetectedObject();
5023 detobj.keyUUID = UUID.Zero;
5024 detobj.nameStr = "";
5025 detobj.ownerUUID = UUID.Zero;
5026 detobj.posVector = AbsolutePosition;
5027 detobj.rotQuat = Quaternion.Identity;
5028 detobj.velVector = Vector3.Zero;
5029 detobj.colliderType = 0;
5030 detobj.groupUUID = UUID.Zero;
5031
5032 return detobj;
5033 }
5034
5035 private ColliderArgs CreateColliderArgs(SceneObjectPart dest, List<uint> colliders)
5036 {
5037 ColliderArgs colliderArgs = new ColliderArgs();
5038 List<DetectedObject> colliding = new List<DetectedObject>();
5039 foreach (uint localId in colliders)
5040 {
5041 if (localId == 0)
5042 continue;
5043
5044 SceneObjectPart obj = m_scene.GetSceneObjectPart(localId);
5045 if (obj != null)
5046 {
5047 if (!dest.CollisionFilteredOut(obj.UUID, obj.Name))
5048 colliding.Add(CreateDetObject(obj));
5049 }
5050 else
5051 {
5052 ScenePresence av = m_scene.GetScenePresence(localId);
5053 if (av != null && (!av.IsChildAgent))
5054 {
5055 if (!dest.CollisionFilteredOut(av.UUID, av.Name))
5056 colliding.Add(CreateDetObject(av));
5057 }
5058 }
5059 }
5060
5061 colliderArgs.Colliders = colliding;
5062
5063 return colliderArgs;
5064 }
5065
5066 private delegate void ScriptCollidingNotification(uint localID, ColliderArgs message);
5067
5068 private void SendCollisionEvent(SceneObjectGroup dest, scriptEvents ev, List<uint> colliders, ScriptCollidingNotification notify)
5069 {
5070 ColliderArgs CollidingMessage;
5071
5072 if (colliders.Count > 0)
5073 {
5074 if ((dest.RootPart.ScriptEvents & ev) != 0)
5075 {
5076 CollidingMessage = CreateColliderArgs(dest.RootPart, colliders);
5077
5078 if (CollidingMessage.Colliders.Count > 0)
5079 notify(dest.RootPart.LocalId, CollidingMessage);
5080 }
5081 }
5082 }
5083
5084 private void SendLandCollisionEvent(SceneObjectGroup dest, scriptEvents ev, ScriptCollidingNotification notify)
5085 {
5086 if ((dest.RootPart.ScriptEvents & ev) != 0)
5087 {
5088 ColliderArgs LandCollidingMessage = new ColliderArgs();
5089 List<DetectedObject> colliding = new List<DetectedObject>();
5090
5091 colliding.Add(CreateDetObjectForGround());
5092 LandCollidingMessage.Colliders = colliding;
5093
5094 notify(dest.RootPart.LocalId, LandCollidingMessage);
5095 }
5096 }
5097
4048 private void TeleportFlagsDebug() { 5098 private void TeleportFlagsDebug() {
4049 5099
4050 // Some temporary debugging help to show all the TeleportFlags we have... 5100 // Some temporary debugging help to show all the TeleportFlags we have...
@@ -4069,6 +5119,5 @@ namespace OpenSim.Region.Framework.Scenes
4069 m_log.InfoFormat("[SCENE PRESENCE]: TELEPORT ******************"); 5119 m_log.InfoFormat("[SCENE PRESENCE]: TELEPORT ******************");
4070 5120
4071 } 5121 }
4072
4073 } 5122 }
4074} 5123}
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresenceStateMachine.cs b/OpenSim/Region/Framework/Scenes/ScenePresenceStateMachine.cs
new file mode 100644
index 0000000..cae7fe5
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/ScenePresenceStateMachine.cs
@@ -0,0 +1,113 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29
30namespace OpenSim.Region.Framework.Scenes
31{
32 /// <summary>
33 /// The possible states that a scene presence can be in. This is currently orthagonal to whether a scene presence
34 /// is root or child.
35 /// </summary>
36 /// <remarks>
37 /// This is a state machine.
38 ///
39 /// [Entry] => Running
40 /// Running => PreRemove, Removing
41 /// PreRemove => Running, Removing
42 /// Removing => Removed
43 ///
44 /// All other methods should only see the scene presence in running state - this is the normal operational state
45 /// Removed state occurs when the presence has been removed. This is the end state with no exit.
46 /// </remarks>
47 public enum ScenePresenceState
48 {
49 Running, // Normal operation state. The scene presence is available.
50 PreRemove, // The presence is due to be removed but can still be returning to running.
51 Removing, // The presence is in the process of being removed from the scene via Scene.RemoveClient.
52 Removed, // The presence has been removed from the scene and is effectively dead.
53 // There is no exit from this state.
54 }
55
56 internal class ScenePresenceStateMachine
57 {
58 private ScenePresence m_sp;
59 private ScenePresenceState m_state;
60
61 internal ScenePresenceStateMachine(ScenePresence sp)
62 {
63 m_sp = sp;
64 m_state = ScenePresenceState.Running;
65 }
66
67 internal ScenePresenceState GetState()
68 {
69 return m_state;
70 }
71
72 /// <summary>
73 /// Updates the state of an agent that is already in transit.
74 /// </summary>
75 /// <param name='id'></param>
76 /// <param name='newState'></param>
77 /// <returns></returns>
78 /// <exception cref='Exception'>Illegal transitions will throw an Exception</exception>
79 internal void SetState(ScenePresenceState newState)
80 {
81 bool transitionOkay = false;
82
83 lock (this)
84 {
85 if (newState == m_state)
86 return;
87 else if (newState == ScenePresenceState.Running && m_state == ScenePresenceState.PreRemove)
88 transitionOkay = true;
89 else if (newState == ScenePresenceState.PreRemove && m_state == ScenePresenceState.Running)
90 transitionOkay = true;
91 else if (newState == ScenePresenceState.Removing)
92 {
93 if (m_state == ScenePresenceState.Running || m_state == ScenePresenceState.PreRemove)
94 transitionOkay = true;
95 }
96 else if (newState == ScenePresenceState.Removed && m_state == ScenePresenceState.Removing)
97 transitionOkay = true;
98 }
99
100 if (!transitionOkay)
101 {
102 throw new Exception(
103 string.Format(
104 "Scene presence {0} is not allowed to move from state {1} to new state {2} in {3}",
105 m_sp.Name, m_state, newState, m_sp.Scene.Name));
106 }
107 else
108 {
109 m_state = newState;
110 }
111 }
112 }
113} \ No newline at end of file
diff --git a/OpenSim/Region/Framework/Scenes/Scripting/ScriptEngineInterface.cs b/OpenSim/Region/Framework/Scenes/Scripting/ScriptEngineInterface.cs
deleted file mode 100644
index 812a21c..0000000
--- a/OpenSim/Region/Framework/Scenes/Scripting/ScriptEngineInterface.cs
+++ /dev/null
@@ -1,38 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28//TODO: WHERE TO PLACE THIS?
29
30namespace OpenSim.Region.Framework.Scenes.Scripting
31{
32 public interface ScriptEngineInterface
33 {
34 void InitializeEngine(Scene Sceneworld);
35 void Shutdown();
36// void StartScript(string ScriptID, IScriptHost ObjectID);
37 }
38}
diff --git a/OpenSim/Region/Framework/Scenes/Scripting/ScriptEngineLoader.cs b/OpenSim/Region/Framework/Scenes/Scripting/ScriptEngineLoader.cs
deleted file mode 100644
index c58ccc5..0000000
--- a/OpenSim/Region/Framework/Scenes/Scripting/ScriptEngineLoader.cs
+++ /dev/null
@@ -1,119 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28/* Original code: Tedd Hansen */
29using System;
30using System.IO;
31using System.Reflection;
32using log4net;
33
34namespace OpenSim.Region.Framework.Scenes.Scripting
35{
36 public class ScriptEngineLoader
37 {
38 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
39
40 public ScriptEngineInterface LoadScriptEngine(string EngineName)
41 {
42 ScriptEngineInterface ret = null;
43 try
44 {
45 ret =
46 LoadAndInitAssembly(
47 Path.Combine("ScriptEngines", "OpenSim.Region.ScriptEngine." + EngineName + ".dll"),
48 "OpenSim.Region.ScriptEngine." + EngineName + ".ScriptEngine");
49 }
50 catch (Exception e)
51 {
52 m_log.Error("[ScriptEngine]: " +
53 "Error loading assembly \"" + EngineName + "\": " + e.Message + ", " +
54 e.StackTrace.ToString());
55 }
56 return ret;
57 }
58
59 /// <summary>
60 /// Does actual loading and initialization of script Assembly
61 /// </summary>
62 /// <param name="FreeAppDomain">AppDomain to load script into</param>
63 /// <param name="FileName">FileName of script assembly (.dll)</param>
64 /// <returns></returns>
65 private ScriptEngineInterface LoadAndInitAssembly(string FileName, string NameSpace)
66 {
67 //Common.SendToDebug("Loading ScriptEngine Assembly " + FileName);
68 // Load .Net Assembly (.dll)
69 // Initialize and return it
70
71 // TODO: Add error handling
72
73 Assembly a;
74 //try
75 //{
76
77
78 // Load to default appdomain (temporary)
79 a = Assembly.LoadFrom(FileName);
80 // Load to specified appdomain
81 // TODO: Insert security
82 //a = FreeAppDomain.Load(FileName);
83 //}
84 //catch (Exception e)
85 //{
86 // m_log.Error("[ScriptEngine]: Error loading assembly \String.Empty + FileName + "\": " + e.ToString());
87 //}
88
89
90 //m_log.Debug("Loading: " + FileName);
91 //foreach (Type _t in a.GetTypes())
92 //{
93 // m_log.Debug("Type: " + _t.ToString());
94 //}
95
96 Type t;
97 //try
98 //{
99 t = a.GetType(NameSpace, true);
100 //}
101 //catch (Exception e)
102 //{
103 // m_log.Error("[ScriptEngine]: Error initializing type \String.Empty + NameSpace + "\" from \String.Empty + FileName + "\": " + e.ToString());
104 //}
105
106 ScriptEngineInterface ret;
107 //try
108 //{
109 ret = (ScriptEngineInterface) Activator.CreateInstance(t);
110 //}
111 //catch (Exception e)
112 //{
113 // m_log.Error("[ScriptEngine]: Error initializing type \String.Empty + NameSpace + "\" from \String.Empty + FileName + "\": " + e.ToString());
114 //}
115
116 return ret;
117 }
118 }
119}
diff --git a/OpenSim/Region/Framework/Scenes/Scripting/ScriptUtils.cs b/OpenSim/Region/Framework/Scenes/Scripting/ScriptUtils.cs
new file mode 100644
index 0000000..f08ba59
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/Scripting/ScriptUtils.cs
@@ -0,0 +1,107 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using OpenMetaverse;
31using OpenSim.Framework;
32
33namespace OpenSim.Region.Framework.Scenes.Scripting
34{
35 /// <summary>
36 /// Utility functions for use by scripts manipulating the scene.
37 /// </summary>
38 public static class ScriptUtils
39 {
40 /// <summary>
41 /// Get an asset id given an item name and an item type.
42 /// </summary>
43 /// <returns>UUID.Zero if the name and type did not match any item.</returns>
44 /// <param name='part'></param>
45 /// <param name='name'></param>
46 /// <param name='type'></param>
47 public static UUID GetAssetIdFromItemName(SceneObjectPart part, string name, int type)
48 {
49 TaskInventoryItem item = part.Inventory.GetInventoryItem(name);
50
51 if (item != null && item.Type == type)
52 return item.AssetID;
53 else
54 return UUID.Zero;
55 }
56
57 /// <summary>
58 /// accepts a valid UUID, -or- a name of an inventory item.
59 /// Returns a valid UUID or UUID.Zero if key invalid and item not found
60 /// in prim inventory.
61 /// </summary>
62 /// <param name="part">Scene object part to search for inventory item</param>
63 /// <param name="key"></param>
64 /// <returns></returns>
65 public static UUID GetAssetIdFromKeyOrItemName(SceneObjectPart part, string identifier)
66 {
67 UUID key;
68
69 // if we can parse the string as a key, use it.
70 // else try to locate the name in inventory of object. found returns key,
71 // not found returns UUID.Zero
72 if (!UUID.TryParse(identifier, out key))
73 {
74 TaskInventoryItem item = part.Inventory.GetInventoryItem(identifier);
75
76 if (item != null)
77 key = item.AssetID;
78 else
79 key = UUID.Zero;
80 }
81
82 return key;
83 }
84
85 /// <summary>
86 /// Return the UUID of the asset matching the specified key or name
87 /// and asset type.
88 /// </summary>
89 /// <param name="part">Scene object part to search for inventory item</param>
90 /// <param name="identifier"></param>
91 /// <param name="type"></param>
92 /// <returns></returns>
93 public static UUID GetAssetIdFromKeyOrItemName(SceneObjectPart part, string identifier, AssetType type)
94 {
95 UUID key;
96
97 if (!UUID.TryParse(identifier, out key))
98 {
99 TaskInventoryItem item = part.Inventory.GetInventoryItem(identifier);
100 if (item != null && item.Type == (int)type)
101 key = item.AssetID;
102 }
103
104 return key;
105 }
106 }
107} \ No newline at end of file
diff --git a/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs
index 5cb271d..998789d 100644
--- a/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs
+++ b/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs
@@ -119,21 +119,22 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
119 return output; 119 return output;
120 } 120 }
121 } 121 }
122 122
123 public static bool TryFromXml(string xml, out CoalescedSceneObjects coa) 123 public static bool TryFromXml(string xml, out CoalescedSceneObjects coa)
124 { 124 {
125// m_log.DebugFormat("[COALESCED SCENE OBJECTS SERIALIZER]: TryFromXml() deserializing {0}", xml); 125// m_log.DebugFormat("[COALESCED SCENE OBJECTS SERIALIZER]: TryFromXml() deserializing {0}", xml);
126 126
127 coa = null; 127 coa = null;
128 int i = 0;
129 128
130 using (StringReader sr = new StringReader(xml)) 129 try
131 { 130 {
132 using (XmlTextReader reader = new XmlTextReader(sr)) 131 // Quickly check if this is a coalesced object, without fully parsing the XML
133 { 132 using (StringReader sr = new StringReader(xml))
134 try 133 {
134 using (XmlTextReader reader = new XmlTextReader(sr))
135 { 135 {
136 reader.Read(); 136 reader.MoveToContent(); // skip possible xml declaration
137
137 if (reader.Name != "CoalescedObject") 138 if (reader.Name != "CoalescedObject")
138 { 139 {
139 // m_log.DebugFormat( 140 // m_log.DebugFormat(
@@ -142,49 +143,47 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
142 143
143 return false; 144 return false;
144 } 145 }
145 146 }
146 coa = new CoalescedSceneObjects(UUID.Zero); 147 }
147 reader.Read();
148
149 while (reader.NodeType != XmlNodeType.EndElement && reader.Name != "CoalescedObject")
150 {
151 if (reader.Name == "SceneObjectGroup")
152 {
153 string soXml = reader.ReadOuterXml();
154
155 SceneObjectGroup so = SceneObjectSerializer.FromOriginalXmlFormat(soXml);
156
157 if (so != null)
158 {
159 coa.Add(so);
160 }
161 else
162 {
163 // XXX: Possibly we should fail outright here rather than continuing if a particular component of the
164 // coalesced object fails to load.
165 m_log.WarnFormat(
166 "[COALESCED SCENE OBJECTS SERIALIZER]: Deserialization of xml for component {0} failed. Continuing.",
167 i);
168 }
169 148
170 i++; 149 XmlDocument doc = new XmlDocument();
171 } 150 doc.LoadXml(xml);
172 } 151 XmlElement e = (XmlElement)doc.SelectSingleNode("/CoalescedObject");
152 if (e == null)
153 return false;
173 154
174 reader.ReadEndElement(); // CoalescedObject 155 coa = new CoalescedSceneObjects(UUID.Zero);
156
157 XmlNodeList groups = e.SelectNodes("SceneObjectGroup");
158 int i = 0;
159
160 foreach (XmlNode n in groups)
161 {
162 SceneObjectGroup so = SceneObjectSerializer.FromOriginalXmlFormat(n.OuterXml);
163 if (so != null)
164 {
165 coa.Add(so);
175 } 166 }
176 catch (Exception e) 167 else
177 { 168 {
178 m_log.ErrorFormat( 169 // XXX: Possibly we should fail outright here rather than continuing if a particular component of the
179 "[COALESCED SCENE OBJECTS SERIALIZER]: Deserialization of xml failed with {0} {1}", 170 // coalesced object fails to load.
180 e.Message, e.StackTrace); 171 m_log.WarnFormat(
181 172 "[COALESCED SCENE OBJECTS SERIALIZER]: Deserialization of xml for component {0} failed. Continuing.",
182 return false; 173 i);
183 } 174 }
175
176 i++;
184 } 177 }
185 } 178 }
179 catch (Exception e)
180 {
181 m_log.Error("[COALESCED SCENE OBJECTS SERIALIZER]: Deserialization of xml failed ", e);
182 Util.LogFailedXML("[COALESCED SCENE OBJECTS SERIALIZER]:", xml);
183 return false;
184 }
186 185
187 return true; 186 return true;
188 } 187 }
189 } 188 }
190} \ No newline at end of file 189}
diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs
index 2d4c60a..4caa9cb 100644
--- a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs
+++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs
@@ -38,6 +38,7 @@ using OpenSim.Framework;
38using OpenSim.Framework.Serialization.External; 38using OpenSim.Framework.Serialization.External;
39using OpenSim.Region.Framework.Interfaces; 39using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Region.Framework.Scenes; 40using OpenSim.Region.Framework.Scenes;
41using OpenSim.Services.Interfaces;
41 42
42namespace OpenSim.Region.Framework.Scenes.Serialization 43namespace OpenSim.Region.Framework.Scenes.Serialization
43{ 44{
@@ -51,7 +52,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
51 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 52 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
52 53
53 private static IUserManagement m_UserManagement; 54 private static IUserManagement m_UserManagement;
54 55
55 /// <summary> 56 /// <summary>
56 /// Deserialize a scene object from the original xml format 57 /// Deserialize a scene object from the original xml format
57 /// </summary> 58 /// </summary>
@@ -59,57 +60,62 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
59 /// <returns>The scene object deserialized. Null on failure.</returns> 60 /// <returns>The scene object deserialized. Null on failure.</returns>
60 public static SceneObjectGroup FromOriginalXmlFormat(string xmlData) 61 public static SceneObjectGroup FromOriginalXmlFormat(string xmlData)
61 { 62 {
62 //m_log.DebugFormat("[SOG]: Starting deserialization of SOG"); 63 String fixedData = ExternalRepresentationUtils.SanitizeXml(xmlData);
63 //int time = System.Environment.TickCount; 64 using (XmlTextReader wrappedReader = new XmlTextReader(fixedData, XmlNodeType.Element, null))
64
65 try
66 { 65 {
67 StringReader sr; 66 using (XmlReader reader = XmlReader.Create(wrappedReader, new XmlReaderSettings() { IgnoreWhitespace = true, ConformanceLevel = ConformanceLevel.Fragment }))
68 XmlTextReader reader; 67 {
69 XmlNodeList parts; 68 try {
70 XmlDocument doc; 69 return FromOriginalXmlFormat(reader);
71 int linkNum; 70 }
72 71 catch (Exception e)
73 doc = new XmlDocument(); 72 {
74 doc.LoadXml(xmlData); 73 m_log.Error("[SERIALIZER]: Deserialization of xml failed ", e);
75 parts = doc.GetElementsByTagName("RootPart"); 74 Util.LogFailedXML("[SERIALIZER]:", fixedData);
75 return null;
76 }
77 }
78 }
79 }
76 80
77 if (parts.Count == 0) 81 /// <summary>
78 throw new Exception("Invalid Xml format - no root part"); 82 /// Deserialize a scene object from the original xml format
83 /// </summary>
84 /// <param name="xmlData"></param>
85 /// <returns>The scene object deserialized. Null on failure.</returns>
86 public static SceneObjectGroup FromOriginalXmlFormat(XmlReader reader)
87 {
88 //m_log.DebugFormat("[SOG]: Starting deserialization of SOG");
89 //int time = System.Environment.TickCount;
79 90
80 sr = new StringReader(parts[0].InnerXml); 91 int linkNum;
81 reader = new XmlTextReader(sr);
82 SceneObjectGroup sceneObject = new SceneObjectGroup(SceneObjectPart.FromXml(reader));
83 reader.Close();
84 sr.Close();
85 92
86 parts = doc.GetElementsByTagName("Part"); 93 reader.ReadToFollowing("RootPart");
94 reader.ReadToFollowing("SceneObjectPart");
95 SceneObjectGroup sceneObject = new SceneObjectGroup(SceneObjectPart.FromXml(reader));
96 reader.ReadToFollowing("OtherParts");
87 97
88 for (int i = 0; i < parts.Count; i++) 98 if (reader.ReadToDescendant("Part"))
99 {
100 do
89 { 101 {
90 sr = new StringReader(parts[i].InnerXml); 102 if (reader.ReadToDescendant("SceneObjectPart"))
91 reader = new XmlTextReader(sr); 103 {
92 SceneObjectPart part = SceneObjectPart.FromXml(reader); 104 SceneObjectPart part = SceneObjectPart.FromXml(reader);
93 linkNum = part.LinkNum; 105 linkNum = part.LinkNum;
94 sceneObject.AddPart(part); 106 sceneObject.AddPart(part);
95 part.LinkNum = linkNum; 107 part.LinkNum = linkNum;
96 part.TrimPermissions(); 108 part.TrimPermissions();
97 reader.Close(); 109 }
98 sr.Close(); 110 }
99 } 111 while (reader.ReadToNextSibling("Part"));
112 }
100 113
101 // Script state may, or may not, exist. Not having any, is NOT 114 // Script state may, or may not, exist. Not having any, is NOT
102 // ever a problem. 115 // ever a problem.
103 sceneObject.LoadScriptState(doc); 116 sceneObject.LoadScriptState(reader);
104 117
105 return sceneObject; 118 return sceneObject;
106 }
107 catch (Exception e)
108 {
109 m_log.ErrorFormat(
110 "[SERIALIZER]: Deserialization of xml failed with {0}. xml was {1}", e, xmlData);
111 return null;
112 }
113 } 119 }
114 120
115 /// <summary> 121 /// <summary>
@@ -232,7 +238,8 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
232 238
233 if (parts.Count == 0) 239 if (parts.Count == 0)
234 { 240 {
235 m_log.ErrorFormat("[SERIALIZER]: Deserialization of xml failed: No SceneObjectPart nodes. xml was " + xmlData); 241 m_log.Error("[SERIALIZER]: Deserialization of xml failed: No SceneObjectPart nodes");
242 Util.LogFailedXML("[SERIALIZER]:", xmlData);
236 return null; 243 return null;
237 } 244 }
238 245
@@ -262,6 +269,12 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
262 sr.Close(); 269 sr.Close();
263 } 270 }
264 271
272 XmlNodeList keymotion = doc.GetElementsByTagName("KeyframeMotion");
273 if (keymotion.Count > 0)
274 sceneObject.RootPart.KeyframeMotion = KeyframeMotion.FromData(sceneObject, Convert.FromBase64String(keymotion[0].InnerText));
275 else
276 sceneObject.RootPart.KeyframeMotion = null;
277
265 // Script state may, or may not, exist. Not having any, is NOT 278 // Script state may, or may not, exist. Not having any, is NOT
266 // ever a problem. 279 // ever a problem.
267 sceneObject.LoadScriptState(doc); 280 sceneObject.LoadScriptState(doc);
@@ -270,7 +283,8 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
270 } 283 }
271 catch (Exception e) 284 catch (Exception e)
272 { 285 {
273 m_log.ErrorFormat("[SERIALIZER]: Deserialization of xml failed with {0}. xml was {1}", e, xmlData); 286 m_log.Error("[SERIALIZER]: Deserialization of xml failed ", e);
287 Util.LogFailedXML("[SERIALIZER]:", xmlData);
274 return null; 288 return null;
275 } 289 }
276 } 290 }
@@ -293,17 +307,84 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
293 } 307 }
294 } 308 }
295 309
310
311 /// <summary>
312 /// Modifies a SceneObjectGroup.
313 /// </summary>
314 /// <param name="sog">The object</param>
315 /// <returns>Whether the object was actually modified</returns>
316 public delegate bool SceneObjectModifier(SceneObjectGroup sog);
317
318 /// <summary>
319 /// Modifies an object by deserializing it; applying 'modifier' to each SceneObjectGroup; and reserializing.
320 /// </summary>
321 /// <param name="assetId">The object's UUID</param>
322 /// <param name="data">Serialized data</param>
323 /// <param name="modifier">The function to run on each SceneObjectGroup</param>
324 /// <returns>The new serialized object's data, or null if an error occurred</returns>
325 public static byte[] ModifySerializedObject(UUID assetId, byte[] data, SceneObjectModifier modifier)
326 {
327 List<SceneObjectGroup> sceneObjects = new List<SceneObjectGroup>();
328 CoalescedSceneObjects coa = null;
329
330 string xmlData = ExternalRepresentationUtils.SanitizeXml(Utils.BytesToString(data));
331
332 if (CoalescedSceneObjectsSerializer.TryFromXml(xmlData, out coa))
333 {
334 // m_log.DebugFormat("[SERIALIZER]: Loaded coalescence {0} has {1} objects", assetId, coa.Count);
335
336 if (coa.Objects.Count == 0)
337 {
338 m_log.WarnFormat("[SERIALIZER]: Aborting load of coalesced object from asset {0} as it has zero loaded components", assetId);
339 return null;
340 }
341
342 sceneObjects.AddRange(coa.Objects);
343 }
344 else
345 {
346 SceneObjectGroup deserializedObject = FromOriginalXmlFormat(xmlData);
347
348 if (deserializedObject != null)
349 {
350 sceneObjects.Add(deserializedObject);
351 }
352 else
353 {
354 m_log.WarnFormat("[SERIALIZER]: Aborting load of object from asset {0} as deserialization failed", assetId);
355 return null;
356 }
357 }
358
359 bool modified = false;
360 foreach (SceneObjectGroup sog in sceneObjects)
361 {
362 if (modifier(sog))
363 modified = true;
364 }
365
366 if (modified)
367 {
368 if (coa != null)
369 data = Utils.StringToBytes(CoalescedSceneObjectsSerializer.ToXml(coa));
370 else
371 data = Utils.StringToBytes(ToOriginalXmlFormat(sceneObjects[0]));
372 }
373
374 return data;
375 }
376
296 377
297 #region manual serialization 378 #region manual serialization
298 379
299 private static Dictionary<string, Action<SceneObjectPart, XmlTextReader>> m_SOPXmlProcessors 380 private static Dictionary<string, Action<SceneObjectPart, XmlReader>> m_SOPXmlProcessors
300 = new Dictionary<string, Action<SceneObjectPart, XmlTextReader>>(); 381 = new Dictionary<string, Action<SceneObjectPart, XmlReader>>();
301 382
302 private static Dictionary<string, Action<TaskInventoryItem, XmlTextReader>> m_TaskInventoryXmlProcessors 383 private static Dictionary<string, Action<TaskInventoryItem, XmlReader>> m_TaskInventoryXmlProcessors
303 = new Dictionary<string, Action<TaskInventoryItem, XmlTextReader>>(); 384 = new Dictionary<string, Action<TaskInventoryItem, XmlReader>>();
304 385
305 private static Dictionary<string, Action<PrimitiveBaseShape, XmlTextReader>> m_ShapeXmlProcessors 386 private static Dictionary<string, Action<PrimitiveBaseShape, XmlReader>> m_ShapeXmlProcessors
306 = new Dictionary<string, Action<PrimitiveBaseShape, XmlTextReader>>(); 387 = new Dictionary<string, Action<PrimitiveBaseShape, XmlReader>>();
307 388
308 static SceneObjectSerializer() 389 static SceneObjectSerializer()
309 { 390 {
@@ -359,6 +440,8 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
359 m_SOPXmlProcessors.Add("CollisionSound", ProcessCollisionSound); 440 m_SOPXmlProcessors.Add("CollisionSound", ProcessCollisionSound);
360 m_SOPXmlProcessors.Add("CollisionSoundVolume", ProcessCollisionSoundVolume); 441 m_SOPXmlProcessors.Add("CollisionSoundVolume", ProcessCollisionSoundVolume);
361 m_SOPXmlProcessors.Add("MediaUrl", ProcessMediaUrl); 442 m_SOPXmlProcessors.Add("MediaUrl", ProcessMediaUrl);
443 m_SOPXmlProcessors.Add("AttachedPos", ProcessAttachedPos);
444 m_SOPXmlProcessors.Add("DynAttrs", ProcessDynAttrs);
362 m_SOPXmlProcessors.Add("TextureAnimation", ProcessTextureAnimation); 445 m_SOPXmlProcessors.Add("TextureAnimation", ProcessTextureAnimation);
363 m_SOPXmlProcessors.Add("ParticleSystem", ProcessParticleSystem); 446 m_SOPXmlProcessors.Add("ParticleSystem", ProcessParticleSystem);
364 m_SOPXmlProcessors.Add("PayPrice0", ProcessPayPrice0); 447 m_SOPXmlProcessors.Add("PayPrice0", ProcessPayPrice0);
@@ -366,6 +449,13 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
366 m_SOPXmlProcessors.Add("PayPrice2", ProcessPayPrice2); 449 m_SOPXmlProcessors.Add("PayPrice2", ProcessPayPrice2);
367 m_SOPXmlProcessors.Add("PayPrice3", ProcessPayPrice3); 450 m_SOPXmlProcessors.Add("PayPrice3", ProcessPayPrice3);
368 m_SOPXmlProcessors.Add("PayPrice4", ProcessPayPrice4); 451 m_SOPXmlProcessors.Add("PayPrice4", ProcessPayPrice4);
452
453 m_SOPXmlProcessors.Add("PhysicsShapeType", ProcessPhysicsShapeType);
454 m_SOPXmlProcessors.Add("Density", ProcessDensity);
455 m_SOPXmlProcessors.Add("Friction", ProcessFriction);
456 m_SOPXmlProcessors.Add("Bounce", ProcessBounce);
457 m_SOPXmlProcessors.Add("GravityModifier", ProcessGravityModifier);
458
369 #endregion 459 #endregion
370 460
371 #region TaskInventoryXmlProcessors initialization 461 #region TaskInventoryXmlProcessors initialization
@@ -419,12 +509,13 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
419 m_ShapeXmlProcessors.Add("ProfileEnd", ProcessShpProfileEnd); 509 m_ShapeXmlProcessors.Add("ProfileEnd", ProcessShpProfileEnd);
420 m_ShapeXmlProcessors.Add("ProfileHollow", ProcessShpProfileHollow); 510 m_ShapeXmlProcessors.Add("ProfileHollow", ProcessShpProfileHollow);
421 m_ShapeXmlProcessors.Add("Scale", ProcessShpScale); 511 m_ShapeXmlProcessors.Add("Scale", ProcessShpScale);
512 m_ShapeXmlProcessors.Add("LastAttachPoint", ProcessShpLastAttach);
422 m_ShapeXmlProcessors.Add("State", ProcessShpState); 513 m_ShapeXmlProcessors.Add("State", ProcessShpState);
423 m_ShapeXmlProcessors.Add("ProfileShape", ProcessShpProfileShape); 514 m_ShapeXmlProcessors.Add("ProfileShape", ProcessShpProfileShape);
424 m_ShapeXmlProcessors.Add("HollowShape", ProcessShpHollowShape); 515 m_ShapeXmlProcessors.Add("HollowShape", ProcessShpHollowShape);
425 m_ShapeXmlProcessors.Add("SculptTexture", ProcessShpSculptTexture); 516 m_ShapeXmlProcessors.Add("SculptTexture", ProcessShpSculptTexture);
426 m_ShapeXmlProcessors.Add("SculptType", ProcessShpSculptType); 517 m_ShapeXmlProcessors.Add("SculptType", ProcessShpSculptType);
427 m_ShapeXmlProcessors.Add("SculptData", ProcessShpSculptData); 518 // Ignore "SculptData"; this element is deprecated
428 m_ShapeXmlProcessors.Add("FlexiSoftness", ProcessShpFlexiSoftness); 519 m_ShapeXmlProcessors.Add("FlexiSoftness", ProcessShpFlexiSoftness);
429 m_ShapeXmlProcessors.Add("FlexiTension", ProcessShpFlexiTension); 520 m_ShapeXmlProcessors.Add("FlexiTension", ProcessShpFlexiTension);
430 m_ShapeXmlProcessors.Add("FlexiDrag", ProcessShpFlexiDrag); 521 m_ShapeXmlProcessors.Add("FlexiDrag", ProcessShpFlexiDrag);
@@ -449,112 +540,112 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
449 } 540 }
450 541
451 #region SOPXmlProcessors 542 #region SOPXmlProcessors
452 private static void ProcessAllowedDrop(SceneObjectPart obj, XmlTextReader reader) 543 private static void ProcessAllowedDrop(SceneObjectPart obj, XmlReader reader)
453 { 544 {
454 obj.AllowedDrop = Util.ReadBoolean(reader); 545 obj.AllowedDrop = Util.ReadBoolean(reader);
455 } 546 }
456 547
457 private static void ProcessCreatorID(SceneObjectPart obj, XmlTextReader reader) 548 private static void ProcessCreatorID(SceneObjectPart obj, XmlReader reader)
458 { 549 {
459 obj.CreatorID = Util.ReadUUID(reader, "CreatorID"); 550 obj.CreatorID = Util.ReadUUID(reader, "CreatorID");
460 } 551 }
461 552
462 private static void ProcessCreatorData(SceneObjectPart obj, XmlTextReader reader) 553 private static void ProcessCreatorData(SceneObjectPart obj, XmlReader reader)
463 { 554 {
464 obj.CreatorData = reader.ReadElementContentAsString("CreatorData", String.Empty); 555 obj.CreatorData = reader.ReadElementContentAsString("CreatorData", String.Empty);
465 } 556 }
466 557
467 private static void ProcessFolderID(SceneObjectPart obj, XmlTextReader reader) 558 private static void ProcessFolderID(SceneObjectPart obj, XmlReader reader)
468 { 559 {
469 obj.FolderID = Util.ReadUUID(reader, "FolderID"); 560 obj.FolderID = Util.ReadUUID(reader, "FolderID");
470 } 561 }
471 562
472 private static void ProcessInventorySerial(SceneObjectPart obj, XmlTextReader reader) 563 private static void ProcessInventorySerial(SceneObjectPart obj, XmlReader reader)
473 { 564 {
474 obj.InventorySerial = (uint)reader.ReadElementContentAsInt("InventorySerial", String.Empty); 565 obj.InventorySerial = (uint)reader.ReadElementContentAsInt("InventorySerial", String.Empty);
475 } 566 }
476 567
477 private static void ProcessTaskInventory(SceneObjectPart obj, XmlTextReader reader) 568 private static void ProcessTaskInventory(SceneObjectPart obj, XmlReader reader)
478 { 569 {
479 obj.TaskInventory = ReadTaskInventory(reader, "TaskInventory"); 570 obj.TaskInventory = ReadTaskInventory(reader, "TaskInventory");
480 } 571 }
481 572
482 private static void ProcessUUID(SceneObjectPart obj, XmlTextReader reader) 573 private static void ProcessUUID(SceneObjectPart obj, XmlReader reader)
483 { 574 {
484 obj.UUID = Util.ReadUUID(reader, "UUID"); 575 obj.UUID = Util.ReadUUID(reader, "UUID");
485 } 576 }
486 577
487 private static void ProcessLocalId(SceneObjectPart obj, XmlTextReader reader) 578 private static void ProcessLocalId(SceneObjectPart obj, XmlReader reader)
488 { 579 {
489 obj.LocalId = (uint)reader.ReadElementContentAsLong("LocalId", String.Empty); 580 obj.LocalId = (uint)reader.ReadElementContentAsLong("LocalId", String.Empty);
490 } 581 }
491 582
492 private static void ProcessName(SceneObjectPart obj, XmlTextReader reader) 583 private static void ProcessName(SceneObjectPart obj, XmlReader reader)
493 { 584 {
494 obj.Name = reader.ReadElementString("Name"); 585 obj.Name = reader.ReadElementString("Name");
495 } 586 }
496 587
497 private static void ProcessMaterial(SceneObjectPart obj, XmlTextReader reader) 588 private static void ProcessMaterial(SceneObjectPart obj, XmlReader reader)
498 { 589 {
499 obj.Material = (byte)reader.ReadElementContentAsInt("Material", String.Empty); 590 obj.Material = (byte)reader.ReadElementContentAsInt("Material", String.Empty);
500 } 591 }
501 592
502 private static void ProcessPassTouches(SceneObjectPart obj, XmlTextReader reader) 593 private static void ProcessPassTouches(SceneObjectPart obj, XmlReader reader)
503 { 594 {
504 obj.PassTouches = Util.ReadBoolean(reader); 595 obj.PassTouches = Util.ReadBoolean(reader);
505 } 596 }
506 597
507 private static void ProcessPassCollisions(SceneObjectPart obj, XmlTextReader reader) 598 private static void ProcessPassCollisions(SceneObjectPart obj, XmlReader reader)
508 { 599 {
509 obj.PassCollisions = Util.ReadBoolean(reader); 600 obj.PassCollisions = Util.ReadBoolean(reader);
510 } 601 }
511 602
512 private static void ProcessRegionHandle(SceneObjectPart obj, XmlTextReader reader) 603 private static void ProcessRegionHandle(SceneObjectPart obj, XmlReader reader)
513 { 604 {
514 obj.RegionHandle = (ulong)reader.ReadElementContentAsLong("RegionHandle", String.Empty); 605 obj.RegionHandle = (ulong)reader.ReadElementContentAsLong("RegionHandle", String.Empty);
515 } 606 }
516 607
517 private static void ProcessScriptAccessPin(SceneObjectPart obj, XmlTextReader reader) 608 private static void ProcessScriptAccessPin(SceneObjectPart obj, XmlReader reader)
518 { 609 {
519 obj.ScriptAccessPin = reader.ReadElementContentAsInt("ScriptAccessPin", String.Empty); 610 obj.ScriptAccessPin = reader.ReadElementContentAsInt("ScriptAccessPin", String.Empty);
520 } 611 }
521 612
522 private static void ProcessGroupPosition(SceneObjectPart obj, XmlTextReader reader) 613 private static void ProcessGroupPosition(SceneObjectPart obj, XmlReader reader)
523 { 614 {
524 obj.GroupPosition = Util.ReadVector(reader, "GroupPosition"); 615 obj.GroupPosition = Util.ReadVector(reader, "GroupPosition");
525 } 616 }
526 617
527 private static void ProcessOffsetPosition(SceneObjectPart obj, XmlTextReader reader) 618 private static void ProcessOffsetPosition(SceneObjectPart obj, XmlReader reader)
528 { 619 {
529 obj.OffsetPosition = Util.ReadVector(reader, "OffsetPosition"); ; 620 obj.OffsetPosition = Util.ReadVector(reader, "OffsetPosition"); ;
530 } 621 }
531 622
532 private static void ProcessRotationOffset(SceneObjectPart obj, XmlTextReader reader) 623 private static void ProcessRotationOffset(SceneObjectPart obj, XmlReader reader)
533 { 624 {
534 obj.RotationOffset = Util.ReadQuaternion(reader, "RotationOffset"); 625 obj.RotationOffset = Util.ReadQuaternion(reader, "RotationOffset");
535 } 626 }
536 627
537 private static void ProcessVelocity(SceneObjectPart obj, XmlTextReader reader) 628 private static void ProcessVelocity(SceneObjectPart obj, XmlReader reader)
538 { 629 {
539 obj.Velocity = Util.ReadVector(reader, "Velocity"); 630 obj.Velocity = Util.ReadVector(reader, "Velocity");
540 } 631 }
541 632
542 private static void ProcessAngularVelocity(SceneObjectPart obj, XmlTextReader reader) 633 private static void ProcessAngularVelocity(SceneObjectPart obj, XmlReader reader)
543 { 634 {
544 obj.AngularVelocity = Util.ReadVector(reader, "AngularVelocity"); 635 obj.AngularVelocity = Util.ReadVector(reader, "AngularVelocity");
545 } 636 }
546 637
547 private static void ProcessAcceleration(SceneObjectPart obj, XmlTextReader reader) 638 private static void ProcessAcceleration(SceneObjectPart obj, XmlReader reader)
548 { 639 {
549 obj.Acceleration = Util.ReadVector(reader, "Acceleration"); 640 obj.Acceleration = Util.ReadVector(reader, "Acceleration");
550 } 641 }
551 642
552 private static void ProcessDescription(SceneObjectPart obj, XmlTextReader reader) 643 private static void ProcessDescription(SceneObjectPart obj, XmlReader reader)
553 { 644 {
554 obj.Description = reader.ReadElementString("Description"); 645 obj.Description = reader.ReadElementString("Description");
555 } 646 }
556 647
557 private static void ProcessColor(SceneObjectPart obj, XmlTextReader reader) 648 private static void ProcessColor(SceneObjectPart obj, XmlReader reader)
558 { 649 {
559 reader.ReadStartElement("Color"); 650 reader.ReadStartElement("Color");
560 if (reader.Name == "R") 651 if (reader.Name == "R")
@@ -568,35 +659,60 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
568 } 659 }
569 } 660 }
570 661
571 private static void ProcessText(SceneObjectPart obj, XmlTextReader reader) 662 private static void ProcessText(SceneObjectPart obj, XmlReader reader)
572 { 663 {
573 obj.Text = reader.ReadElementString("Text", String.Empty); 664 obj.Text = reader.ReadElementString("Text", String.Empty);
574 } 665 }
575 666
576 private static void ProcessSitName(SceneObjectPart obj, XmlTextReader reader) 667 private static void ProcessSitName(SceneObjectPart obj, XmlReader reader)
577 { 668 {
578 obj.SitName = reader.ReadElementString("SitName", String.Empty); 669 obj.SitName = reader.ReadElementString("SitName", String.Empty);
579 } 670 }
580 671
581 private static void ProcessTouchName(SceneObjectPart obj, XmlTextReader reader) 672 private static void ProcessTouchName(SceneObjectPart obj, XmlReader reader)
582 { 673 {
583 obj.TouchName = reader.ReadElementString("TouchName", String.Empty); 674 obj.TouchName = reader.ReadElementString("TouchName", String.Empty);
584 } 675 }
585 676
586 private static void ProcessLinkNum(SceneObjectPart obj, XmlTextReader reader) 677 private static void ProcessLinkNum(SceneObjectPart obj, XmlReader reader)
587 { 678 {
588 obj.LinkNum = reader.ReadElementContentAsInt("LinkNum", String.Empty); 679 obj.LinkNum = reader.ReadElementContentAsInt("LinkNum", String.Empty);
589 } 680 }
590 681
591 private static void ProcessClickAction(SceneObjectPart obj, XmlTextReader reader) 682 private static void ProcessClickAction(SceneObjectPart obj, XmlReader reader)
592 { 683 {
593 obj.ClickAction = (byte)reader.ReadElementContentAsInt("ClickAction", String.Empty); 684 obj.ClickAction = (byte)reader.ReadElementContentAsInt("ClickAction", String.Empty);
594 } 685 }
595 686
596 private static void ProcessShape(SceneObjectPart obj, XmlTextReader reader) 687 private static void ProcessPhysicsShapeType(SceneObjectPart obj, XmlReader reader)
688 {
689 obj.PhysicsShapeType = (byte)reader.ReadElementContentAsInt("PhysicsShapeType", String.Empty);
690 }
691
692 private static void ProcessDensity(SceneObjectPart obj, XmlReader reader)
693 {
694 obj.Density = reader.ReadElementContentAsFloat("Density", String.Empty);
695 }
696
697 private static void ProcessFriction(SceneObjectPart obj, XmlReader reader)
698 {
699 obj.Friction = reader.ReadElementContentAsFloat("Friction", String.Empty);
700 }
701
702 private static void ProcessBounce(SceneObjectPart obj, XmlReader reader)
703 {
704 obj.Restitution = reader.ReadElementContentAsFloat("Bounce", String.Empty);
705 }
706
707 private static void ProcessGravityModifier(SceneObjectPart obj, XmlReader reader)
708 {
709 obj.GravityModifier = reader.ReadElementContentAsFloat("GravityModifier", String.Empty);
710 }
711
712 private static void ProcessShape(SceneObjectPart obj, XmlReader reader)
597 { 713 {
598 List<string> errorNodeNames; 714 List<string> errorNodeNames;
599 obj.Shape = ReadShape(reader, "Shape", out errorNodeNames); 715 obj.Shape = ReadShape(reader, "Shape", out errorNodeNames, obj);
600 716
601 if (errorNodeNames != null) 717 if (errorNodeNames != null)
602 { 718 {
@@ -606,153 +722,163 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
606 } 722 }
607 } 723 }
608 724
609 private static void ProcessScale(SceneObjectPart obj, XmlTextReader reader) 725 private static void ProcessScale(SceneObjectPart obj, XmlReader reader)
610 { 726 {
611 obj.Scale = Util.ReadVector(reader, "Scale"); 727 obj.Scale = Util.ReadVector(reader, "Scale");
612 } 728 }
613 729
614 private static void ProcessSitTargetOrientation(SceneObjectPart obj, XmlTextReader reader) 730 private static void ProcessSitTargetOrientation(SceneObjectPart obj, XmlReader reader)
615 { 731 {
616 obj.SitTargetOrientation = Util.ReadQuaternion(reader, "SitTargetOrientation"); 732 obj.SitTargetOrientation = Util.ReadQuaternion(reader, "SitTargetOrientation");
617 } 733 }
618 734
619 private static void ProcessSitTargetPosition(SceneObjectPart obj, XmlTextReader reader) 735 private static void ProcessSitTargetPosition(SceneObjectPart obj, XmlReader reader)
620 { 736 {
621 obj.SitTargetPosition = Util.ReadVector(reader, "SitTargetPosition"); 737 obj.SitTargetPosition = Util.ReadVector(reader, "SitTargetPosition");
622 } 738 }
623 739
624 private static void ProcessSitTargetPositionLL(SceneObjectPart obj, XmlTextReader reader) 740 private static void ProcessSitTargetPositionLL(SceneObjectPart obj, XmlReader reader)
625 { 741 {
626 obj.SitTargetPositionLL = Util.ReadVector(reader, "SitTargetPositionLL"); 742 obj.SitTargetPositionLL = Util.ReadVector(reader, "SitTargetPositionLL");
627 } 743 }
628 744
629 private static void ProcessSitTargetOrientationLL(SceneObjectPart obj, XmlTextReader reader) 745 private static void ProcessSitTargetOrientationLL(SceneObjectPart obj, XmlReader reader)
630 { 746 {
631 obj.SitTargetOrientationLL = Util.ReadQuaternion(reader, "SitTargetOrientationLL"); 747 obj.SitTargetOrientationLL = Util.ReadQuaternion(reader, "SitTargetOrientationLL");
632 } 748 }
633 749
634 private static void ProcessParentID(SceneObjectPart obj, XmlTextReader reader) 750 private static void ProcessParentID(SceneObjectPart obj, XmlReader reader)
635 { 751 {
636 string str = reader.ReadElementContentAsString("ParentID", String.Empty); 752 string str = reader.ReadElementContentAsString("ParentID", String.Empty);
637 obj.ParentID = Convert.ToUInt32(str); 753 obj.ParentID = Convert.ToUInt32(str);
638 } 754 }
639 755
640 private static void ProcessCreationDate(SceneObjectPart obj, XmlTextReader reader) 756 private static void ProcessCreationDate(SceneObjectPart obj, XmlReader reader)
641 { 757 {
642 obj.CreationDate = reader.ReadElementContentAsInt("CreationDate", String.Empty); 758 obj.CreationDate = reader.ReadElementContentAsInt("CreationDate", String.Empty);
643 } 759 }
644 760
645 private static void ProcessCategory(SceneObjectPart obj, XmlTextReader reader) 761 private static void ProcessCategory(SceneObjectPart obj, XmlReader reader)
646 { 762 {
647 obj.Category = (uint)reader.ReadElementContentAsInt("Category", String.Empty); 763 obj.Category = (uint)reader.ReadElementContentAsInt("Category", String.Empty);
648 } 764 }
649 765
650 private static void ProcessSalePrice(SceneObjectPart obj, XmlTextReader reader) 766 private static void ProcessSalePrice(SceneObjectPart obj, XmlReader reader)
651 { 767 {
652 obj.SalePrice = reader.ReadElementContentAsInt("SalePrice", String.Empty); 768 obj.SalePrice = reader.ReadElementContentAsInt("SalePrice", String.Empty);
653 } 769 }
654 770
655 private static void ProcessObjectSaleType(SceneObjectPart obj, XmlTextReader reader) 771 private static void ProcessObjectSaleType(SceneObjectPart obj, XmlReader reader)
656 { 772 {
657 obj.ObjectSaleType = (byte)reader.ReadElementContentAsInt("ObjectSaleType", String.Empty); 773 obj.ObjectSaleType = (byte)reader.ReadElementContentAsInt("ObjectSaleType", String.Empty);
658 } 774 }
659 775
660 private static void ProcessOwnershipCost(SceneObjectPart obj, XmlTextReader reader) 776 private static void ProcessOwnershipCost(SceneObjectPart obj, XmlReader reader)
661 { 777 {
662 obj.OwnershipCost = reader.ReadElementContentAsInt("OwnershipCost", String.Empty); 778 obj.OwnershipCost = reader.ReadElementContentAsInt("OwnershipCost", String.Empty);
663 } 779 }
664 780
665 private static void ProcessGroupID(SceneObjectPart obj, XmlTextReader reader) 781 private static void ProcessGroupID(SceneObjectPart obj, XmlReader reader)
666 { 782 {
667 obj.GroupID = Util.ReadUUID(reader, "GroupID"); 783 obj.GroupID = Util.ReadUUID(reader, "GroupID");
668 } 784 }
669 785
670 private static void ProcessOwnerID(SceneObjectPart obj, XmlTextReader reader) 786 private static void ProcessOwnerID(SceneObjectPart obj, XmlReader reader)
671 { 787 {
672 obj.OwnerID = Util.ReadUUID(reader, "OwnerID"); 788 obj.OwnerID = Util.ReadUUID(reader, "OwnerID");
673 } 789 }
674 790
675 private static void ProcessLastOwnerID(SceneObjectPart obj, XmlTextReader reader) 791 private static void ProcessLastOwnerID(SceneObjectPart obj, XmlReader reader)
676 { 792 {
677 obj.LastOwnerID = Util.ReadUUID(reader, "LastOwnerID"); 793 obj.LastOwnerID = Util.ReadUUID(reader, "LastOwnerID");
678 } 794 }
679 795
680 private static void ProcessBaseMask(SceneObjectPart obj, XmlTextReader reader) 796 private static void ProcessBaseMask(SceneObjectPart obj, XmlReader reader)
681 { 797 {
682 obj.BaseMask = (uint)reader.ReadElementContentAsInt("BaseMask", String.Empty); 798 obj.BaseMask = (uint)reader.ReadElementContentAsInt("BaseMask", String.Empty);
683 } 799 }
684 800
685 private static void ProcessOwnerMask(SceneObjectPart obj, XmlTextReader reader) 801 private static void ProcessOwnerMask(SceneObjectPart obj, XmlReader reader)
686 { 802 {
687 obj.OwnerMask = (uint)reader.ReadElementContentAsInt("OwnerMask", String.Empty); 803 obj.OwnerMask = (uint)reader.ReadElementContentAsInt("OwnerMask", String.Empty);
688 } 804 }
689 805
690 private static void ProcessGroupMask(SceneObjectPart obj, XmlTextReader reader) 806 private static void ProcessGroupMask(SceneObjectPart obj, XmlReader reader)
691 { 807 {
692 obj.GroupMask = (uint)reader.ReadElementContentAsInt("GroupMask", String.Empty); 808 obj.GroupMask = (uint)reader.ReadElementContentAsInt("GroupMask", String.Empty);
693 } 809 }
694 810
695 private static void ProcessEveryoneMask(SceneObjectPart obj, XmlTextReader reader) 811 private static void ProcessEveryoneMask(SceneObjectPart obj, XmlReader reader)
696 { 812 {
697 obj.EveryoneMask = (uint)reader.ReadElementContentAsInt("EveryoneMask", String.Empty); 813 obj.EveryoneMask = (uint)reader.ReadElementContentAsInt("EveryoneMask", String.Empty);
698 } 814 }
699 815
700 private static void ProcessNextOwnerMask(SceneObjectPart obj, XmlTextReader reader) 816 private static void ProcessNextOwnerMask(SceneObjectPart obj, XmlReader reader)
701 { 817 {
702 obj.NextOwnerMask = (uint)reader.ReadElementContentAsInt("NextOwnerMask", String.Empty); 818 obj.NextOwnerMask = (uint)reader.ReadElementContentAsInt("NextOwnerMask", String.Empty);
703 } 819 }
704 820
705 private static void ProcessFlags(SceneObjectPart obj, XmlTextReader reader) 821 private static void ProcessFlags(SceneObjectPart obj, XmlReader reader)
706 { 822 {
707 obj.Flags = Util.ReadEnum<PrimFlags>(reader, "Flags"); 823 obj.Flags = Util.ReadEnum<PrimFlags>(reader, "Flags");
708 } 824 }
709 825
710 private static void ProcessCollisionSound(SceneObjectPart obj, XmlTextReader reader) 826 private static void ProcessCollisionSound(SceneObjectPart obj, XmlReader reader)
711 { 827 {
712 obj.CollisionSound = Util.ReadUUID(reader, "CollisionSound"); 828 obj.CollisionSound = Util.ReadUUID(reader, "CollisionSound");
713 } 829 }
714 830
715 private static void ProcessCollisionSoundVolume(SceneObjectPart obj, XmlTextReader reader) 831 private static void ProcessCollisionSoundVolume(SceneObjectPart obj, XmlReader reader)
716 { 832 {
717 obj.CollisionSoundVolume = reader.ReadElementContentAsFloat("CollisionSoundVolume", String.Empty); 833 obj.CollisionSoundVolume = reader.ReadElementContentAsFloat("CollisionSoundVolume", String.Empty);
718 } 834 }
719 835
720 private static void ProcessMediaUrl(SceneObjectPart obj, XmlTextReader reader) 836 private static void ProcessMediaUrl(SceneObjectPart obj, XmlReader reader)
721 { 837 {
722 obj.MediaUrl = reader.ReadElementContentAsString("MediaUrl", String.Empty); 838 obj.MediaUrl = reader.ReadElementContentAsString("MediaUrl", String.Empty);
723 } 839 }
724 840
725 private static void ProcessTextureAnimation(SceneObjectPart obj, XmlTextReader reader) 841 private static void ProcessAttachedPos(SceneObjectPart obj, XmlReader reader)
842 {
843 obj.AttachedPos = Util.ReadVector(reader, "AttachedPos");
844 }
845
846 private static void ProcessDynAttrs(SceneObjectPart obj, XmlReader reader)
847 {
848 obj.DynAttrs.ReadXml(reader);
849 }
850
851 private static void ProcessTextureAnimation(SceneObjectPart obj, XmlReader reader)
726 { 852 {
727 obj.TextureAnimation = Convert.FromBase64String(reader.ReadElementContentAsString("TextureAnimation", String.Empty)); 853 obj.TextureAnimation = Convert.FromBase64String(reader.ReadElementContentAsString("TextureAnimation", String.Empty));
728 } 854 }
729 855
730 private static void ProcessParticleSystem(SceneObjectPart obj, XmlTextReader reader) 856 private static void ProcessParticleSystem(SceneObjectPart obj, XmlReader reader)
731 { 857 {
732 obj.ParticleSystem = Convert.FromBase64String(reader.ReadElementContentAsString("ParticleSystem", String.Empty)); 858 obj.ParticleSystem = Convert.FromBase64String(reader.ReadElementContentAsString("ParticleSystem", String.Empty));
733 } 859 }
734 860
735 private static void ProcessPayPrice0(SceneObjectPart obj, XmlTextReader reader) 861 private static void ProcessPayPrice0(SceneObjectPart obj, XmlReader reader)
736 { 862 {
737 obj.PayPrice[0] = (int)reader.ReadElementContentAsInt("PayPrice0", String.Empty); 863 obj.PayPrice[0] = (int)reader.ReadElementContentAsInt("PayPrice0", String.Empty);
738 } 864 }
739 865
740 private static void ProcessPayPrice1(SceneObjectPart obj, XmlTextReader reader) 866 private static void ProcessPayPrice1(SceneObjectPart obj, XmlReader reader)
741 { 867 {
742 obj.PayPrice[1] = (int)reader.ReadElementContentAsInt("PayPrice1", String.Empty); 868 obj.PayPrice[1] = (int)reader.ReadElementContentAsInt("PayPrice1", String.Empty);
743 } 869 }
744 870
745 private static void ProcessPayPrice2(SceneObjectPart obj, XmlTextReader reader) 871 private static void ProcessPayPrice2(SceneObjectPart obj, XmlReader reader)
746 { 872 {
747 obj.PayPrice[2] = (int)reader.ReadElementContentAsInt("PayPrice2", String.Empty); 873 obj.PayPrice[2] = (int)reader.ReadElementContentAsInt("PayPrice2", String.Empty);
748 } 874 }
749 875
750 private static void ProcessPayPrice3(SceneObjectPart obj, XmlTextReader reader) 876 private static void ProcessPayPrice3(SceneObjectPart obj, XmlReader reader)
751 { 877 {
752 obj.PayPrice[3] = (int)reader.ReadElementContentAsInt("PayPrice3", String.Empty); 878 obj.PayPrice[3] = (int)reader.ReadElementContentAsInt("PayPrice3", String.Empty);
753 } 879 }
754 880
755 private static void ProcessPayPrice4(SceneObjectPart obj, XmlTextReader reader) 881 private static void ProcessPayPrice4(SceneObjectPart obj, XmlReader reader)
756 { 882 {
757 obj.PayPrice[4] = (int)reader.ReadElementContentAsInt("PayPrice4", String.Empty); 883 obj.PayPrice[4] = (int)reader.ReadElementContentAsInt("PayPrice4", String.Empty);
758 } 884 }
@@ -760,122 +886,122 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
760 #endregion 886 #endregion
761 887
762 #region TaskInventoryXmlProcessors 888 #region TaskInventoryXmlProcessors
763 private static void ProcessTIAssetID(TaskInventoryItem item, XmlTextReader reader) 889 private static void ProcessTIAssetID(TaskInventoryItem item, XmlReader reader)
764 { 890 {
765 item.AssetID = Util.ReadUUID(reader, "AssetID"); 891 item.AssetID = Util.ReadUUID(reader, "AssetID");
766 } 892 }
767 893
768 private static void ProcessTIBasePermissions(TaskInventoryItem item, XmlTextReader reader) 894 private static void ProcessTIBasePermissions(TaskInventoryItem item, XmlReader reader)
769 { 895 {
770 item.BasePermissions = (uint)reader.ReadElementContentAsInt("BasePermissions", String.Empty); 896 item.BasePermissions = (uint)reader.ReadElementContentAsInt("BasePermissions", String.Empty);
771 } 897 }
772 898
773 private static void ProcessTICreationDate(TaskInventoryItem item, XmlTextReader reader) 899 private static void ProcessTICreationDate(TaskInventoryItem item, XmlReader reader)
774 { 900 {
775 item.CreationDate = (uint)reader.ReadElementContentAsInt("CreationDate", String.Empty); 901 item.CreationDate = (uint)reader.ReadElementContentAsInt("CreationDate", String.Empty);
776 } 902 }
777 903
778 private static void ProcessTICreatorID(TaskInventoryItem item, XmlTextReader reader) 904 private static void ProcessTICreatorID(TaskInventoryItem item, XmlReader reader)
779 { 905 {
780 item.CreatorID = Util.ReadUUID(reader, "CreatorID"); 906 item.CreatorID = Util.ReadUUID(reader, "CreatorID");
781 } 907 }
782 908
783 private static void ProcessTICreatorData(TaskInventoryItem item, XmlTextReader reader) 909 private static void ProcessTICreatorData(TaskInventoryItem item, XmlReader reader)
784 { 910 {
785 item.CreatorData = reader.ReadElementContentAsString("CreatorData", String.Empty); 911 item.CreatorData = reader.ReadElementContentAsString("CreatorData", String.Empty);
786 } 912 }
787 913
788 private static void ProcessTIDescription(TaskInventoryItem item, XmlTextReader reader) 914 private static void ProcessTIDescription(TaskInventoryItem item, XmlReader reader)
789 { 915 {
790 item.Description = reader.ReadElementContentAsString("Description", String.Empty); 916 item.Description = reader.ReadElementContentAsString("Description", String.Empty);
791 } 917 }
792 918
793 private static void ProcessTIEveryonePermissions(TaskInventoryItem item, XmlTextReader reader) 919 private static void ProcessTIEveryonePermissions(TaskInventoryItem item, XmlReader reader)
794 { 920 {
795 item.EveryonePermissions = (uint)reader.ReadElementContentAsInt("EveryonePermissions", String.Empty); 921 item.EveryonePermissions = (uint)reader.ReadElementContentAsInt("EveryonePermissions", String.Empty);
796 } 922 }
797 923
798 private static void ProcessTIFlags(TaskInventoryItem item, XmlTextReader reader) 924 private static void ProcessTIFlags(TaskInventoryItem item, XmlReader reader)
799 { 925 {
800 item.Flags = (uint)reader.ReadElementContentAsInt("Flags", String.Empty); 926 item.Flags = (uint)reader.ReadElementContentAsInt("Flags", String.Empty);
801 } 927 }
802 928
803 private static void ProcessTIGroupID(TaskInventoryItem item, XmlTextReader reader) 929 private static void ProcessTIGroupID(TaskInventoryItem item, XmlReader reader)
804 { 930 {
805 item.GroupID = Util.ReadUUID(reader, "GroupID"); 931 item.GroupID = Util.ReadUUID(reader, "GroupID");
806 } 932 }
807 933
808 private static void ProcessTIGroupPermissions(TaskInventoryItem item, XmlTextReader reader) 934 private static void ProcessTIGroupPermissions(TaskInventoryItem item, XmlReader reader)
809 { 935 {
810 item.GroupPermissions = (uint)reader.ReadElementContentAsInt("GroupPermissions", String.Empty); 936 item.GroupPermissions = (uint)reader.ReadElementContentAsInt("GroupPermissions", String.Empty);
811 } 937 }
812 938
813 private static void ProcessTIInvType(TaskInventoryItem item, XmlTextReader reader) 939 private static void ProcessTIInvType(TaskInventoryItem item, XmlReader reader)
814 { 940 {
815 item.InvType = reader.ReadElementContentAsInt("InvType", String.Empty); 941 item.InvType = reader.ReadElementContentAsInt("InvType", String.Empty);
816 } 942 }
817 943
818 private static void ProcessTIItemID(TaskInventoryItem item, XmlTextReader reader) 944 private static void ProcessTIItemID(TaskInventoryItem item, XmlReader reader)
819 { 945 {
820 item.ItemID = Util.ReadUUID(reader, "ItemID"); 946 item.ItemID = Util.ReadUUID(reader, "ItemID");
821 } 947 }
822 948
823 private static void ProcessTIOldItemID(TaskInventoryItem item, XmlTextReader reader) 949 private static void ProcessTIOldItemID(TaskInventoryItem item, XmlReader reader)
824 { 950 {
825 item.OldItemID = Util.ReadUUID(reader, "OldItemID"); 951 item.OldItemID = Util.ReadUUID(reader, "OldItemID");
826 } 952 }
827 953
828 private static void ProcessTILastOwnerID(TaskInventoryItem item, XmlTextReader reader) 954 private static void ProcessTILastOwnerID(TaskInventoryItem item, XmlReader reader)
829 { 955 {
830 item.LastOwnerID = Util.ReadUUID(reader, "LastOwnerID"); 956 item.LastOwnerID = Util.ReadUUID(reader, "LastOwnerID");
831 } 957 }
832 958
833 private static void ProcessTIName(TaskInventoryItem item, XmlTextReader reader) 959 private static void ProcessTIName(TaskInventoryItem item, XmlReader reader)
834 { 960 {
835 item.Name = reader.ReadElementContentAsString("Name", String.Empty); 961 item.Name = reader.ReadElementContentAsString("Name", String.Empty);
836 } 962 }
837 963
838 private static void ProcessTINextPermissions(TaskInventoryItem item, XmlTextReader reader) 964 private static void ProcessTINextPermissions(TaskInventoryItem item, XmlReader reader)
839 { 965 {
840 item.NextPermissions = (uint)reader.ReadElementContentAsInt("NextPermissions", String.Empty); 966 item.NextPermissions = (uint)reader.ReadElementContentAsInt("NextPermissions", String.Empty);
841 } 967 }
842 968
843 private static void ProcessTIOwnerID(TaskInventoryItem item, XmlTextReader reader) 969 private static void ProcessTIOwnerID(TaskInventoryItem item, XmlReader reader)
844 { 970 {
845 item.OwnerID = Util.ReadUUID(reader, "OwnerID"); 971 item.OwnerID = Util.ReadUUID(reader, "OwnerID");
846 } 972 }
847 973
848 private static void ProcessTICurrentPermissions(TaskInventoryItem item, XmlTextReader reader) 974 private static void ProcessTICurrentPermissions(TaskInventoryItem item, XmlReader reader)
849 { 975 {
850 item.CurrentPermissions = (uint)reader.ReadElementContentAsInt("CurrentPermissions", String.Empty); 976 item.CurrentPermissions = (uint)reader.ReadElementContentAsInt("CurrentPermissions", String.Empty);
851 } 977 }
852 978
853 private static void ProcessTIParentID(TaskInventoryItem item, XmlTextReader reader) 979 private static void ProcessTIParentID(TaskInventoryItem item, XmlReader reader)
854 { 980 {
855 item.ParentID = Util.ReadUUID(reader, "ParentID"); 981 item.ParentID = Util.ReadUUID(reader, "ParentID");
856 } 982 }
857 983
858 private static void ProcessTIParentPartID(TaskInventoryItem item, XmlTextReader reader) 984 private static void ProcessTIParentPartID(TaskInventoryItem item, XmlReader reader)
859 { 985 {
860 item.ParentPartID = Util.ReadUUID(reader, "ParentPartID"); 986 item.ParentPartID = Util.ReadUUID(reader, "ParentPartID");
861 } 987 }
862 988
863 private static void ProcessTIPermsGranter(TaskInventoryItem item, XmlTextReader reader) 989 private static void ProcessTIPermsGranter(TaskInventoryItem item, XmlReader reader)
864 { 990 {
865 item.PermsGranter = Util.ReadUUID(reader, "PermsGranter"); 991 item.PermsGranter = Util.ReadUUID(reader, "PermsGranter");
866 } 992 }
867 993
868 private static void ProcessTIPermsMask(TaskInventoryItem item, XmlTextReader reader) 994 private static void ProcessTIPermsMask(TaskInventoryItem item, XmlReader reader)
869 { 995 {
870 item.PermsMask = reader.ReadElementContentAsInt("PermsMask", String.Empty); 996 item.PermsMask = reader.ReadElementContentAsInt("PermsMask", String.Empty);
871 } 997 }
872 998
873 private static void ProcessTIType(TaskInventoryItem item, XmlTextReader reader) 999 private static void ProcessTIType(TaskInventoryItem item, XmlReader reader)
874 { 1000 {
875 item.Type = reader.ReadElementContentAsInt("Type", String.Empty); 1001 item.Type = reader.ReadElementContentAsInt("Type", String.Empty);
876 } 1002 }
877 1003
878 private static void ProcessTIOwnerChanged(TaskInventoryItem item, XmlTextReader reader) 1004 private static void ProcessTIOwnerChanged(TaskInventoryItem item, XmlReader reader)
879 { 1005 {
880 item.OwnerChanged = Util.ReadBoolean(reader); 1006 item.OwnerChanged = Util.ReadBoolean(reader);
881 } 1007 }
@@ -883,245 +1009,243 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
883 #endregion 1009 #endregion
884 1010
885 #region ShapeXmlProcessors 1011 #region ShapeXmlProcessors
886 private static void ProcessShpProfileCurve(PrimitiveBaseShape shp, XmlTextReader reader) 1012 private static void ProcessShpProfileCurve(PrimitiveBaseShape shp, XmlReader reader)
887 { 1013 {
888 shp.ProfileCurve = (byte)reader.ReadElementContentAsInt("ProfileCurve", String.Empty); 1014 shp.ProfileCurve = (byte)reader.ReadElementContentAsInt("ProfileCurve", String.Empty);
889 } 1015 }
890 1016
891 private static void ProcessShpTextureEntry(PrimitiveBaseShape shp, XmlTextReader reader) 1017 private static void ProcessShpTextureEntry(PrimitiveBaseShape shp, XmlReader reader)
892 { 1018 {
893 byte[] teData = Convert.FromBase64String(reader.ReadElementString("TextureEntry")); 1019 byte[] teData = Convert.FromBase64String(reader.ReadElementString("TextureEntry"));
894 shp.Textures = new Primitive.TextureEntry(teData, 0, teData.Length); 1020 shp.Textures = new Primitive.TextureEntry(teData, 0, teData.Length);
895 } 1021 }
896 1022
897 private static void ProcessShpExtraParams(PrimitiveBaseShape shp, XmlTextReader reader) 1023 private static void ProcessShpExtraParams(PrimitiveBaseShape shp, XmlReader reader)
898 { 1024 {
899 shp.ExtraParams = Convert.FromBase64String(reader.ReadElementString("ExtraParams")); 1025 shp.ExtraParams = Convert.FromBase64String(reader.ReadElementString("ExtraParams"));
900 } 1026 }
901 1027
902 private static void ProcessShpPathBegin(PrimitiveBaseShape shp, XmlTextReader reader) 1028 private static void ProcessShpPathBegin(PrimitiveBaseShape shp, XmlReader reader)
903 { 1029 {
904 shp.PathBegin = (ushort)reader.ReadElementContentAsInt("PathBegin", String.Empty); 1030 shp.PathBegin = (ushort)reader.ReadElementContentAsInt("PathBegin", String.Empty);
905 } 1031 }
906 1032
907 private static void ProcessShpPathCurve(PrimitiveBaseShape shp, XmlTextReader reader) 1033 private static void ProcessShpPathCurve(PrimitiveBaseShape shp, XmlReader reader)
908 { 1034 {
909 shp.PathCurve = (byte)reader.ReadElementContentAsInt("PathCurve", String.Empty); 1035 shp.PathCurve = (byte)reader.ReadElementContentAsInt("PathCurve", String.Empty);
910 } 1036 }
911 1037
912 private static void ProcessShpPathEnd(PrimitiveBaseShape shp, XmlTextReader reader) 1038 private static void ProcessShpPathEnd(PrimitiveBaseShape shp, XmlReader reader)
913 { 1039 {
914 shp.PathEnd = (ushort)reader.ReadElementContentAsInt("PathEnd", String.Empty); 1040 shp.PathEnd = (ushort)reader.ReadElementContentAsInt("PathEnd", String.Empty);
915 } 1041 }
916 1042
917 private static void ProcessShpPathRadiusOffset(PrimitiveBaseShape shp, XmlTextReader reader) 1043 private static void ProcessShpPathRadiusOffset(PrimitiveBaseShape shp, XmlReader reader)
918 { 1044 {
919 shp.PathRadiusOffset = (sbyte)reader.ReadElementContentAsInt("PathRadiusOffset", String.Empty); 1045 shp.PathRadiusOffset = (sbyte)reader.ReadElementContentAsInt("PathRadiusOffset", String.Empty);
920 } 1046 }
921 1047
922 private static void ProcessShpPathRevolutions(PrimitiveBaseShape shp, XmlTextReader reader) 1048 private static void ProcessShpPathRevolutions(PrimitiveBaseShape shp, XmlReader reader)
923 { 1049 {
924 shp.PathRevolutions = (byte)reader.ReadElementContentAsInt("PathRevolutions", String.Empty); 1050 shp.PathRevolutions = (byte)reader.ReadElementContentAsInt("PathRevolutions", String.Empty);
925 } 1051 }
926 1052
927 private static void ProcessShpPathScaleX(PrimitiveBaseShape shp, XmlTextReader reader) 1053 private static void ProcessShpPathScaleX(PrimitiveBaseShape shp, XmlReader reader)
928 { 1054 {
929 shp.PathScaleX = (byte)reader.ReadElementContentAsInt("PathScaleX", String.Empty); 1055 shp.PathScaleX = (byte)reader.ReadElementContentAsInt("PathScaleX", String.Empty);
930 } 1056 }
931 1057
932 private static void ProcessShpPathScaleY(PrimitiveBaseShape shp, XmlTextReader reader) 1058 private static void ProcessShpPathScaleY(PrimitiveBaseShape shp, XmlReader reader)
933 { 1059 {
934 shp.PathScaleY = (byte)reader.ReadElementContentAsInt("PathScaleY", String.Empty); 1060 shp.PathScaleY = (byte)reader.ReadElementContentAsInt("PathScaleY", String.Empty);
935 } 1061 }
936 1062
937 private static void ProcessShpPathShearX(PrimitiveBaseShape shp, XmlTextReader reader) 1063 private static void ProcessShpPathShearX(PrimitiveBaseShape shp, XmlReader reader)
938 { 1064 {
939 shp.PathShearX = (byte)reader.ReadElementContentAsInt("PathShearX", String.Empty); 1065 shp.PathShearX = (byte)reader.ReadElementContentAsInt("PathShearX", String.Empty);
940 } 1066 }
941 1067
942 private static void ProcessShpPathShearY(PrimitiveBaseShape shp, XmlTextReader reader) 1068 private static void ProcessShpPathShearY(PrimitiveBaseShape shp, XmlReader reader)
943 { 1069 {
944 shp.PathShearY = (byte)reader.ReadElementContentAsInt("PathShearY", String.Empty); 1070 shp.PathShearY = (byte)reader.ReadElementContentAsInt("PathShearY", String.Empty);
945 } 1071 }
946 1072
947 private static void ProcessShpPathSkew(PrimitiveBaseShape shp, XmlTextReader reader) 1073 private static void ProcessShpPathSkew(PrimitiveBaseShape shp, XmlReader reader)
948 { 1074 {
949 shp.PathSkew = (sbyte)reader.ReadElementContentAsInt("PathSkew", String.Empty); 1075 shp.PathSkew = (sbyte)reader.ReadElementContentAsInt("PathSkew", String.Empty);
950 } 1076 }
951 1077
952 private static void ProcessShpPathTaperX(PrimitiveBaseShape shp, XmlTextReader reader) 1078 private static void ProcessShpPathTaperX(PrimitiveBaseShape shp, XmlReader reader)
953 { 1079 {
954 shp.PathTaperX = (sbyte)reader.ReadElementContentAsInt("PathTaperX", String.Empty); 1080 shp.PathTaperX = (sbyte)reader.ReadElementContentAsInt("PathTaperX", String.Empty);
955 } 1081 }
956 1082
957 private static void ProcessShpPathTaperY(PrimitiveBaseShape shp, XmlTextReader reader) 1083 private static void ProcessShpPathTaperY(PrimitiveBaseShape shp, XmlReader reader)
958 { 1084 {
959 shp.PathTaperY = (sbyte)reader.ReadElementContentAsInt("PathTaperY", String.Empty); 1085 shp.PathTaperY = (sbyte)reader.ReadElementContentAsInt("PathTaperY", String.Empty);
960 } 1086 }
961 1087
962 private static void ProcessShpPathTwist(PrimitiveBaseShape shp, XmlTextReader reader) 1088 private static void ProcessShpPathTwist(PrimitiveBaseShape shp, XmlReader reader)
963 { 1089 {
964 shp.PathTwist = (sbyte)reader.ReadElementContentAsInt("PathTwist", String.Empty); 1090 shp.PathTwist = (sbyte)reader.ReadElementContentAsInt("PathTwist", String.Empty);
965 } 1091 }
966 1092
967 private static void ProcessShpPathTwistBegin(PrimitiveBaseShape shp, XmlTextReader reader) 1093 private static void ProcessShpPathTwistBegin(PrimitiveBaseShape shp, XmlReader reader)
968 { 1094 {
969 shp.PathTwistBegin = (sbyte)reader.ReadElementContentAsInt("PathTwistBegin", String.Empty); 1095 shp.PathTwistBegin = (sbyte)reader.ReadElementContentAsInt("PathTwistBegin", String.Empty);
970 } 1096 }
971 1097
972 private static void ProcessShpPCode(PrimitiveBaseShape shp, XmlTextReader reader) 1098 private static void ProcessShpPCode(PrimitiveBaseShape shp, XmlReader reader)
973 { 1099 {
974 shp.PCode = (byte)reader.ReadElementContentAsInt("PCode", String.Empty); 1100 shp.PCode = (byte)reader.ReadElementContentAsInt("PCode", String.Empty);
975 } 1101 }
976 1102
977 private static void ProcessShpProfileBegin(PrimitiveBaseShape shp, XmlTextReader reader) 1103 private static void ProcessShpProfileBegin(PrimitiveBaseShape shp, XmlReader reader)
978 { 1104 {
979 shp.ProfileBegin = (ushort)reader.ReadElementContentAsInt("ProfileBegin", String.Empty); 1105 shp.ProfileBegin = (ushort)reader.ReadElementContentAsInt("ProfileBegin", String.Empty);
980 } 1106 }
981 1107
982 private static void ProcessShpProfileEnd(PrimitiveBaseShape shp, XmlTextReader reader) 1108 private static void ProcessShpProfileEnd(PrimitiveBaseShape shp, XmlReader reader)
983 { 1109 {
984 shp.ProfileEnd = (ushort)reader.ReadElementContentAsInt("ProfileEnd", String.Empty); 1110 shp.ProfileEnd = (ushort)reader.ReadElementContentAsInt("ProfileEnd", String.Empty);
985 } 1111 }
986 1112
987 private static void ProcessShpProfileHollow(PrimitiveBaseShape shp, XmlTextReader reader) 1113 private static void ProcessShpProfileHollow(PrimitiveBaseShape shp, XmlReader reader)
988 { 1114 {
989 shp.ProfileHollow = (ushort)reader.ReadElementContentAsInt("ProfileHollow", String.Empty); 1115 shp.ProfileHollow = (ushort)reader.ReadElementContentAsInt("ProfileHollow", String.Empty);
990 } 1116 }
991 1117
992 private static void ProcessShpScale(PrimitiveBaseShape shp, XmlTextReader reader) 1118 private static void ProcessShpScale(PrimitiveBaseShape shp, XmlReader reader)
993 { 1119 {
994 shp.Scale = Util.ReadVector(reader, "Scale"); 1120 shp.Scale = Util.ReadVector(reader, "Scale");
995 } 1121 }
996 1122
997 private static void ProcessShpState(PrimitiveBaseShape shp, XmlTextReader reader) 1123 private static void ProcessShpState(PrimitiveBaseShape shp, XmlReader reader)
998 { 1124 {
999 shp.State = (byte)reader.ReadElementContentAsInt("State", String.Empty); 1125 shp.State = (byte)reader.ReadElementContentAsInt("State", String.Empty);
1000 } 1126 }
1001 1127
1002 private static void ProcessShpProfileShape(PrimitiveBaseShape shp, XmlTextReader reader) 1128 private static void ProcessShpLastAttach(PrimitiveBaseShape shp, XmlReader reader)
1129 {
1130 shp.LastAttachPoint = (byte)reader.ReadElementContentAsInt("LastAttachPoint", String.Empty);
1131 }
1132
1133 private static void ProcessShpProfileShape(PrimitiveBaseShape shp, XmlReader reader)
1003 { 1134 {
1004 shp.ProfileShape = Util.ReadEnum<ProfileShape>(reader, "ProfileShape"); 1135 shp.ProfileShape = Util.ReadEnum<ProfileShape>(reader, "ProfileShape");
1005 } 1136 }
1006 1137
1007 private static void ProcessShpHollowShape(PrimitiveBaseShape shp, XmlTextReader reader) 1138 private static void ProcessShpHollowShape(PrimitiveBaseShape shp, XmlReader reader)
1008 { 1139 {
1009 shp.HollowShape = Util.ReadEnum<HollowShape>(reader, "HollowShape"); 1140 shp.HollowShape = Util.ReadEnum<HollowShape>(reader, "HollowShape");
1010 } 1141 }
1011 1142
1012 private static void ProcessShpSculptTexture(PrimitiveBaseShape shp, XmlTextReader reader) 1143 private static void ProcessShpSculptTexture(PrimitiveBaseShape shp, XmlReader reader)
1013 { 1144 {
1014 shp.SculptTexture = Util.ReadUUID(reader, "SculptTexture"); 1145 shp.SculptTexture = Util.ReadUUID(reader, "SculptTexture");
1015 } 1146 }
1016 1147
1017 private static void ProcessShpSculptType(PrimitiveBaseShape shp, XmlTextReader reader) 1148 private static void ProcessShpSculptType(PrimitiveBaseShape shp, XmlReader reader)
1018 { 1149 {
1019 shp.SculptType = (byte)reader.ReadElementContentAsInt("SculptType", String.Empty); 1150 shp.SculptType = (byte)reader.ReadElementContentAsInt("SculptType", String.Empty);
1020 } 1151 }
1021 1152
1022 private static void ProcessShpSculptData(PrimitiveBaseShape shp, XmlTextReader reader) 1153 private static void ProcessShpFlexiSoftness(PrimitiveBaseShape shp, XmlReader reader)
1023 {
1024// m_log.DebugFormat("[SCENE OBJECT SERIALIZER]: Setting sculpt data length {0}", shp.SculptData.Length);
1025
1026 shp.SculptData = Convert.FromBase64String(reader.ReadElementString("SculptData"));
1027 }
1028
1029 private static void ProcessShpFlexiSoftness(PrimitiveBaseShape shp, XmlTextReader reader)
1030 { 1154 {
1031 shp.FlexiSoftness = reader.ReadElementContentAsInt("FlexiSoftness", String.Empty); 1155 shp.FlexiSoftness = reader.ReadElementContentAsInt("FlexiSoftness", String.Empty);
1032 } 1156 }
1033 1157
1034 private static void ProcessShpFlexiTension(PrimitiveBaseShape shp, XmlTextReader reader) 1158 private static void ProcessShpFlexiTension(PrimitiveBaseShape shp, XmlReader reader)
1035 { 1159 {
1036 shp.FlexiTension = reader.ReadElementContentAsFloat("FlexiTension", String.Empty); 1160 shp.FlexiTension = reader.ReadElementContentAsFloat("FlexiTension", String.Empty);
1037 } 1161 }
1038 1162
1039 private static void ProcessShpFlexiDrag(PrimitiveBaseShape shp, XmlTextReader reader) 1163 private static void ProcessShpFlexiDrag(PrimitiveBaseShape shp, XmlReader reader)
1040 { 1164 {
1041 shp.FlexiDrag = reader.ReadElementContentAsFloat("FlexiDrag", String.Empty); 1165 shp.FlexiDrag = reader.ReadElementContentAsFloat("FlexiDrag", String.Empty);
1042 } 1166 }
1043 1167
1044 private static void ProcessShpFlexiGravity(PrimitiveBaseShape shp, XmlTextReader reader) 1168 private static void ProcessShpFlexiGravity(PrimitiveBaseShape shp, XmlReader reader)
1045 { 1169 {
1046 shp.FlexiGravity = reader.ReadElementContentAsFloat("FlexiGravity", String.Empty); 1170 shp.FlexiGravity = reader.ReadElementContentAsFloat("FlexiGravity", String.Empty);
1047 } 1171 }
1048 1172
1049 private static void ProcessShpFlexiWind(PrimitiveBaseShape shp, XmlTextReader reader) 1173 private static void ProcessShpFlexiWind(PrimitiveBaseShape shp, XmlReader reader)
1050 { 1174 {
1051 shp.FlexiWind = reader.ReadElementContentAsFloat("FlexiWind", String.Empty); 1175 shp.FlexiWind = reader.ReadElementContentAsFloat("FlexiWind", String.Empty);
1052 } 1176 }
1053 1177
1054 private static void ProcessShpFlexiForceX(PrimitiveBaseShape shp, XmlTextReader reader) 1178 private static void ProcessShpFlexiForceX(PrimitiveBaseShape shp, XmlReader reader)
1055 { 1179 {
1056 shp.FlexiForceX = reader.ReadElementContentAsFloat("FlexiForceX", String.Empty); 1180 shp.FlexiForceX = reader.ReadElementContentAsFloat("FlexiForceX", String.Empty);
1057 } 1181 }
1058 1182
1059 private static void ProcessShpFlexiForceY(PrimitiveBaseShape shp, XmlTextReader reader) 1183 private static void ProcessShpFlexiForceY(PrimitiveBaseShape shp, XmlReader reader)
1060 { 1184 {
1061 shp.FlexiForceY = reader.ReadElementContentAsFloat("FlexiForceY", String.Empty); 1185 shp.FlexiForceY = reader.ReadElementContentAsFloat("FlexiForceY", String.Empty);
1062 } 1186 }
1063 1187
1064 private static void ProcessShpFlexiForceZ(PrimitiveBaseShape shp, XmlTextReader reader) 1188 private static void ProcessShpFlexiForceZ(PrimitiveBaseShape shp, XmlReader reader)
1065 { 1189 {
1066 shp.FlexiForceZ = reader.ReadElementContentAsFloat("FlexiForceZ", String.Empty); 1190 shp.FlexiForceZ = reader.ReadElementContentAsFloat("FlexiForceZ", String.Empty);
1067 } 1191 }
1068 1192
1069 private static void ProcessShpLightColorR(PrimitiveBaseShape shp, XmlTextReader reader) 1193 private static void ProcessShpLightColorR(PrimitiveBaseShape shp, XmlReader reader)
1070 { 1194 {
1071 shp.LightColorR = reader.ReadElementContentAsFloat("LightColorR", String.Empty); 1195 shp.LightColorR = reader.ReadElementContentAsFloat("LightColorR", String.Empty);
1072 } 1196 }
1073 1197
1074 private static void ProcessShpLightColorG(PrimitiveBaseShape shp, XmlTextReader reader) 1198 private static void ProcessShpLightColorG(PrimitiveBaseShape shp, XmlReader reader)
1075 { 1199 {
1076 shp.LightColorG = reader.ReadElementContentAsFloat("LightColorG", String.Empty); 1200 shp.LightColorG = reader.ReadElementContentAsFloat("LightColorG", String.Empty);
1077 } 1201 }
1078 1202
1079 private static void ProcessShpLightColorB(PrimitiveBaseShape shp, XmlTextReader reader) 1203 private static void ProcessShpLightColorB(PrimitiveBaseShape shp, XmlReader reader)
1080 { 1204 {
1081 shp.LightColorB = reader.ReadElementContentAsFloat("LightColorB", String.Empty); 1205 shp.LightColorB = reader.ReadElementContentAsFloat("LightColorB", String.Empty);
1082 } 1206 }
1083 1207
1084 private static void ProcessShpLightColorA(PrimitiveBaseShape shp, XmlTextReader reader) 1208 private static void ProcessShpLightColorA(PrimitiveBaseShape shp, XmlReader reader)
1085 { 1209 {
1086 shp.LightColorA = reader.ReadElementContentAsFloat("LightColorA", String.Empty); 1210 shp.LightColorA = reader.ReadElementContentAsFloat("LightColorA", String.Empty);
1087 } 1211 }
1088 1212
1089 private static void ProcessShpLightRadius(PrimitiveBaseShape shp, XmlTextReader reader) 1213 private static void ProcessShpLightRadius(PrimitiveBaseShape shp, XmlReader reader)
1090 { 1214 {
1091 shp.LightRadius = reader.ReadElementContentAsFloat("LightRadius", String.Empty); 1215 shp.LightRadius = reader.ReadElementContentAsFloat("LightRadius", String.Empty);
1092 } 1216 }
1093 1217
1094 private static void ProcessShpLightCutoff(PrimitiveBaseShape shp, XmlTextReader reader) 1218 private static void ProcessShpLightCutoff(PrimitiveBaseShape shp, XmlReader reader)
1095 { 1219 {
1096 shp.LightCutoff = reader.ReadElementContentAsFloat("LightCutoff", String.Empty); 1220 shp.LightCutoff = reader.ReadElementContentAsFloat("LightCutoff", String.Empty);
1097 } 1221 }
1098 1222
1099 private static void ProcessShpLightFalloff(PrimitiveBaseShape shp, XmlTextReader reader) 1223 private static void ProcessShpLightFalloff(PrimitiveBaseShape shp, XmlReader reader)
1100 { 1224 {
1101 shp.LightFalloff = reader.ReadElementContentAsFloat("LightFalloff", String.Empty); 1225 shp.LightFalloff = reader.ReadElementContentAsFloat("LightFalloff", String.Empty);
1102 } 1226 }
1103 1227
1104 private static void ProcessShpLightIntensity(PrimitiveBaseShape shp, XmlTextReader reader) 1228 private static void ProcessShpLightIntensity(PrimitiveBaseShape shp, XmlReader reader)
1105 { 1229 {
1106 shp.LightIntensity = reader.ReadElementContentAsFloat("LightIntensity", String.Empty); 1230 shp.LightIntensity = reader.ReadElementContentAsFloat("LightIntensity", String.Empty);
1107 } 1231 }
1108 1232
1109 private static void ProcessShpFlexiEntry(PrimitiveBaseShape shp, XmlTextReader reader) 1233 private static void ProcessShpFlexiEntry(PrimitiveBaseShape shp, XmlReader reader)
1110 { 1234 {
1111 shp.FlexiEntry = Util.ReadBoolean(reader); 1235 shp.FlexiEntry = Util.ReadBoolean(reader);
1112 } 1236 }
1113 1237
1114 private static void ProcessShpLightEntry(PrimitiveBaseShape shp, XmlTextReader reader) 1238 private static void ProcessShpLightEntry(PrimitiveBaseShape shp, XmlReader reader)
1115 { 1239 {
1116 shp.LightEntry = Util.ReadBoolean(reader); 1240 shp.LightEntry = Util.ReadBoolean(reader);
1117 } 1241 }
1118 1242
1119 private static void ProcessShpSculptEntry(PrimitiveBaseShape shp, XmlTextReader reader) 1243 private static void ProcessShpSculptEntry(PrimitiveBaseShape shp, XmlReader reader)
1120 { 1244 {
1121 shp.SculptEntry = Util.ReadBoolean(reader); 1245 shp.SculptEntry = Util.ReadBoolean(reader);
1122 } 1246 }
1123 1247
1124 private static void ProcessShpMedia(PrimitiveBaseShape shp, XmlTextReader reader) 1248 private static void ProcessShpMedia(PrimitiveBaseShape shp, XmlReader reader)
1125 { 1249 {
1126 string value = reader.ReadElementContentAsString("Media", String.Empty); 1250 string value = reader.ReadElementContentAsString("Media", String.Empty);
1127 shp.Media = PrimitiveBaseShape.MediaList.FromXml(value); 1251 shp.Media = PrimitiveBaseShape.MediaList.FromXml(value);
@@ -1144,6 +1268,16 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
1144 }); 1268 });
1145 1269
1146 writer.WriteEndElement(); 1270 writer.WriteEndElement();
1271
1272 if (sog.RootPart.KeyframeMotion != null)
1273 {
1274 Byte[] data = sog.RootPart.KeyframeMotion.Serialize();
1275
1276 writer.WriteStartElement(String.Empty, "KeyframeMotion", String.Empty);
1277 writer.WriteBase64(data, 0, data.Length);
1278 writer.WriteEndElement();
1279 }
1280
1147 writer.WriteEndElement(); 1281 writer.WriteEndElement();
1148 } 1282 }
1149 1283
@@ -1157,14 +1291,14 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
1157 1291
1158 WriteUUID(writer, "CreatorID", sop.CreatorID, options); 1292 WriteUUID(writer, "CreatorID", sop.CreatorID, options);
1159 1293
1160 if (sop.CreatorData != null && sop.CreatorData != string.Empty) 1294 if (!string.IsNullOrEmpty(sop.CreatorData))
1161 writer.WriteElementString("CreatorData", sop.CreatorData); 1295 writer.WriteElementString("CreatorData", sop.CreatorData);
1162 else if (options.ContainsKey("home")) 1296 else if (options.ContainsKey("home"))
1163 { 1297 {
1164 if (m_UserManagement == null) 1298 if (m_UserManagement == null)
1165 m_UserManagement = sop.ParentGroup.Scene.RequestModuleInterface<IUserManagement>(); 1299 m_UserManagement = sop.ParentGroup.Scene.RequestModuleInterface<IUserManagement>();
1166 string name = m_UserManagement.GetUserName(sop.CreatorID); 1300 string name = m_UserManagement.GetUserName(sop.CreatorID);
1167 writer.WriteElementString("CreatorData", (string)options["home"] + ";" + name); 1301 writer.WriteElementString("CreatorData", ExternalRepresentationUtils.CalcCreatorData((string)options["home"], name));
1168 } 1302 }
1169 1303
1170 WriteUUID(writer, "FolderID", sop.FolderID, options); 1304 WriteUUID(writer, "FolderID", sop.FolderID, options);
@@ -1217,7 +1351,9 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
1217 writer.WriteElementString("SalePrice", sop.SalePrice.ToString()); 1351 writer.WriteElementString("SalePrice", sop.SalePrice.ToString());
1218 writer.WriteElementString("ObjectSaleType", sop.ObjectSaleType.ToString()); 1352 writer.WriteElementString("ObjectSaleType", sop.ObjectSaleType.ToString());
1219 writer.WriteElementString("OwnershipCost", sop.OwnershipCost.ToString()); 1353 writer.WriteElementString("OwnershipCost", sop.OwnershipCost.ToString());
1220 WriteUUID(writer, "GroupID", sop.GroupID, options); 1354
1355 UUID groupID = options.ContainsKey("wipe-owners") ? UUID.Zero : sop.GroupID;
1356 WriteUUID(writer, "GroupID", groupID, options);
1221 1357
1222 UUID ownerID = options.ContainsKey("wipe-owners") ? UUID.Zero : sop.OwnerID; 1358 UUID ownerID = options.ContainsKey("wipe-owners") ? UUID.Zero : sop.OwnerID;
1223 WriteUUID(writer, "OwnerID", ownerID, options); 1359 WriteUUID(writer, "OwnerID", ownerID, options);
@@ -1235,6 +1371,15 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
1235 writer.WriteElementString("CollisionSoundVolume", sop.CollisionSoundVolume.ToString()); 1371 writer.WriteElementString("CollisionSoundVolume", sop.CollisionSoundVolume.ToString());
1236 if (sop.MediaUrl != null) 1372 if (sop.MediaUrl != null)
1237 writer.WriteElementString("MediaUrl", sop.MediaUrl.ToString()); 1373 writer.WriteElementString("MediaUrl", sop.MediaUrl.ToString());
1374 WriteVector(writer, "AttachedPos", sop.AttachedPos);
1375
1376 if (sop.DynAttrs.CountNamespaces > 0)
1377 {
1378 writer.WriteStartElement("DynAttrs");
1379 sop.DynAttrs.WriteXml(writer);
1380 writer.WriteEndElement();
1381 }
1382
1238 WriteBytes(writer, "TextureAnimation", sop.TextureAnimation); 1383 WriteBytes(writer, "TextureAnimation", sop.TextureAnimation);
1239 WriteBytes(writer, "ParticleSystem", sop.ParticleSystem); 1384 WriteBytes(writer, "ParticleSystem", sop.ParticleSystem);
1240 writer.WriteElementString("PayPrice0", sop.PayPrice[0].ToString()); 1385 writer.WriteElementString("PayPrice0", sop.PayPrice[0].ToString());
@@ -1243,6 +1388,17 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
1243 writer.WriteElementString("PayPrice3", sop.PayPrice[3].ToString()); 1388 writer.WriteElementString("PayPrice3", sop.PayPrice[3].ToString());
1244 writer.WriteElementString("PayPrice4", sop.PayPrice[4].ToString()); 1389 writer.WriteElementString("PayPrice4", sop.PayPrice[4].ToString());
1245 1390
1391 if(sop.PhysicsShapeType != sop.DefaultPhysicsShapeType())
1392 writer.WriteElementString("PhysicsShapeType", sop.PhysicsShapeType.ToString().ToLower());
1393 if (sop.Density != 1000.0f)
1394 writer.WriteElementString("Density", sop.Density.ToString().ToLower());
1395 if (sop.Friction != 0.6f)
1396 writer.WriteElementString("Friction", sop.Friction.ToString().ToLower());
1397 if (sop.Restitution != 0.5f)
1398 writer.WriteElementString("Bounce", sop.Restitution.ToString().ToLower());
1399 if (sop.GravityModifier != 1.0f)
1400 writer.WriteElementString("GravityModifier", sop.GravityModifier.ToString().ToLower());
1401
1246 writer.WriteEndElement(); 1402 writer.WriteEndElement();
1247 } 1403 }
1248 1404
@@ -1310,20 +1466,23 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
1310 1466
1311 WriteUUID(writer, "CreatorID", item.CreatorID, options); 1467 WriteUUID(writer, "CreatorID", item.CreatorID, options);
1312 1468
1313 if (item.CreatorData != null && item.CreatorData != string.Empty) 1469 if (!string.IsNullOrEmpty(item.CreatorData))
1314 writer.WriteElementString("CreatorData", item.CreatorData); 1470 writer.WriteElementString("CreatorData", item.CreatorData);
1315 else if (options.ContainsKey("home")) 1471 else if (options.ContainsKey("home"))
1316 { 1472 {
1317 if (m_UserManagement == null) 1473 if (m_UserManagement == null)
1318 m_UserManagement = scene.RequestModuleInterface<IUserManagement>(); 1474 m_UserManagement = scene.RequestModuleInterface<IUserManagement>();
1319 string name = m_UserManagement.GetUserName(item.CreatorID); 1475 string name = m_UserManagement.GetUserName(item.CreatorID);
1320 writer.WriteElementString("CreatorData", (string)options["home"] + ";" + name); 1476 writer.WriteElementString("CreatorData", ExternalRepresentationUtils.CalcCreatorData((string)options["home"], name));
1321 } 1477 }
1322 1478
1323 writer.WriteElementString("Description", item.Description); 1479 writer.WriteElementString("Description", item.Description);
1324 writer.WriteElementString("EveryonePermissions", item.EveryonePermissions.ToString()); 1480 writer.WriteElementString("EveryonePermissions", item.EveryonePermissions.ToString());
1325 writer.WriteElementString("Flags", item.Flags.ToString()); 1481 writer.WriteElementString("Flags", item.Flags.ToString());
1326 WriteUUID(writer, "GroupID", item.GroupID, options); 1482
1483 UUID groupID = options.ContainsKey("wipe-owners") ? UUID.Zero : item.GroupID;
1484 WriteUUID(writer, "GroupID", groupID, options);
1485
1327 writer.WriteElementString("GroupPermissions", item.GroupPermissions.ToString()); 1486 writer.WriteElementString("GroupPermissions", item.GroupPermissions.ToString());
1328 writer.WriteElementString("InvType", item.InvType.ToString()); 1487 writer.WriteElementString("InvType", item.InvType.ToString());
1329 WriteUUID(writer, "ItemID", item.ItemID, options); 1488 WriteUUID(writer, "ItemID", item.ItemID, options);
@@ -1344,7 +1503,9 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
1344 WriteUUID(writer, "PermsGranter", item.PermsGranter, options); 1503 WriteUUID(writer, "PermsGranter", item.PermsGranter, options);
1345 writer.WriteElementString("PermsMask", item.PermsMask.ToString()); 1504 writer.WriteElementString("PermsMask", item.PermsMask.ToString());
1346 writer.WriteElementString("Type", item.Type.ToString()); 1505 writer.WriteElementString("Type", item.Type.ToString());
1347 writer.WriteElementString("OwnerChanged", item.OwnerChanged.ToString().ToLower()); 1506
1507 bool ownerChanged = options.ContainsKey("wipe-owners") ? false : item.OwnerChanged;
1508 writer.WriteElementString("OwnerChanged", ownerChanged.ToString().ToLower());
1348 1509
1349 writer.WriteEndElement(); // TaskInventoryItem 1510 writer.WriteEndElement(); // TaskInventoryItem
1350 } 1511 }
@@ -1398,20 +1559,14 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
1398 writer.WriteElementString("ProfileEnd", shp.ProfileEnd.ToString()); 1559 writer.WriteElementString("ProfileEnd", shp.ProfileEnd.ToString());
1399 writer.WriteElementString("ProfileHollow", shp.ProfileHollow.ToString()); 1560 writer.WriteElementString("ProfileHollow", shp.ProfileHollow.ToString());
1400 writer.WriteElementString("State", shp.State.ToString()); 1561 writer.WriteElementString("State", shp.State.ToString());
1562 writer.WriteElementString("LastAttachPoint", shp.LastAttachPoint.ToString());
1401 1563
1402 WriteFlags(writer, "ProfileShape", shp.ProfileShape.ToString(), options); 1564 WriteFlags(writer, "ProfileShape", shp.ProfileShape.ToString(), options);
1403 WriteFlags(writer, "HollowShape", shp.HollowShape.ToString(), options); 1565 WriteFlags(writer, "HollowShape", shp.HollowShape.ToString(), options);
1404 1566
1405 WriteUUID(writer, "SculptTexture", shp.SculptTexture, options); 1567 WriteUUID(writer, "SculptTexture", shp.SculptTexture, options);
1406 writer.WriteElementString("SculptType", shp.SculptType.ToString()); 1568 writer.WriteElementString("SculptType", shp.SculptType.ToString());
1407 writer.WriteStartElement("SculptData"); 1569 // Don't serialize SculptData. It's just a copy of the asset, which can be loaded separately using 'SculptTexture'.
1408 byte[] sd;
1409 if (shp.SculptData != null)
1410 sd = shp.SculptData;
1411 else
1412 sd = Utils.EmptyBytes;
1413 writer.WriteBase64(sd, 0, sd.Length);
1414 writer.WriteEndElement(); // SculptData
1415 1570
1416 writer.WriteElementString("FlexiSoftness", shp.FlexiSoftness.ToString()); 1571 writer.WriteElementString("FlexiSoftness", shp.FlexiSoftness.ToString());
1417 writer.WriteElementString("FlexiTension", shp.FlexiTension.ToString()); 1572 writer.WriteElementString("FlexiTension", shp.FlexiTension.ToString());
@@ -1442,28 +1597,31 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
1442 } 1597 }
1443 } 1598 }
1444 1599
1445 public static SceneObjectPart Xml2ToSOP(XmlTextReader reader) 1600 public static SceneObjectPart Xml2ToSOP(XmlReader reader)
1446 { 1601 {
1447 SceneObjectPart obj = new SceneObjectPart(); 1602 SceneObjectPart obj = new SceneObjectPart();
1448 1603
1449 reader.ReadStartElement("SceneObjectPart"); 1604 reader.ReadStartElement("SceneObjectPart");
1450 1605
1451 ExternalRepresentationUtils.ExecuteReadProcessors( 1606 bool errors = ExternalRepresentationUtils.ExecuteReadProcessors(
1452 obj, 1607 obj,
1453 m_SOPXmlProcessors, 1608 m_SOPXmlProcessors,
1454 reader, 1609 reader,
1455 (o, nodeName, e) 1610 (o, nodeName, e) => {
1456 => m_log.DebugFormat( 1611 m_log.Debug(string.Format("[SceneObjectSerializer]: Error while parsing element {0} in object {1} {2} ",
1457 "[SceneObjectSerializer]: Exception while parsing {0} in object {1} {2}: {3}{4}", 1612 nodeName, ((SceneObjectPart)o).Name, ((SceneObjectPart)o).UUID), e);
1458 ((SceneObjectPart)o).Name, ((SceneObjectPart)o).UUID, nodeName, e.Message, e.StackTrace)); 1613 });
1614
1615 if (errors)
1616 throw new XmlException(string.Format("Error parsing object {0} {1}", obj.Name, obj.UUID));
1459 1617
1460 reader.ReadEndElement(); // SceneObjectPart 1618 reader.ReadEndElement(); // SceneObjectPart
1461 1619
1462 //m_log.DebugFormat("[XXX]: parsed SOP {0} - {1}", obj.Name, obj.UUID); 1620 // m_log.DebugFormat("[SceneObjectSerializer]: parsed SOP {0} {1}", obj.Name, obj.UUID);
1463 return obj; 1621 return obj;
1464 } 1622 }
1465 1623
1466 public static TaskInventoryDictionary ReadTaskInventory(XmlTextReader reader, string name) 1624 public static TaskInventoryDictionary ReadTaskInventory(XmlReader reader, string name)
1467 { 1625 {
1468 TaskInventoryDictionary tinv = new TaskInventoryDictionary(); 1626 TaskInventoryDictionary tinv = new TaskInventoryDictionary();
1469 1627
@@ -1504,7 +1662,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
1504 /// <param name="name">The name of the xml element containing the shape</param> 1662 /// <param name="name">The name of the xml element containing the shape</param>
1505 /// <param name="errors">a list containing the failing node names. If no failures then null.</param> 1663 /// <param name="errors">a list containing the failing node names. If no failures then null.</param>
1506 /// <returns>The shape parsed</returns> 1664 /// <returns>The shape parsed</returns>
1507 public static PrimitiveBaseShape ReadShape(XmlTextReader reader, string name, out List<string> errorNodeNames) 1665 public static PrimitiveBaseShape ReadShape(XmlReader reader, string name, out List<string> errorNodeNames, SceneObjectPart obj)
1508 { 1666 {
1509 List<string> internalErrorNodeNames = null; 1667 List<string> internalErrorNodeNames = null;
1510 1668
@@ -1523,18 +1681,14 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
1523 shape, 1681 shape,
1524 m_ShapeXmlProcessors, 1682 m_ShapeXmlProcessors,
1525 reader, 1683 reader,
1526 (o, nodeName, e) 1684 (o, nodeName, e) => {
1527 => 1685 m_log.Debug(string.Format("[SceneObjectSerializer]: Error while parsing element {0} in Shape property of object {1} {2} ",
1528 { 1686 nodeName, obj.Name, obj.UUID), e);
1529// m_log.DebugFormat(
1530// "[SceneObjectSerializer]: Exception while parsing Shape property {0}: {1}{2}",
1531// nodeName, e.Message, e.StackTrace);
1532 if (internalErrorNodeNames == null)
1533 internalErrorNodeNames = new List<string>();
1534 1687
1535 internalErrorNodeNames.Add(nodeName); 1688 if (internalErrorNodeNames == null)
1536 } 1689 internalErrorNodeNames = new List<string>();
1537 ); 1690 internalErrorNodeNames.Add(nodeName);
1691 });
1538 1692
1539 reader.ReadEndElement(); // Shape 1693 reader.ReadEndElement(); // Shape
1540 1694
diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneXmlLoader.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneXmlLoader.cs
index a3485d2..3c03130 100644
--- a/OpenSim/Region/Framework/Scenes/Serialization/SceneXmlLoader.cs
+++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneXmlLoader.cs
@@ -34,7 +34,7 @@ using OpenMetaverse;
34using log4net; 34using log4net;
35using OpenSim.Framework; 35using OpenSim.Framework;
36using OpenSim.Region.Framework.Scenes; 36using OpenSim.Region.Framework.Scenes;
37using OpenSim.Region.Physics.Manager; 37using OpenSim.Region.PhysicsModules.SharedBase;
38 38
39namespace OpenSim.Region.Framework.Scenes.Serialization 39namespace OpenSim.Region.Framework.Scenes.Serialization
40{ 40{
diff --git a/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs b/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs
index b9d615e..3effee7 100644..100755
--- a/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs
+++ b/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs
@@ -61,6 +61,10 @@ namespace OpenSim.Region.Framework.Scenes
61 61
62 private YourStatsAreWrong handlerStatsIncorrect; 62 private YourStatsAreWrong handlerStatsIncorrect;
63 63
64 // Determines the size of the array that is used to collect StatBlocks
65 // for sending to the SimStats and SimExtraStatsCollector
66 private const int m_statisticArraySize = 28;
67
64 /// <summary> 68 /// <summary>
65 /// These are the IDs of stats sent in the StatsPacket to the viewer. 69 /// These are the IDs of stats sent in the StatsPacket to the viewer.
66 /// </summary> 70 /// </summary>
@@ -104,7 +108,12 @@ namespace OpenSim.Region.Framework.Scenes
104 ScriptEps = 31, 108 ScriptEps = 31,
105 SimSpareMs = 32, 109 SimSpareMs = 32,
106 SimSleepMs = 33, 110 SimSleepMs = 33,
107 SimIoPumpTime = 34 111 SimIoPumpTime = 34,
112 FrameDilation = 35,
113 UsersLoggingIn = 36,
114 TotalGeoPrim = 37,
115 TotalMesh = 38,
116 ThreadCount = 39
108 } 117 }
109 118
110 /// <summary> 119 /// <summary>
@@ -167,15 +176,20 @@ namespace OpenSim.Region.Framework.Scenes
167 /// Parameter to adjust reported scene fps 176 /// Parameter to adjust reported scene fps
168 /// </summary> 177 /// </summary>
169 /// <remarks> 178 /// <remarks>
170 /// Our scene loop runs slower than other server implementations, apparantly because we work somewhat differently. 179 /// The close we have to a frame rate as expected by viewers, users and scripts
171 /// However, we will still report an FPS that's closer to what people are used to seeing. A lower FPS might 180 /// is heartbeat rate.
172 /// affect clients and monitoring scripts/software. 181 /// heartbeat rate default value is very diferent from the expected one
182 /// and can be changed from region to region acording to its specific simulation needs
183 /// since this creates incompatibility with expected values,
184 /// this scale factor can be used to normalize values to a Virtual FPS.
185 /// original decision was to use a value of 55fps for all opensim
186 /// corresponding, with default heartbeat rate, to a value of 5.
173 /// </remarks> 187 /// </remarks>
174 private float m_reportedFpsCorrectionFactor = 5; 188 private float m_statisticsFPSfactor = 5.0f;
175 189
176 // saved last reported value so there is something available for llGetRegionFPS 190 // saved last reported value so there is something available for llGetRegionFPS
177 private float lastReportedSimFPS; 191 private float lastReportedSimFPS;
178 private float[] lastReportedSimStats = new float[22]; 192 private float[] lastReportedSimStats = new float[m_statisticArraySize];
179 private float m_pfps; 193 private float m_pfps;
180 194
181 /// <summary> 195 /// <summary>
@@ -195,13 +209,13 @@ namespace OpenSim.Region.Framework.Scenes
195 private int m_physicsMS; 209 private int m_physicsMS;
196 private int m_imageMS; 210 private int m_imageMS;
197 private int m_otherMS; 211 private int m_otherMS;
198 212 private int m_scriptMS;
199//Ckrinke: (3-21-08) Comment out to remove a compiler warning. Bring back into play when needed.
200//Ckrinke private int m_scriptMS = 0;
201 213
202 private int m_rootAgents; 214 private int m_rootAgents;
203 private int m_childAgents; 215 private int m_childAgents;
204 private int m_numPrim; 216 private int m_numPrim;
217 private int m_numGeoPrim;
218 private int m_numMesh;
205 private int m_inPacketsPerSecond; 219 private int m_inPacketsPerSecond;
206 private int m_outPacketsPerSecond; 220 private int m_outPacketsPerSecond;
207 private int m_activePrim; 221 private int m_activePrim;
@@ -213,6 +227,34 @@ namespace OpenSim.Region.Framework.Scenes
213 227
214 private int m_objectCapacity = 45000; 228 private int m_objectCapacity = 45000;
215 229
230 // This is the number of frames that will be stored and then averaged for
231 // the Total, Simulation, Physics, and Network Frame Time; It is set to
232 // 10 by default but can be changed by the OpenSim.ini configuration file
233 // NumberOfFrames parameter
234 private int m_numberFramesStored;
235
236 // The arrays that will hold the time it took to run the past N frames,
237 // where N is the num_frames_to_average given by the configuration file
238 private double[] m_totalFrameTimeMilliseconds;
239 private double[] m_simulationFrameTimeMilliseconds;
240 private double[] m_physicsFrameTimeMilliseconds;
241 private double[] m_networkFrameTimeMilliseconds;
242
243 // The location of the next time in milliseconds that will be
244 // (over)written when the next frame completes
245 private int m_nextLocation = 0;
246
247 // The correct number of frames that have completed since the last stats
248 // update for physics
249 private int m_numberPhysicsFrames;
250
251 // The current number of users attempting to login to the region
252 private int m_usersLoggingIn;
253
254 // The last reported value of threads from the SmartThreadPool inside of
255 // XEngine
256 private int m_inUseThreads;
257
216 private Scene m_scene; 258 private Scene m_scene;
217 259
218 private RegionInfo ReportingRegion; 260 private RegionInfo ReportingRegion;
@@ -222,12 +264,34 @@ namespace OpenSim.Region.Framework.Scenes
222 private IEstateModule estateModule; 264 private IEstateModule estateModule;
223 265
224 public SimStatsReporter(Scene scene) 266 public SimStatsReporter(Scene scene)
267 : this(scene, Scene.m_defaultNumberFramesStored)
268 {
269 }
270
271 public SimStatsReporter(Scene scene, int numberOfFrames)
225 { 272 {
273 // Store the number of frames from the OpenSim.ini configuration file
274 m_numberFramesStored = numberOfFrames;
275
276 // Initialize the different frame time arrays to the correct sizes
277 m_totalFrameTimeMilliseconds = new double[m_numberFramesStored];
278 m_simulationFrameTimeMilliseconds = new double[m_numberFramesStored];
279 m_physicsFrameTimeMilliseconds = new double[m_numberFramesStored];
280 m_networkFrameTimeMilliseconds = new double[m_numberFramesStored];
281
282 // Initialize the current number of users logging into the region
283 m_usersLoggingIn = 0;
284
226 m_scene = scene; 285 m_scene = scene;
227 m_reportedFpsCorrectionFactor = scene.MinFrameTime * m_nominalReportedFps; 286
228 m_statsUpdateFactor = (float)(m_statsUpdatesEveryMS / 1000); 287 m_statsUpdateFactor = (float)(m_statsUpdatesEveryMS / 1000);
229 ReportingRegion = scene.RegionInfo; 288 ReportingRegion = scene.RegionInfo;
230 289
290 if(scene.Normalized55FPS)
291 m_statisticsFPSfactor = 55.0f * m_scene.MinFrameTicks / 1000.0f;
292 else
293 m_statisticsFPSfactor = 1.0f;
294
231 m_objectCapacity = scene.RegionInfo.ObjectCapacity; 295 m_objectCapacity = scene.RegionInfo.ObjectCapacity;
232 m_report.AutoReset = true; 296 m_report.AutoReset = true;
233 m_report.Interval = m_statsUpdatesEveryMS; 297 m_report.Interval = m_statsUpdatesEveryMS;
@@ -239,7 +303,7 @@ namespace OpenSim.Region.Framework.Scenes
239 303
240 /// At the moment, we'll only report if a frame is over 120% of target, since commonly frames are a bit 304 /// At the moment, we'll only report if a frame is over 120% of target, since commonly frames are a bit
241 /// longer than ideal (which in itself is a concern). 305 /// longer than ideal (which in itself is a concern).
242 SlowFramesStatReportThreshold = (int)Math.Ceiling(m_scene.MinFrameTime * 1000 * 1.2); 306 SlowFramesStatReportThreshold = (int)Math.Ceiling(scene.MinFrameTicks * 1.2);
243 307
244 SlowFramesStat 308 SlowFramesStat
245 = new Stat( 309 = new Stat(
@@ -254,8 +318,10 @@ namespace OpenSim.Region.Framework.Scenes
254 StatVerbosity.Info); 318 StatVerbosity.Info);
255 319
256 StatsManager.RegisterStat(SlowFramesStat); 320 StatsManager.RegisterStat(SlowFramesStat);
321
257 } 322 }
258 323
324
259 public void Close() 325 public void Close()
260 { 326 {
261 m_report.Elapsed -= TriggerStatsHeartbeat; 327 m_report.Elapsed -= TriggerStatsHeartbeat;
@@ -289,7 +355,21 @@ namespace OpenSim.Region.Framework.Scenes
289 355
290 private void statsHeartBeat(object sender, EventArgs e) 356 private void statsHeartBeat(object sender, EventArgs e)
291 { 357 {
292 SimStatsPacket.StatBlock[] sb = new SimStatsPacket.StatBlock[22]; 358 double totalSumFrameTime;
359 double simulationSumFrameTime;
360 double physicsSumFrameTime;
361 double networkSumFrameTime;
362 float frameDilation;
363 int currentFrame;
364
365 if (!m_scene.Active)
366 return;
367
368 // Create arrays to hold the statistics for this current scene,
369 // these will be passed to the SimExtraStatsCollector, they are also
370 // sent to the SimStats class
371 SimStatsPacket.StatBlock[] sb = new
372 SimStatsPacket.StatBlock[m_statisticArraySize];
293 SimStatsPacket.RegionBlock rb = new SimStatsPacket.RegionBlock(); 373 SimStatsPacket.RegionBlock rb = new SimStatsPacket.RegionBlock();
294 374
295 // Know what's not thread safe in Mono... modifying timers. 375 // Know what's not thread safe in Mono... modifying timers.
@@ -311,14 +391,15 @@ namespace OpenSim.Region.Framework.Scenes
311 391
312#region various statistic googly moogly 392#region various statistic googly moogly
313 393
314 // We're going to lie about the FPS because we've been lying since 2008. The actual FPS is currently 394 int reportedFPS = (int)(m_fps * m_statisticsFPSfactor);
315 // locked at a maximum of 11. Maybe at some point this can change so that we're not lying.
316 int reportedFPS = (int)(m_fps * m_reportedFpsCorrectionFactor);
317 395
318 // save the reported value so there is something available for llGetRegionFPS 396 // save the reported value so there is something available for llGetRegionFPS
319 lastReportedSimFPS = reportedFPS / m_statsUpdateFactor; 397 lastReportedSimFPS = reportedFPS / m_statsUpdateFactor;
320 398
321 float physfps = ((m_pfps / 1000)); 399 // ORIGINAL code commented out until we have time to add our own
400 // statistics to the statistics window
401 //float physfps = ((m_pfps / 1000));
402 float physfps = m_numberPhysicsFrames * m_statisticsFPSfactor;
322 403
323 //if (physfps > 600) 404 //if (physfps > 600)
324 //physfps = physfps - (physfps - 600); 405 //physfps = physfps - (physfps - 600);
@@ -331,6 +412,8 @@ namespace OpenSim.Region.Framework.Scenes
331 m_rootAgents = m_scene.SceneGraph.GetRootAgentCount(); 412 m_rootAgents = m_scene.SceneGraph.GetRootAgentCount();
332 m_childAgents = m_scene.SceneGraph.GetChildAgentCount(); 413 m_childAgents = m_scene.SceneGraph.GetChildAgentCount();
333 m_numPrim = m_scene.SceneGraph.GetTotalObjectsCount(); 414 m_numPrim = m_scene.SceneGraph.GetTotalObjectsCount();
415 m_numGeoPrim = m_scene.SceneGraph.GetTotalPrimObjectsCount();
416 m_numMesh = m_scene.SceneGraph.GetTotalMeshObjectsCount();
334 m_activePrim = m_scene.SceneGraph.GetActiveObjectsCount(); 417 m_activePrim = m_scene.SceneGraph.GetActiveObjectsCount();
335 m_activeScripts = m_scene.SceneGraph.GetActiveScriptsCount(); 418 m_activeScripts = m_scene.SceneGraph.GetActiveScriptsCount();
336 419
@@ -349,18 +432,52 @@ namespace OpenSim.Region.Framework.Scenes
349 // values to X-per-second values. 432 // values to X-per-second values.
350 433
351 uint thisFrame = m_scene.Frame; 434 uint thisFrame = m_scene.Frame;
352 float framesUpdated = (float)(thisFrame - m_lastUpdateFrame) * m_reportedFpsCorrectionFactor; 435 uint numFrames = thisFrame - m_lastUpdateFrame;
436 float framesUpdated = (float)numFrames * m_statisticsFPSfactor;
353 m_lastUpdateFrame = thisFrame; 437 m_lastUpdateFrame = thisFrame;
354 438
355 // Avoid div-by-zero if somehow we've not updated any frames. 439 // Avoid div-by-zero if somehow we've not updated any frames.
356 if (framesUpdated == 0) 440 if (framesUpdated == 0)
357 framesUpdated = 1; 441 framesUpdated = 1;
358 442
359 for (int i = 0; i < 22; i++) 443 for (int i = 0; i < m_statisticArraySize; i++)
360 { 444 {
361 sb[i] = new SimStatsPacket.StatBlock(); 445 sb[i] = new SimStatsPacket.StatBlock();
362 } 446 }
363 447
448 // Resetting the sums of the frame times to prevent any errors
449 // in calculating the moving average for frame time
450 totalSumFrameTime = 0;
451 simulationSumFrameTime = 0;
452 physicsSumFrameTime = 0;
453 networkSumFrameTime = 0;
454
455 // Loop through all the frames that were stored for the current
456 // heartbeat to process the moving average of frame times
457 for (int i = 0; i < m_numberFramesStored; i++)
458 {
459 // Sum up each frame time in order to calculate the moving
460 // average of frame time
461 totalSumFrameTime += m_totalFrameTimeMilliseconds[i];
462 simulationSumFrameTime +=
463 m_simulationFrameTimeMilliseconds[i];
464 physicsSumFrameTime += m_physicsFrameTimeMilliseconds[i];
465 networkSumFrameTime += m_networkFrameTimeMilliseconds[i];
466 }
467
468 // Get the index that represents the current frame based on the next one known; go back
469 // to the last index if next one is stated to restart at 0
470 if (m_nextLocation == 0)
471 currentFrame = m_numberFramesStored - 1;
472 else
473 currentFrame = m_nextLocation - 1;
474
475 // Calculate the frame dilation; which is currently based on the ratio between the sum of the
476 // physics and simulation rate, and the set minimum time to run a scene's frame
477 frameDilation = (float)(m_simulationFrameTimeMilliseconds[currentFrame] +
478 m_physicsFrameTimeMilliseconds[currentFrame]) / m_scene.MinFrameTicks;
479
480 // ORIGINAL code commented out until we have time to add our own
364 sb[0].StatID = (uint) Stats.TimeDilation; 481 sb[0].StatID = (uint) Stats.TimeDilation;
365 sb[0].StatValue = (Single.IsNaN(m_timeDilation)) ? 0.1f : m_timeDilation ; //((((m_timeDilation + (0.10f * statsUpdateFactor)) /10) / statsUpdateFactor)); 482 sb[0].StatValue = (Single.IsNaN(m_timeDilation)) ? 0.1f : m_timeDilation ; //((((m_timeDilation + (0.10f * statsUpdateFactor)) /10) / statsUpdateFactor));
366 483
@@ -385,20 +502,26 @@ namespace OpenSim.Region.Framework.Scenes
385 sb[7].StatID = (uint) Stats.ActivePrim; 502 sb[7].StatID = (uint) Stats.ActivePrim;
386 sb[7].StatValue = m_activePrim; 503 sb[7].StatValue = m_activePrim;
387 504
505 // ORIGINAL code commented out until we have time to add our own
506 // statistics to the statistics window
388 sb[8].StatID = (uint)Stats.FrameMS; 507 sb[8].StatID = (uint)Stats.FrameMS;
389 sb[8].StatValue = m_frameMS / framesUpdated; 508 //sb[8].StatValue = m_frameMS / framesUpdated;
509 sb[8].StatValue = (float) totalSumFrameTime / m_numberFramesStored / m_statisticsFPSfactor;
390 510
391 sb[9].StatID = (uint)Stats.NetMS; 511 sb[9].StatID = (uint)Stats.NetMS;
392 sb[9].StatValue = m_netMS / framesUpdated; 512 //sb[9].StatValue = m_netMS / framesUpdated;
513 sb[9].StatValue = (float) networkSumFrameTime / m_numberFramesStored / m_statisticsFPSfactor;
393 514
394 sb[10].StatID = (uint)Stats.PhysicsMS; 515 sb[10].StatID = (uint)Stats.PhysicsMS;
395 sb[10].StatValue = m_physicsMS / framesUpdated; 516 //sb[10].StatValue = m_physicsMS / framesUpdated;
517 sb[10].StatValue = (float) physicsSumFrameTime / m_numberFramesStored / m_statisticsFPSfactor;
396 518
397 sb[11].StatID = (uint)Stats.ImageMS ; 519 sb[11].StatID = (uint)Stats.ImageMS ;
398 sb[11].StatValue = m_imageMS / framesUpdated; 520 sb[11].StatValue = m_imageMS / framesUpdated;
399 521
400 sb[12].StatID = (uint)Stats.OtherMS; 522 sb[12].StatID = (uint)Stats.OtherMS;
401 sb[12].StatValue = m_otherMS / framesUpdated; 523 //sb[12].StatValue = m_otherMS / framesUpdated;
524 sb[12].StatValue = (float) simulationSumFrameTime / m_numberFramesStored / m_statisticsFPSfactor;
402 525
403 sb[13].StatID = (uint)Stats.InPacketsPerSecond; 526 sb[13].StatID = (uint)Stats.InPacketsPerSecond;
404 sb[13].StatValue = (m_inPacketsPerSecond / m_statsUpdateFactor); 527 sb[13].StatValue = (m_inPacketsPerSecond / m_statsUpdateFactor);
@@ -427,7 +550,31 @@ namespace OpenSim.Region.Framework.Scenes
427 sb[21].StatID = (uint)Stats.SimSpareMs; 550 sb[21].StatID = (uint)Stats.SimSpareMs;
428 sb[21].StatValue = m_spareMS / framesUpdated; 551 sb[21].StatValue = m_spareMS / framesUpdated;
429 552
430 for (int i = 0; i < 22; i++) 553 // Current ratio between the sum of physics and sim rate, and the
554 // minimum time to run a scene's frame
555 sb[22].StatID = (uint)Stats.FrameDilation;
556 sb[22].StatValue = frameDilation;
557
558 // Current number of users currently attemptint to login to region
559 sb[23].StatID = (uint)Stats.UsersLoggingIn;
560 sb[23].StatValue = m_usersLoggingIn;
561
562 // Total number of geometric primitives in the scene
563 sb[24].StatID = (uint)Stats.TotalGeoPrim;
564 sb[24].StatValue = m_numGeoPrim;
565
566 // Total number of mesh objects in the scene
567 sb[25].StatID = (uint)Stats.TotalMesh;
568 sb[25].StatValue = m_numMesh;
569
570 // Current number of threads that XEngine is using
571 sb[26].StatID = (uint)Stats.ThreadCount;
572 sb[26].StatValue = m_inUseThreads;
573
574 sb[27].StatID = (uint)Stats.ScriptMS;
575 sb[27].StatValue = (numFrames <= 0) ? 0 : ((float)m_scriptMS / numFrames);
576
577 for (int i = 0; i < m_statisticArraySize; i++)
431 { 578 {
432 lastReportedSimStats[i] = sb[i].StatValue; 579 lastReportedSimStats[i] = sb[i].StatValue;
433 } 580 }
@@ -472,6 +619,10 @@ namespace OpenSim.Region.Framework.Scenes
472 619
473 private void ResetValues() 620 private void ResetValues()
474 { 621 {
622 // Reset the number of frames that the physics library has
623 // processed since the last stats report
624 m_numberPhysicsFrames = 0;
625
475 m_timeDilation = 0; 626 m_timeDilation = 0;
476 m_fps = 0; 627 m_fps = 0;
477 m_pfps = 0; 628 m_pfps = 0;
@@ -488,10 +639,8 @@ namespace OpenSim.Region.Framework.Scenes
488 m_physicsMS = 0; 639 m_physicsMS = 0;
489 m_imageMS = 0; 640 m_imageMS = 0;
490 m_otherMS = 0; 641 m_otherMS = 0;
642 m_scriptMS = 0;
491 m_spareMS = 0; 643 m_spareMS = 0;
492
493//Ckrinke This variable is not used, so comment to remove compiler warning until it is used.
494//Ckrinke m_scriptMS = 0;
495 } 644 }
496 645
497 # region methods called from Scene 646 # region methods called from Scene
@@ -602,6 +751,37 @@ namespace OpenSim.Region.Framework.Scenes
602 m_otherMS += ms; 751 m_otherMS += ms;
603 } 752 }
604 753
754 public void AddScriptMS(int ms)
755 {
756 m_scriptMS += ms;
757 }
758
759 public void addPhysicsFrame(int frames)
760 {
761 // Add the number of physics frames to the correct total physics
762 // frames
763 m_numberPhysicsFrames += frames;
764 }
765
766 public void addFrameTimeMilliseconds(double total, double simulation,
767 double physics, double network)
768 {
769 // Save the frame times from the current frame into the appropriate
770 // arrays
771 m_totalFrameTimeMilliseconds[m_nextLocation] = total;
772 m_simulationFrameTimeMilliseconds[m_nextLocation] = simulation;
773 m_physicsFrameTimeMilliseconds[m_nextLocation] = physics;
774 m_networkFrameTimeMilliseconds[m_nextLocation] = network;
775
776 // Update to the next location in the list
777 m_nextLocation++;
778
779 // Since the list will begin to overwrite the oldest frame values
780 // first, the next location needs to loop back to the beginning of the
781 // list whenever it reaches the end
782 m_nextLocation = m_nextLocation % m_numberFramesStored;
783 }
784
605 public void AddPendingDownloads(int count) 785 public void AddPendingDownloads(int count)
606 { 786 {
607 m_pendingDownloads += count; 787 m_pendingDownloads += count;
@@ -624,6 +804,31 @@ namespace OpenSim.Region.Framework.Scenes
624 AddunAckedBytes(unAckedBytes); 804 AddunAckedBytes(unAckedBytes);
625 } 805 }
626 806
807 public void UpdateUsersLoggingIn(bool isLoggingIn)
808 {
809 // Determine whether the user has started logging in or has completed
810 // logging into the region
811 if (isLoggingIn)
812 {
813 // The user is starting to login to the region so increment the
814 // number of users attempting to login to the region
815 m_usersLoggingIn++;
816 }
817 else
818 {
819 // The user has finished logging into the region so decrement the
820 // number of users logging into the region
821 m_usersLoggingIn--;
822 }
823 }
824
825 public void SetThreadCount(int inUseThreads)
826 {
827 // Save the new number of threads to our member variable to send to
828 // the extra stats collector
829 m_inUseThreads = inUseThreads;
830 }
831
627 #endregion 832 #endregion
628 833
629 public Dictionary<string, float> GetExtraSimStats() 834 public Dictionary<string, float> GetExtraSimStats()
diff --git a/OpenSim/Region/Framework/Scenes/TerrainChannel.cs b/OpenSim/Region/Framework/Scenes/TerrainChannel.cs
index c0ca48e..3d563a6 100644
--- a/OpenSim/Region/Framework/Scenes/TerrainChannel.cs
+++ b/OpenSim/Region/Framework/Scenes/TerrainChannel.cs
@@ -25,14 +25,21 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using OpenSim.Framework;
29using OpenSim.Region.Framework.Interfaces;
30using System; 28using System;
29using System.IO;
31using System.Text; 30using System.Text;
31using System.Reflection;
32using System.Xml; 32using System.Xml;
33using System.IO;
34using System.Xml.Serialization; 33using System.Xml.Serialization;
35 34
35using OpenSim.Data;
36using OpenSim.Framework;
37using OpenSim.Region.Framework.Interfaces;
38
39using OpenMetaverse;
40
41using log4net;
42
36namespace OpenSim.Region.Framework.Scenes 43namespace OpenSim.Region.Framework.Scenes
37{ 44{
38 /// <summary> 45 /// <summary>
@@ -40,132 +47,136 @@ namespace OpenSim.Region.Framework.Scenes
40 /// </summary> 47 /// </summary>
41 public class TerrainChannel : ITerrainChannel 48 public class TerrainChannel : ITerrainChannel
42 { 49 {
43 private readonly bool[,] taint; 50 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
44 private double[,] map; 51 private static string LogHeader = "[TERRAIN CHANNEL]";
52
53 protected TerrainData m_terrainData;
54
55 public int Width { get { return m_terrainData.SizeX; } } // X dimension
56 // Unfortunately, for historical reasons, in this module 'Width' is X and 'Height' is Y
57 public int Height { get { return m_terrainData.SizeY; } } // Y dimension
58 public int Altitude { get { return m_terrainData.SizeZ; } } // Y dimension
45 59
60 // Default, not-often-used builder
46 public TerrainChannel() 61 public TerrainChannel()
47 { 62 {
48 map = new double[Constants.RegionSize, Constants.RegionSize]; 63 m_terrainData = new HeightmapTerrainData((int)Constants.RegionSize, (int)Constants.RegionSize, (int)Constants.RegionHeight);
49 taint = new bool[Constants.RegionSize / 16, Constants.RegionSize / 16]; 64 FlatLand();
50 65 // PinHeadIsland();
51 PinHeadIsland();
52 } 66 }
53 67
54 public TerrainChannel(String type) 68 // Create terrain of given size
69 public TerrainChannel(int pX, int pY)
55 { 70 {
56 map = new double[Constants.RegionSize, Constants.RegionSize]; 71 m_terrainData = new HeightmapTerrainData(pX, pY, (int)Constants.RegionHeight);
57 taint = new bool[Constants.RegionSize / 16, Constants.RegionSize / 16]; 72 }
58 73
74 // Create terrain of specified size and initialize with specified terrain.
75 // TODO: join this with the terrain initializers.
76 public TerrainChannel(String type, int pX, int pY, int pZ)
77 {
78 m_terrainData = new HeightmapTerrainData(pX, pY, pZ);
59 if (type.Equals("flat")) 79 if (type.Equals("flat"))
60 FlatLand(); 80 FlatLand();
61 else 81 else
62 PinHeadIsland(); 82 PinHeadIsland();
63 } 83 }
64 84
65 public TerrainChannel(double[,] import) 85 // Create channel passed a heightmap and expected dimensions of the region.
86 // The heightmap might not fit the passed size so accomodations must be made.
87 public TerrainChannel(double[,] pM, int pSizeX, int pSizeY, int pAltitude)
66 { 88 {
67 map = import; 89 int hmSizeX = pM.GetLength(0);
68 taint = new bool[import.GetLength(0),import.GetLength(1)]; 90 int hmSizeY = pM.GetLength(1);
69 }
70 91
71 public TerrainChannel(bool createMap) 92 m_terrainData = new HeightmapTerrainData(pSizeX, pSizeY, pAltitude);
72 { 93
73 if (createMap) 94 for (int xx = 0; xx < pSizeX; xx++)
74 { 95 for (int yy = 0; yy < pSizeY; yy++)
75 map = new double[Constants.RegionSize,Constants.RegionSize]; 96 if (xx > hmSizeX || yy > hmSizeY)
76 taint = new bool[Constants.RegionSize / 16,Constants.RegionSize / 16]; 97 m_terrainData[xx, yy] = TerrainData.DefaultTerrainHeight;
77 } 98 else
99 m_terrainData[xx, yy] = (float)pM[xx, yy];
78 } 100 }
79 101
80 public TerrainChannel(int w, int h) 102 public TerrainChannel(TerrainData pTerrData)
81 { 103 {
82 map = new double[w,h]; 104 m_terrainData = pTerrData;
83 taint = new bool[w / 16,h / 16];
84 } 105 }
85 106
86 #region ITerrainChannel Members 107 #region ITerrainChannel Members
87 108
88 public int Width 109 // ITerrainChannel.MakeCopy()
110 public ITerrainChannel MakeCopy()
89 { 111 {
90 get { return map.GetLength(0); } 112 return this.Copy();
91 } 113 }
92 114
93 public int Height 115 // ITerrainChannel.GetTerrainData()
116 public TerrainData GetTerrainData()
94 { 117 {
95 get { return map.GetLength(1); } 118 return m_terrainData;
96 } 119 }
97 120
98 public ITerrainChannel MakeCopy() 121 // ITerrainChannel.GetFloatsSerialized()
122 // This one dimensional version is ordered so height = map[y*sizeX+x];
123 // DEPRECATED: don't use this function as it does not retain the dimensions of the terrain
124 // and the caller will probably do the wrong thing if the terrain is not the legacy 256x256.
125 public float[] GetFloatsSerialised()
99 { 126 {
100 TerrainChannel copy = new TerrainChannel(false); 127 return m_terrainData.GetFloatsSerialized();
101 copy.map = (double[,]) map.Clone();
102
103 return copy;
104 } 128 }
105 129
106 public float[] GetFloatsSerialised() 130 // ITerrainChannel.GetDoubles()
131 public double[,] GetDoubles()
107 { 132 {
108 // Move the member variables into local variables, calling 133 double[,] heights = new double[Width, Height];
109 // member variables 256*256 times gets expensive
110 int w = Width;
111 int h = Height;
112 float[] heights = new float[w * h];
113 134
114 int i, j; // map coordinates
115 int idx = 0; // index into serialized array 135 int idx = 0; // index into serialized array
116 for (i = 0; i < h; i++) 136 for (int ii = 0; ii < Width; ii++)
117 { 137 {
118 for (j = 0; j < w; j++) 138 for (int jj = 0; jj < Height; jj++)
119 { 139 {
120 heights[idx++] = (float)map[j, i]; 140 heights[ii, jj] = (double)m_terrainData[ii, jj];
141 idx++;
121 } 142 }
122 } 143 }
123 144
124 return heights; 145 return heights;
125 } 146 }
126 147
127 public double[,] GetDoubles() 148 // ITerrainChannel.this[x,y]
128 {
129 return map;
130 }
131
132 public double this[int x, int y] 149 public double this[int x, int y]
133 { 150 {
134 get { return map[x, y]; } 151 get {
152 if (x < 0 || x >= Width || y < 0 || y >= Height)
153 return 0;
154 return (double)m_terrainData[x, y];
155 }
135 set 156 set
136 { 157 {
137 // Will "fix" terrain hole problems. Although not fantastically.
138 if (Double.IsNaN(value) || Double.IsInfinity(value)) 158 if (Double.IsNaN(value) || Double.IsInfinity(value))
139 return; 159 return;
140 160
141 if (map[x, y] != value) 161 m_terrainData[x, y] = (float)value;
142 {
143 taint[x / 16, y / 16] = true;
144 map[x, y] = value;
145 }
146 } 162 }
147 } 163 }
148 164
149 public bool Tainted(int x, int y) 165 // ITerrainChannel.GetHieghtAtXYZ(x, y, z)
166 public float GetHeightAtXYZ(float x, float y, float z)
150 { 167 {
151 if (taint[x / 16, y / 16]) 168 if (x < 0 || x >= Width || y < 0 || y >= Height)
152 { 169 return 0;
153 taint[x / 16, y / 16] = false; 170 return m_terrainData[(int)x, (int)y];
154 return true;
155 }
156 return false;
157 } 171 }
158 172
159 #endregion 173 // ITerrainChannel.Tainted()
160 174 public bool Tainted(int x, int y)
161 public TerrainChannel Copy()
162 { 175 {
163 TerrainChannel copy = new TerrainChannel(false); 176 return m_terrainData.IsTaintedAt(x, y);
164 copy.map = (double[,]) map.Clone();
165
166 return copy;
167 } 177 }
168 178
179 // ITerrainChannel.SaveToXmlString()
169 public string SaveToXmlString() 180 public string SaveToXmlString()
170 { 181 {
171 XmlWriterSettings settings = new XmlWriterSettings(); 182 XmlWriterSettings settings = new XmlWriterSettings();
@@ -181,13 +192,7 @@ namespace OpenSim.Region.Framework.Scenes
181 } 192 }
182 } 193 }
183 194
184 private void WriteXml(XmlWriter writer) 195 // ITerrainChannel.LoadFromXmlString()
185 {
186 writer.WriteStartElement(String.Empty, "TerrainMap", String.Empty);
187 ToXml(writer);
188 writer.WriteEndElement();
189 }
190
191 public void LoadFromXmlString(string data) 196 public void LoadFromXmlString(string data)
192 { 197 {
193 StringReader sr = new StringReader(data); 198 StringReader sr = new StringReader(data);
@@ -199,12 +204,124 @@ namespace OpenSim.Region.Framework.Scenes
199 sr.Close(); 204 sr.Close();
200 } 205 }
201 206
207 // ITerrainChannel.Merge
208 public void Merge(ITerrainChannel newTerrain, Vector3 displacement, float radianRotation, Vector2 rotationDisplacement)
209 {
210 m_log.DebugFormat("{0} Merge. inSize=<{1},{2}>, disp={3}, rot={4}, rotDisp={5}, outSize=<{6},{7}>", LogHeader,
211 newTerrain.Width, newTerrain.Height,
212 displacement, radianRotation, rotationDisplacement,
213 m_terrainData.SizeX, m_terrainData.SizeY);
214 for (int xx = 0; xx < newTerrain.Width; xx++)
215 {
216 for (int yy = 0; yy < newTerrain.Height; yy++)
217 {
218 int dispX = (int)displacement.X;
219 int dispY = (int)displacement.Y;
220 float newHeight = (float)newTerrain[xx, yy] + displacement.Z;
221 if (radianRotation == 0)
222 {
223 // If no rotation, place the new height in the specified location
224 dispX += xx;
225 dispY += yy;
226 if (dispX >= 0 && dispX < m_terrainData.SizeX && dispY >= 0 && dispY < m_terrainData.SizeY)
227 {
228 m_terrainData[dispX, dispY] = newHeight;
229 }
230 }
231 else
232 {
233 // If rotating, we have to smooth the result because the conversion
234 // to ints will mean heightmap entries will not get changed
235 // First compute the rotation location for the new height.
236 dispX += (int)(rotationDisplacement.X
237 + ((float)xx - rotationDisplacement.X) * Math.Cos(radianRotation)
238 - ((float)yy - rotationDisplacement.Y) * Math.Sin(radianRotation) );
239
240 dispY += (int)(rotationDisplacement.Y
241 + ((float)xx - rotationDisplacement.X) * Math.Sin(radianRotation)
242 + ((float)yy - rotationDisplacement.Y) * Math.Cos(radianRotation) );
243
244 if (dispX >= 0 && dispX < m_terrainData.SizeX && dispY >= 0 && dispY < m_terrainData.SizeY)
245 {
246 float oldHeight = m_terrainData[dispX, dispY];
247 // Smooth the heights around this location if the old height is far from this one
248 for (int sxx = dispX - 2; sxx < dispX + 2; sxx++)
249 {
250 for (int syy = dispY - 2; syy < dispY + 2; syy++)
251 {
252 if (sxx >= 0 && sxx < m_terrainData.SizeX && syy >= 0 && syy < m_terrainData.SizeY)
253 {
254 if (sxx == dispX && syy == dispY)
255 {
256 // Set height for the exact rotated point
257 m_terrainData[dispX, dispY] = newHeight;
258 }
259 else
260 {
261 if (Math.Abs(m_terrainData[sxx, syy] - newHeight) > 1f)
262 {
263 // If the adjacent height is far off, force it to this height
264 m_terrainData[sxx, syy] = newHeight;
265 }
266 }
267 }
268 }
269 }
270 }
271
272 if (dispX >= 0 && dispX < m_terrainData.SizeX && dispY >= 0 && dispY < m_terrainData.SizeY)
273 {
274 m_terrainData[dispX, dispY] = (float)newTerrain[xx, yy];
275 }
276 }
277 }
278 }
279 }
280
281 #endregion
282
283 public TerrainChannel Copy()
284 {
285 TerrainChannel copy = new TerrainChannel();
286 copy.m_terrainData = m_terrainData.Clone();
287 return copy;
288 }
289
290 private void WriteXml(XmlWriter writer)
291 {
292 if (Width == Constants.RegionSize && Height == Constants.RegionSize)
293 {
294 // Downward compatibility for legacy region terrain maps.
295 // If region is exactly legacy size, return the old format XML.
296 writer.WriteStartElement(String.Empty, "TerrainMap", String.Empty);
297 ToXml(writer);
298 writer.WriteEndElement();
299 }
300 else
301 {
302 // New format XML that includes width and length.
303 writer.WriteStartElement(String.Empty, "TerrainMap2", String.Empty);
304 ToXml2(writer);
305 writer.WriteEndElement();
306 }
307 }
308
202 private void ReadXml(XmlReader reader) 309 private void ReadXml(XmlReader reader)
203 { 310 {
204 reader.ReadStartElement("TerrainMap"); 311 // Check the first element. If legacy element, use the legacy reader.
205 FromXml(reader); 312 if (reader.IsStartElement("TerrainMap"))
313 {
314 reader.ReadStartElement("TerrainMap");
315 FromXml(reader);
316 }
317 else
318 {
319 reader.ReadStartElement("TerrainMap2");
320 FromXml2(reader);
321 }
206 } 322 }
207 323
324 // Write legacy terrain map. Presumed to be 256x256 of data encoded as floats in a byte array.
208 private void ToXml(XmlWriter xmlWriter) 325 private void ToXml(XmlWriter xmlWriter)
209 { 326 {
210 float[] mapData = GetFloatsSerialised(); 327 float[] mapData = GetFloatsSerialised();
@@ -218,12 +335,15 @@ namespace OpenSim.Region.Framework.Scenes
218 serializer.Serialize(xmlWriter, buffer); 335 serializer.Serialize(xmlWriter, buffer);
219 } 336 }
220 337
338 // Read legacy terrain map. Presumed to be 256x256 of data encoded as floats in a byte array.
221 private void FromXml(XmlReader xmlReader) 339 private void FromXml(XmlReader xmlReader)
222 { 340 {
223 XmlSerializer serializer = new XmlSerializer(typeof(byte[])); 341 XmlSerializer serializer = new XmlSerializer(typeof(byte[]));
224 byte[] dataArray = (byte[])serializer.Deserialize(xmlReader); 342 byte[] dataArray = (byte[])serializer.Deserialize(xmlReader);
225 int index = 0; 343 int index = 0;
226 344
345 m_terrainData = new HeightmapTerrainData(Height, Width, (int)Constants.RegionHeight);
346
227 for (int y = 0; y < Height; y++) 347 for (int y = 0; y < Height; y++)
228 { 348 {
229 for (int x = 0; x < Width; x++) 349 for (int x = 0; x < Width; x++)
@@ -236,35 +356,63 @@ namespace OpenSim.Region.Framework.Scenes
236 } 356 }
237 } 357 }
238 358
359 private class TerrainChannelXMLPackage
360 {
361 public int Version;
362 public int SizeX;
363 public int SizeY;
364 public int SizeZ;
365 public float CompressionFactor;
366 public int[] Map;
367 public TerrainChannelXMLPackage(int pX, int pY, int pZ, float pCompressionFactor, int[] pMap)
368 {
369 Version = 1;
370 SizeX = pX;
371 SizeY = pY;
372 SizeZ = pZ;
373 CompressionFactor = pCompressionFactor;
374 Map = pMap;
375 }
376 }
377
378 // New terrain serialization format that includes the width and length.
379 private void ToXml2(XmlWriter xmlWriter)
380 {
381 TerrainChannelXMLPackage package = new TerrainChannelXMLPackage(Width, Height, Altitude, m_terrainData.CompressionFactor,
382 m_terrainData.GetCompressedMap());
383 XmlSerializer serializer = new XmlSerializer(typeof(TerrainChannelXMLPackage));
384 serializer.Serialize(xmlWriter, package);
385 }
386
387 // New terrain serialization format that includes the width and length.
388 private void FromXml2(XmlReader xmlReader)
389 {
390 XmlSerializer serializer = new XmlSerializer(typeof(TerrainChannelXMLPackage));
391 TerrainChannelXMLPackage package = (TerrainChannelXMLPackage)serializer.Deserialize(xmlReader);
392 m_terrainData = new HeightmapTerrainData(package.Map, package.CompressionFactor, package.SizeX, package.SizeY, package.SizeZ);
393 }
394
395 // Fill the heightmap with the center bump terrain
239 private void PinHeadIsland() 396 private void PinHeadIsland()
240 { 397 {
241 int x; 398 for (int x = 0; x < Width; x++)
242 for (x = 0; x < Constants.RegionSize; x++)
243 { 399 {
244 int y; 400 for (int y = 0; y < Height; y++)
245 for (y = 0; y < Constants.RegionSize; y++)
246 { 401 {
247 map[x, y] = TerrainUtil.PerlinNoise2D(x, y, 2, 0.125) * 10; 402 m_terrainData[x, y] = (float)TerrainUtil.PerlinNoise2D(x, y, 2, 0.125) * 10;
248 double spherFacA = TerrainUtil.SphericalFactor(x, y, Constants.RegionSize / 2.0, Constants.RegionSize / 2.0, 50) * 0.01; 403 float spherFacA = (float)(TerrainUtil.SphericalFactor(x, y, m_terrainData.SizeX / 2.0, m_terrainData.SizeY / 2.0, 50) * 0.01d);
249 double spherFacB = TerrainUtil.SphericalFactor(x, y, Constants.RegionSize / 2.0, Constants.RegionSize / 2.0, 100) * 0.001; 404 float spherFacB = (float)(TerrainUtil.SphericalFactor(x, y, m_terrainData.SizeX / 2.0, m_terrainData.SizeY / 2.0, 100) * 0.001d);
250 if (map[x, y] < spherFacA) 405 if (m_terrainData[x, y]< spherFacA)
251 map[x, y] = spherFacA; 406 m_terrainData[x, y]= spherFacA;
252 if (map[x, y] < spherFacB) 407 if (m_terrainData[x, y]< spherFacB)
253 map[x, y] = spherFacB; 408 m_terrainData[x, y] = spherFacB;
254 } 409 }
255 } 410 }
256 } 411 }
257 412
258 private void FlatLand() 413 private void FlatLand()
259 { 414 {
260 int x; 415 m_terrainData.ClearLand();
261 for (x = 0; x < Constants.RegionSize; x++)
262 {
263 int y;
264 for (y = 0; y < Constants.RegionSize; y++)
265 map[x, y] = 21;
266 }
267 } 416 }
268
269 } 417 }
270} 418}
diff --git a/OpenSim/Region/Framework/Scenes/TerrainCompressor.cs b/OpenSim/Region/Framework/Scenes/TerrainCompressor.cs
new file mode 100644
index 0000000..fc8f8cd
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/TerrainCompressor.cs
@@ -0,0 +1,948 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28/* Freely adapted from the Aurora version of the terrain compressor.
29 * Copyright (c) Contributors, http://aurora-sim.org/, http://opensimulator.org/
30 */
31
32using System;
33using System.Reflection;
34
35using log4net;
36
37using OpenSim.Framework;
38using OpenSim.Region.Framework;
39using OpenSim.Region.Framework.Scenes;
40
41using OpenMetaverse;
42using OpenMetaverse.Packets;
43
44namespace OpenSim.Region.ClientStack.LindenUDP
45{
46 public static class OpenSimTerrainCompressor
47 {
48// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
49
50#pragma warning disable 414
51 private static string LogHeader = "[TERRAIN COMPRESSOR]";
52#pragma warning restore 414
53
54 public const int END_OF_PATCHES = 97;
55
56 private const float OO_SQRT2 = 0.7071067811865475244008443621049f;
57 private const int STRIDE = 264;
58
59 private const int ZERO_CODE = 0x0;
60 private const int ZERO_EOB = 0x2;
61 private const int POSITIVE_VALUE = 0x6;
62 private const int NEGATIVE_VALUE = 0x7;
63
64 private static readonly float[] DequantizeTable16 =
65 new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
66
67 private static readonly float[] DequantizeTable32 =
68 new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
69
70 private static readonly float[] CosineTable16 = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
71 //private static readonly float[] CosineTable32 = new float[Constants.TerrainPatchSize * Constants.TerrainPatchSize];
72 private static readonly int[] CopyMatrix16 = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
73 private static readonly int[] CopyMatrix32 = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
74
75 private static readonly float[] QuantizeTable16 =
76 new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
77
78 static OpenSimTerrainCompressor()
79 {
80 // Initialize the decompression tables
81 BuildDequantizeTable16();
82 SetupCosines16();
83 BuildCopyMatrix16();
84 BuildQuantizeTable16();
85 }
86
87 // Used to send cloud and wind patches
88 public static LayerDataPacket CreateLayerDataPacket(TerrainPatch[] patches, byte type, int pRegionSizeX,
89 int pRegionSizeY)
90 {
91 LayerDataPacket layer = new LayerDataPacket {LayerID = {Type = type}};
92
93 TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader
94 {Stride = STRIDE, PatchSize = Constants.TerrainPatchSize};
95
96 // Should be enough to fit even the most poorly packed data
97 byte[] data = new byte[patches.Length*Constants.TerrainPatchSize*Constants.TerrainPatchSize*2];
98 BitPack bitpack = new BitPack(data, 0);
99 bitpack.PackBits(header.Stride, 16);
100 bitpack.PackBits(header.PatchSize, 8);
101 bitpack.PackBits(type, 8);
102
103 foreach (TerrainPatch t in patches)
104 CreatePatch(bitpack, t.Data, t.X, t.Y, pRegionSizeX, pRegionSizeY);
105
106 bitpack.PackBits(END_OF_PATCHES, 8);
107
108 layer.LayerData.Data = new byte[bitpack.BytePos + 1];
109 Buffer.BlockCopy(bitpack.Data, 0, layer.LayerData.Data, 0, bitpack.BytePos + 1);
110
111 return layer;
112 }
113
114 // Create a land packet for a single patch.
115 public static LayerDataPacket CreateLandPacket(TerrainData terrData, int patchX, int patchY)
116 {
117 int[] xPieces = new int[1];
118 int[] yPieces = new int[1];
119 xPieces[0] = patchX; // patch X dimension
120 yPieces[0] = patchY;
121
122 return CreateLandPacket(terrData, xPieces, yPieces);
123 }
124
125 public static LayerDataPacket CreateLandPacket(TerrainData terrData, int[] xPieces, int[] yPieces)
126 {
127 byte landPacketType = (byte)TerrainPatch.LayerType.Land;
128 if (terrData.SizeX > Constants.RegionSize || terrData.SizeY > Constants.RegionSize)
129 {
130 landPacketType = (byte)TerrainPatch.LayerType.LandExtended;
131 }
132
133 return CreateLandPacket(terrData, xPieces, yPieces, landPacketType);
134 }
135
136 /// <summary>
137 /// Creates a LayerData packet for compressed land data given a full
138 /// simulator heightmap and an array of indices of patches to compress
139 /// </summary>
140 /// <param name="terrData">
141 /// Terrain data that can result in a meter square heightmap.
142 /// </param>
143 /// <param name="x">
144 /// Array of indexes in the grid of patches
145 /// for this simulator.
146 /// If creating a packet for multiple patches, there will be entries in
147 /// both the X and Y arrays for each of the patches.
148 /// For example if patches 1 and 17 are to be sent,
149 /// x[] = {1,1} and y[] = {0,1} which specifies the patches at
150 /// indexes <1,0> and <1,1> (presuming the terrain size is 16x16 patches).
151 /// </param>
152 /// <param name="y">
153 /// Array of indexes in the grid of patches.
154 /// </param>
155 /// <param name="type"></param>
156 /// <returns></returns>
157 public static LayerDataPacket CreateLandPacket(TerrainData terrData, int[] x, int[] y, byte type)
158 {
159 LayerDataPacket layer = new LayerDataPacket {LayerID = {Type = type}};
160
161 TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader
162 {Stride = STRIDE, PatchSize = Constants.TerrainPatchSize};
163
164 byte[] data = new byte[x.Length * Constants.TerrainPatchSize * Constants.TerrainPatchSize * 2];
165 BitPack bitpack = new BitPack(data, 0);
166 bitpack.PackBits(header.Stride, 16);
167 bitpack.PackBits(header.PatchSize, 8);
168 bitpack.PackBits(type, 8);
169
170 for (int i = 0; i < x.Length; i++)
171 CreatePatchFromHeightmap(bitpack, terrData, x[i], y[i]);
172
173 bitpack.PackBits(END_OF_PATCHES, 8);
174
175 layer.LayerData.Data = new byte[bitpack.BytePos + 1];
176 Buffer.BlockCopy(bitpack.Data, 0, layer.LayerData.Data, 0, bitpack.BytePos + 1);
177
178 return layer;
179 }
180
181 // Unused: left for historical reference.
182 public static void CreatePatch(BitPack output, float[] patchData, int x, int y, int pRegionSizeX, int pRegionSizeY)
183 {
184 TerrainPatch.Header header = PrescanPatch(patchData);
185 header.QuantWBits = 136;
186 if (pRegionSizeX > Constants.RegionSize || pRegionSizeY > Constants.RegionSize)
187 {
188 header.PatchIDs = (y & 0xFFFF);
189 header.PatchIDs += (x << 16);
190 }
191 else
192 {
193 header.PatchIDs = (y & 0x1F);
194 header.PatchIDs += (x << 5);
195 }
196
197 // NOTE: No idea what prequant and postquant should be or what they do
198
199 int wbits;
200 int[] patch = CompressPatch(patchData, header, 10, out wbits);
201 wbits = EncodePatchHeader(output, header, patch, Constants.RegionSize, Constants.RegionSize, wbits);
202 EncodePatch(output, patch, 0, wbits);
203 }
204
205 /// <summary>
206 /// Add a patch of terrain to a BitPacker
207 /// </summary>
208 /// <param name="output">BitPacker to write the patch to</param>
209 /// <param name="heightmap">
210 /// Heightmap of the simulator. Presumed to be an sizeX*sizeY array.
211 /// </param>
212 /// <param name="patchX">
213 /// X offset of the patch to create.
214 /// </param>
215 /// <param name="patchY">
216 /// Y offset of the patch to create.
217 /// </param>
218 /// <param name="pRegionSizeX"></param>
219 /// <param name="pRegionSizeY"></param>
220 public static void CreatePatchFromHeightmap(BitPack output, TerrainData terrData, int patchX, int patchY)
221 {
222 TerrainPatch.Header header = PrescanPatch(terrData, patchX, patchY);
223 header.QuantWBits = 136;
224
225 // If larger than legacy region size, pack patch X and Y info differently.
226 if (terrData.SizeX > Constants.RegionSize || terrData.SizeY > Constants.RegionSize)
227 {
228 header.PatchIDs = (patchY & 0xFFFF);
229 header.PatchIDs += (patchX << 16);
230 }
231 else
232 {
233 header.PatchIDs = (patchY & 0x1F);
234 header.PatchIDs += (patchX << 5);
235 }
236
237 // m_log.DebugFormat("{0} CreatePatchFromHeightmap. patchX={1}, patchY={2}, DCOffset={3}, range={4}",
238 // LogHeader, patchX, patchY, header.DCOffset, header.Range);
239
240 // NOTE: No idea what prequant and postquant should be or what they do
241 int wbits;
242 int[] patch = CompressPatch(terrData, patchX, patchY, header, 10, out wbits);
243 wbits = EncodePatchHeader(output, header, patch, (uint)terrData.SizeX, (uint)terrData.SizeY, wbits);
244 EncodePatch(output, patch, 0, wbits);
245 }
246
247 private static TerrainPatch.Header PrescanPatch(float[] patch)
248 {
249 TerrainPatch.Header header = new TerrainPatch.Header();
250 float zmax = -99999999.0f;
251 float zmin = 99999999.0f;
252
253 for (int i = 0; i < Constants.TerrainPatchSize*Constants.TerrainPatchSize; i++)
254 {
255 float val = patch[i];
256 if (val > zmax) zmax = val;
257 if (val < zmin) zmin = val;
258 }
259
260 header.DCOffset = zmin;
261 header.Range = (int) ((zmax - zmin) + 1.0f);
262
263 return header;
264 }
265
266 // Scan the height info we're returning and return a patch packet header for this patch.
267 private static TerrainPatch.Header PrescanPatch(TerrainData terrData, int patchX, int patchY)
268 {
269 TerrainPatch.Header header = new TerrainPatch.Header();
270 float zmax = -99999999.0f;
271 float zmin = 99999999.0f;
272
273 for (int j = patchY*Constants.TerrainPatchSize; j < (patchY + 1)*Constants.TerrainPatchSize; j++)
274 {
275 for (int i = patchX*Constants.TerrainPatchSize; i < (patchX + 1)*Constants.TerrainPatchSize; i++)
276 {
277 float val = terrData[i, j];
278 if (val > zmax) zmax = val;
279 if (val < zmin) zmin = val;
280 }
281 }
282
283 header.DCOffset = zmin;
284 header.Range = (int)((zmax - zmin) + 1.0f);
285
286 return header;
287 }
288
289 public static TerrainPatch.Header DecodePatchHeader(BitPack bitpack)
290 {
291 TerrainPatch.Header header = new TerrainPatch.Header {QuantWBits = bitpack.UnpackBits(8)};
292
293 // Quantized word bits
294 if (header.QuantWBits == END_OF_PATCHES)
295 return header;
296
297 // DC offset
298 header.DCOffset = bitpack.UnpackFloat();
299
300 // Range
301 header.Range = bitpack.UnpackBits(16);
302
303 // Patch IDs (10 bits)
304 header.PatchIDs = bitpack.UnpackBits(10);
305
306 // Word bits
307 header.WordBits = (uint) ((header.QuantWBits & 0x0f) + 2);
308
309 return header;
310 }
311
312 private static int EncodePatchHeader(BitPack output, TerrainPatch.Header header, int[] patch, uint pRegionSizeX,
313 uint pRegionSizeY, int wbits)
314 {
315 /*
316 int temp;
317 int wbits = (header.QuantWBits & 0x0f) + 2;
318 uint maxWbits = (uint)wbits + 5;
319 uint minWbits = ((uint)wbits >> 1);
320 int wbitsMaxValue;
321 */
322 // goal is to determ minimum number of bits to use so all data fits
323 /*
324 wbits = (int)minWbits;
325 wbitsMaxValue = (1 << wbits);
326
327 for (int i = 0; i < patch.Length; i++)
328 {
329 temp = patch[i];
330 if (temp != 0)
331 {
332 // Get the absolute value
333 if (temp < 0) temp *= -1;
334
335 no coments..
336
337 for (int j = (int)maxWbits; j > (int)minWbits; j--)
338 {
339 if ((temp & (1 << j)) != 0)
340 {
341 if (j > wbits) wbits = j;
342 break;
343 }
344 }
345
346 while (temp > wbitsMaxValue)
347 {
348 wbits++;
349 if (wbits == maxWbits)
350 goto Done;
351 wbitsMaxValue = 1 << wbits;
352 }
353 }
354 }
355
356 Done:
357
358 // wbits += 1;
359 */
360 // better check
361 if (wbits > 17)
362 wbits = 16;
363 else if (wbits < 3)
364 wbits = 3;
365
366 header.QuantWBits &= 0xf0;
367
368 header.QuantWBits |= (wbits - 2);
369
370 output.PackBits(header.QuantWBits, 8);
371 output.PackFloat(header.DCOffset);
372 output.PackBits(header.Range, 16);
373 if (pRegionSizeX > Constants.RegionSize || pRegionSizeY > Constants.RegionSize)
374 output.PackBits(header.PatchIDs, 32);
375 else
376 output.PackBits(header.PatchIDs, 10);
377
378 return wbits;
379 }
380
381 private static void IDCTColumn16(float[] linein, float[] lineout, int column)
382 {
383 for (int n = 0; n < Constants.TerrainPatchSize; n++)
384 {
385 float total = OO_SQRT2*linein[column];
386
387 for (int u = 1; u < Constants.TerrainPatchSize; u++)
388 {
389 int usize = u*Constants.TerrainPatchSize;
390 total += linein[usize + column]*CosineTable16[usize + n];
391 }
392
393 lineout[Constants.TerrainPatchSize*n + column] = total;
394 }
395 }
396
397 private static void IDCTLine16(float[] linein, float[] lineout, int line)
398 {
399 const float oosob = 2.0f/Constants.TerrainPatchSize;
400 int lineSize = line*Constants.TerrainPatchSize;
401
402 for (int n = 0; n < Constants.TerrainPatchSize; n++)
403 {
404 float total = OO_SQRT2*linein[lineSize];
405
406 for (int u = 1; u < Constants.TerrainPatchSize; u++)
407 {
408 total += linein[lineSize + u]*CosineTable16[u*Constants.TerrainPatchSize + n];
409 }
410
411 lineout[lineSize + n] = total*oosob;
412 }
413 }
414
415/*
416 private static void DCTLine16(float[] linein, float[] lineout, int line)
417 {
418 float total = 0.0f;
419 int lineSize = line * Constants.TerrainPatchSize;
420
421 for (int n = 0; n < Constants.TerrainPatchSize; n++)
422 {
423 total += linein[lineSize + n];
424 }
425
426 lineout[lineSize] = OO_SQRT2 * total;
427
428 int uptr = 0;
429 for (int u = 1; u < Constants.TerrainPatchSize; u++)
430 {
431 total = 0.0f;
432 uptr += Constants.TerrainPatchSize;
433
434 for (int n = 0; n < Constants.TerrainPatchSize; n++)
435 {
436 total += linein[lineSize + n] * CosineTable16[uptr + n];
437 }
438
439 lineout[lineSize + u] = total;
440 }
441 }
442*/
443
444 private static void DCTLine16(float[] linein, float[] lineout, int line)
445 {
446 // outputs transpose data (lines exchanged with coluns )
447 // so to save a bit of cpu when doing coluns
448 float total = 0.0f;
449 int lineSize = line*Constants.TerrainPatchSize;
450
451 for (int n = 0; n < Constants.TerrainPatchSize; n++)
452 {
453 total += linein[lineSize + n];
454 }
455
456 lineout[line] = OO_SQRT2*total;
457
458 for (int u = Constants.TerrainPatchSize;
459 u < Constants.TerrainPatchSize*Constants.TerrainPatchSize;
460 u += Constants.TerrainPatchSize)
461 {
462 total = 0.0f;
463 for (int ptrn = lineSize, ptru = u; ptrn < lineSize + Constants.TerrainPatchSize; ptrn++,ptru++)
464 {
465 total += linein[ptrn]*CosineTable16[ptru];
466 }
467
468 lineout[line + u] = total;
469 }
470 }
471
472
473 /*
474 private static void DCTColumn16(float[] linein, int[] lineout, int column)
475 {
476 float total = 0.0f;
477 // const float oosob = 2.0f / Constants.TerrainPatchSize;
478
479 for (int n = 0; n < Constants.TerrainPatchSize; n++)
480 {
481 total += linein[Constants.TerrainPatchSize * n + column];
482 }
483
484 // lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * oosob * QuantizeTable16[column]);
485 lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * QuantizeTable16[column]);
486
487 for (int uptr = Constants.TerrainPatchSize; uptr < Constants.TerrainPatchSize * Constants.TerrainPatchSize; uptr += Constants.TerrainPatchSize)
488 {
489 total = 0.0f;
490
491 for (int n = 0; n < Constants.TerrainPatchSize; n++)
492 {
493 total += linein[Constants.TerrainPatchSize * n + column] * CosineTable16[uptr + n];
494 }
495
496 // lineout[CopyMatrix16[Constants.TerrainPatchSize * u + column]] = (int)(total * oosob * QuantizeTable16[Constants.TerrainPatchSize * u + column]);
497 lineout[CopyMatrix16[uptr + column]] = (int)(total * QuantizeTable16[uptr + column]);
498 }
499 }
500
501 private static void DCTColumn16(float[] linein, int[] lineout, int column)
502 {
503 // input columns are in fact stored in lines now
504
505 float total = 0.0f;
506// const float oosob = 2.0f / Constants.TerrainPatchSize;
507 int inlinesptr = Constants.TerrainPatchSize*column;
508
509 for (int n = 0; n < Constants.TerrainPatchSize; n++)
510 {
511 total += linein[inlinesptr + n];
512 }
513
514 // lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * oosob * QuantizeTable16[column]);
515 lineout[CopyMatrix16[column]] = (int) (OO_SQRT2*total*QuantizeTable16[column]);
516
517 for (int uptr = Constants.TerrainPatchSize;
518 uptr < Constants.TerrainPatchSize*Constants.TerrainPatchSize;
519 uptr += Constants.TerrainPatchSize)
520 {
521 total = 0.0f;
522
523 for (int n = inlinesptr, ptru = uptr; n < inlinesptr + Constants.TerrainPatchSize; n++, ptru++)
524 {
525 total += linein[n]*CosineTable16[ptru];
526 }
527
528// lineout[CopyMatrix16[Constants.TerrainPatchSize * u + column]] = (int)(total * oosob * QuantizeTable16[Constants.TerrainPatchSize * u + column]);
529 lineout[CopyMatrix16[uptr + column]] = (int) (total*QuantizeTable16[uptr + column]);
530 }
531 }
532 */
533
534 private static int DCTColumn16Wbits(float[] linein, int[] lineout, int column, int wbits, int maxwbits)
535 {
536 // input columns are in fact stored in lines now
537
538 bool dowbits = wbits != maxwbits;
539 int wbitsMaxValue = 1 << wbits;
540
541 float total = 0.0f;
542 // const float oosob = 2.0f / Constants.TerrainPatchSize;
543 int inlinesptr = Constants.TerrainPatchSize*column;
544
545 for (int n = 0; n < Constants.TerrainPatchSize; n++)
546 {
547 total += linein[inlinesptr + n];
548 }
549
550 // lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * oosob * QuantizeTable16[column]);
551 int tmp = (int) (OO_SQRT2*total*QuantizeTable16[column]);
552 lineout[CopyMatrix16[column]] = tmp;
553
554 if (dowbits)
555 {
556 if (tmp < 0) tmp *= -1;
557 while (tmp > wbitsMaxValue)
558 {
559 wbits++;
560 wbitsMaxValue = 1 << wbits;
561 if (wbits == maxwbits)
562 {
563 dowbits = false;
564 break;
565 }
566 }
567 }
568
569 for (int uptr = Constants.TerrainPatchSize;
570 uptr < Constants.TerrainPatchSize*Constants.TerrainPatchSize;
571 uptr += Constants.TerrainPatchSize)
572 {
573 total = 0.0f;
574
575 for (int n = inlinesptr, ptru = uptr; n < inlinesptr + Constants.TerrainPatchSize; n++, ptru++)
576 {
577 total += linein[n]*CosineTable16[ptru];
578 }
579
580 tmp = (int) (total*QuantizeTable16[uptr + column]);
581 lineout[CopyMatrix16[uptr + column]] = tmp;
582
583 if (dowbits)
584 {
585 if (tmp < 0) tmp *= -1;
586 while (tmp > wbitsMaxValue)
587 {
588 wbits++;
589 wbitsMaxValue = 1 << wbits;
590 if (wbits == maxwbits)
591 {
592 dowbits = false;
593 break;
594 }
595 }
596 }
597 }
598 return wbits;
599 }
600
601 public static void DecodePatch(int[] patches, BitPack bitpack, TerrainPatch.Header header, int size)
602 {
603 for (int n = 0; n < size*size; n++)
604 {
605 // ?
606 int temp = bitpack.UnpackBits(1);
607 if (temp != 0)
608 {
609 // Value or EOB
610 temp = bitpack.UnpackBits(1);
611 if (temp != 0)
612 {
613 // Value
614 temp = bitpack.UnpackBits(1);
615 if (temp != 0)
616 {
617 // Negative
618 temp = bitpack.UnpackBits((int) header.WordBits);
619 patches[n] = temp*-1;
620 }
621 else
622 {
623 // Positive
624 temp = bitpack.UnpackBits((int) header.WordBits);
625 patches[n] = temp;
626 }
627 }
628 else
629 {
630 // Set the rest to zero
631 // TODO: This might not be necessary
632 for (int o = n; o < size*size; o++)
633 {
634 patches[o] = 0;
635 }
636 break;
637 }
638 }
639 else
640 {
641 patches[n] = 0;
642 }
643 }
644 }
645
646 private static void EncodePatch(BitPack output, int[] patch, int postquant, int wbits)
647 {
648 int maxwbitssize = (1 << wbits) - 1;
649
650 if (postquant > Constants.TerrainPatchSize*Constants.TerrainPatchSize || postquant < 0)
651 {
652 Logger.Log("Postquant is outside the range of allowed values in EncodePatch()", Helpers.LogLevel.Error);
653 return;
654 }
655
656 if (postquant != 0) patch[Constants.TerrainPatchSize*Constants.TerrainPatchSize - postquant] = 0;
657
658 for (int i = 0; i < Constants.TerrainPatchSize*Constants.TerrainPatchSize; i++)
659 {
660 int temp = patch[i];
661
662 if (temp == 0)
663 {
664 bool eob = true;
665
666 for (int j = i; j < Constants.TerrainPatchSize*Constants.TerrainPatchSize - postquant; j++)
667 {
668 if (patch[j] != 0)
669 {
670 eob = false;
671 break;
672 }
673 }
674
675 if (eob)
676 {
677 output.PackBits(ZERO_EOB, 2);
678 return;
679 }
680 output.PackBits(ZERO_CODE, 1);
681 }
682 else
683 {
684 if (temp < 0)
685 {
686 temp *= -1;
687
688 if (temp > maxwbitssize) temp = maxwbitssize;
689
690 output.PackBits(NEGATIVE_VALUE, 3);
691 output.PackBits(temp, wbits);
692 }
693 else
694 {
695 if (temp > maxwbitssize) temp = maxwbitssize;
696
697 output.PackBits(POSITIVE_VALUE, 3);
698 output.PackBits(temp, wbits);
699 }
700 }
701 }
702 }
703
704 public static float[] DecompressPatch(int[] patches, TerrainPatch.Header header, TerrainPatch.GroupHeader group)
705 {
706 float[] block = new float[group.PatchSize*group.PatchSize];
707 float[] output = new float[group.PatchSize*group.PatchSize];
708 int prequant = (header.QuantWBits >> 4) + 2;
709 int quantize = 1 << prequant;
710 float ooq = 1.0f/quantize;
711 float mult = ooq*header.Range;
712 float addval = mult*(1 << (prequant - 1)) + header.DCOffset;
713
714 if (group.PatchSize == Constants.TerrainPatchSize)
715 {
716 for (int n = 0; n < Constants.TerrainPatchSize*Constants.TerrainPatchSize; n++)
717 {
718 block[n] = patches[CopyMatrix16[n]]*DequantizeTable16[n];
719 }
720
721 float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
722
723 for (int o = 0; o < Constants.TerrainPatchSize; o++)
724 IDCTColumn16(block, ftemp, o);
725 for (int o = 0; o < Constants.TerrainPatchSize; o++)
726 IDCTLine16(ftemp, block, o);
727 }
728 else
729 {
730 for (int n = 0; n < Constants.TerrainPatchSize*2*Constants.TerrainPatchSize*2; n++)
731 {
732 block[n] = patches[CopyMatrix32[n]]*DequantizeTable32[n];
733 }
734
735 Logger.Log("Implement IDCTPatchLarge", Helpers.LogLevel.Error);
736 }
737
738 for (int j = 0; j < block.Length; j++)
739 {
740 output[j] = block[j]*mult + addval;
741 }
742
743 return output;
744 }
745
746 private static int[] CompressPatch(float[] patchData, TerrainPatch.Header header, int prequant, out int wbits)
747 {
748 float[] block = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
749 int wordsize = (prequant - 2) & 0x0f;
750 float oozrange = 1.0f/header.Range;
751 float range = (1 << prequant);
752 float premult = oozrange*range;
753 float sub = (1 << (prequant - 1)) + header.DCOffset*premult;
754
755 header.QuantWBits = wordsize;
756 header.QuantWBits |= wordsize << 4;
757
758 int k = 0;
759 for (int j = 0; j < Constants.TerrainPatchSize; j++)
760 {
761 for (int i = 0; i < Constants.TerrainPatchSize; i++)
762 block[k++] = patchData[j*Constants.TerrainPatchSize + i]*premult - sub;
763 }
764
765 float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
766 int[] itemp = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
767
768
769 int maxWbits = prequant + 5;
770 wbits = (prequant >> 1);
771
772 for (int o = 0; o < Constants.TerrainPatchSize; o++)
773 DCTLine16(block, ftemp, o);
774 for (int o = 0; o < Constants.TerrainPatchSize; o++)
775 wbits = DCTColumn16Wbits(ftemp, itemp, o, wbits, maxWbits);
776
777 return itemp;
778 }
779
780 private static int[] CompressPatch(float[,] patchData, TerrainPatch.Header header, int prequant, out int wbits)
781 {
782 float[] block = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
783 float oozrange = 1.0f/header.Range;
784 float range = (1 << prequant);
785 float premult = oozrange*range;
786 float sub = (1 << (prequant - 1)) + header.DCOffset*premult;
787 int wordsize = (prequant - 2) & 0x0f;
788
789 header.QuantWBits = wordsize;
790 header.QuantWBits |= wordsize << 4;
791
792 int k = 0;
793 for (int j = 0; j < Constants.TerrainPatchSize; j++)
794 {
795 for (int i = 0; i < Constants.TerrainPatchSize; i++)
796 block[k++] = patchData[j, i]*premult - sub;
797 }
798
799 float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
800 int[] itemp = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
801
802 int maxWbits = prequant + 5;
803 wbits = (prequant >> 1);
804
805 for (int o = 0; o < Constants.TerrainPatchSize; o++)
806 DCTLine16(block, ftemp, o);
807 for (int o = 0; o < Constants.TerrainPatchSize; o++)
808 wbits = DCTColumn16Wbits(ftemp, itemp, o, wbits, maxWbits);
809
810 return itemp;
811 }
812
813 private static int[] CompressPatch(TerrainData terrData, int patchX, int patchY, TerrainPatch.Header header,
814 int prequant, out int wbits)
815 {
816 float[] block = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
817 int wordsize = prequant;
818 float oozrange = 1.0f/header.Range;
819 float range = (1 << prequant);
820 float premult = oozrange*range;
821 float sub = (1 << (prequant - 1)) + header.DCOffset*premult;
822
823 header.QuantWBits = wordsize - 2;
824 header.QuantWBits |= (prequant - 2) << 4;
825
826 int k = 0;
827
828 int yPatchLimit = patchY >= (terrData.SizeY / Constants.TerrainPatchSize) ?
829 (terrData.SizeY - Constants.TerrainPatchSize) / Constants.TerrainPatchSize : patchY;
830 yPatchLimit = (yPatchLimit + 1) * Constants.TerrainPatchSize;
831
832 int xPatchLimit = patchX >= (terrData.SizeX / Constants.TerrainPatchSize) ?
833 (terrData.SizeX - Constants.TerrainPatchSize) / Constants.TerrainPatchSize : patchX;
834 xPatchLimit = (xPatchLimit + 1) * Constants.TerrainPatchSize;
835
836 for (int yy = patchY * Constants.TerrainPatchSize; yy < yPatchLimit; yy++)
837 {
838 for (int xx = patchX * Constants.TerrainPatchSize; xx < xPatchLimit; xx++)
839 {
840 block[k++] = terrData[xx, yy] * premult - sub;
841 }
842 }
843
844 float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
845 int[] itemp = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
846
847 int maxWbits = prequant + 5;
848 wbits = (prequant >> 1);
849
850 for (int o = 0; o < Constants.TerrainPatchSize; o++)
851 DCTLine16(block, ftemp, o);
852 for (int o = 0; o < Constants.TerrainPatchSize; o++)
853 wbits = DCTColumn16Wbits(ftemp, itemp, o, wbits, maxWbits);
854
855 return itemp;
856 }
857
858 #region Initialization
859
860 private static void BuildDequantizeTable16()
861 {
862 for (int j = 0; j < Constants.TerrainPatchSize; j++)
863 {
864 for (int i = 0; i < Constants.TerrainPatchSize; i++)
865 {
866 DequantizeTable16[j*Constants.TerrainPatchSize + i] = 1.0f + 2.0f*(i + j);
867 }
868 }
869 }
870
871 private static void BuildQuantizeTable16()
872 {
873 const float oosob = 2.0f/Constants.TerrainPatchSize;
874 for (int j = 0; j < Constants.TerrainPatchSize; j++)
875 {
876 for (int i = 0; i < Constants.TerrainPatchSize; i++)
877 {
878// QuantizeTable16[j * Constants.TerrainPatchSize + i] = 1.0f / (1.0f + 2.0f * ((float)i + (float)j));
879 QuantizeTable16[j*Constants.TerrainPatchSize + i] = oosob/(1.0f + 2.0f*(i + (float) j));
880 }
881 }
882 }
883
884 private static void SetupCosines16()
885 {
886 const float hposz = (float) Math.PI*0.5f/Constants.TerrainPatchSize;
887
888 for (int u = 0; u < Constants.TerrainPatchSize; u++)
889 {
890 for (int n = 0; n < Constants.TerrainPatchSize; n++)
891 {
892 CosineTable16[u*Constants.TerrainPatchSize + n] = (float) Math.Cos((2.0f*n + 1.0f)*u*hposz);
893 }
894 }
895 }
896
897 private static void BuildCopyMatrix16()
898 {
899 bool diag = false;
900 bool right = true;
901 int i = 0;
902 int j = 0;
903 int count = 0;
904
905 while (i < Constants.TerrainPatchSize && j < Constants.TerrainPatchSize)
906 {
907 CopyMatrix16[j*Constants.TerrainPatchSize + i] = count++;
908
909 if (!diag)
910 {
911 if (right)
912 {
913 if (i < Constants.TerrainPatchSize - 1) i++;
914 else j++;
915
916 right = false;
917 diag = true;
918 }
919 else
920 {
921 if (j < Constants.TerrainPatchSize - 1) j++;
922 else i++;
923
924 right = true;
925 diag = true;
926 }
927 }
928 else
929 {
930 if (right)
931 {
932 i++;
933 j--;
934 if (i == Constants.TerrainPatchSize - 1 || j == 0) diag = false;
935 }
936 else
937 {
938 i--;
939 j++;
940 if (j == Constants.TerrainPatchSize - 1 || i == 0) diag = false;
941 }
942 }
943 }
944 }
945
946 #endregion Initialization
947 }
948}
diff --git a/OpenSim/Region/Framework/Scenes/Tests/EntityManagerTests.cs b/OpenSim/Region/Framework/Scenes/Tests/EntityManagerTests.cs
index 766ce83..da18941 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/EntityManagerTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/EntityManagerTests.cs
@@ -34,7 +34,6 @@ using Nini.Config;
34using NUnit.Framework; 34using NUnit.Framework;
35using OpenMetaverse; 35using OpenMetaverse;
36using OpenSim.Framework; 36using OpenSim.Framework;
37using OpenSim.Framework.Communications;
38using OpenSim.Region.Framework.Scenes; 37using OpenSim.Region.Framework.Scenes;
39using OpenSim.Tests.Common; 38using OpenSim.Tests.Common;
40 39
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneGraphTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneGraphTests.cs
index 575a081..ee7c8a9 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/SceneGraphTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/SceneGraphTests.cs
@@ -32,10 +32,8 @@ using System.Text;
32using NUnit.Framework; 32using NUnit.Framework;
33using OpenMetaverse; 33using OpenMetaverse;
34using OpenSim.Framework; 34using OpenSim.Framework;
35using OpenSim.Framework.Communications;
36using OpenSim.Region.Framework.Scenes; 35using OpenSim.Region.Framework.Scenes;
37using OpenSim.Tests.Common; 36using OpenSim.Tests.Common;
38using OpenSim.Tests.Common.Mock;
39 37
40namespace OpenSim.Region.Framework.Scenes.Tests 38namespace OpenSim.Region.Framework.Scenes.Tests
41{ 39{
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneManagerTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneManagerTests.cs
index 2d831fa..3172227 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/SceneManagerTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/SceneManagerTests.cs
@@ -32,11 +32,9 @@ using System.Threading;
32using NUnit.Framework; 32using NUnit.Framework;
33using OpenMetaverse; 33using OpenMetaverse;
34using OpenSim.Framework; 34using OpenSim.Framework;
35using OpenSim.Framework.Communications;
36using OpenSim.Region.Framework.Scenes; 35using OpenSim.Region.Framework.Scenes;
37using OpenSim.Services.Interfaces; 36using OpenSim.Services.Interfaces;
38using OpenSim.Tests.Common; 37using OpenSim.Tests.Common;
39using OpenSim.Tests.Common.Mock;
40 38
41namespace OpenSim.Region.Framework.Scenes.Tests 39namespace OpenSim.Region.Framework.Scenes.Tests
42{ 40{
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs
index a07d64c..098f1b4 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs
@@ -33,11 +33,9 @@ using Nini.Config;
33using NUnit.Framework; 33using NUnit.Framework;
34using OpenMetaverse; 34using OpenMetaverse;
35using OpenSim.Framework; 35using OpenSim.Framework;
36using OpenSim.Framework.Communications;
37using OpenSim.Region.Framework.Scenes; 36using OpenSim.Region.Framework.Scenes;
38using OpenSim.Services.Interfaces; 37using OpenSim.Services.Interfaces;
39using OpenSim.Tests.Common; 38using OpenSim.Tests.Common;
40using OpenSim.Tests.Common.Mock;
41 39
42namespace OpenSim.Region.Framework.Scenes.Tests 40namespace OpenSim.Region.Framework.Scenes.Tests
43{ 41{
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectCopyTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectCopyTests.cs
new file mode 100644
index 0000000..0b196c1
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectCopyTests.cs
@@ -0,0 +1,346 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using Nini.Config;
32using NUnit.Framework;
33using OpenMetaverse;
34using OpenSim.Framework;
35using OpenSim.Region.CoreModules.Framework.EntityTransfer;
36using OpenSim.Region.CoreModules.Framework.InventoryAccess;
37using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation;
38using OpenSim.Region.CoreModules.World.Permissions;
39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Services.Interfaces;
41using OpenSim.Tests.Common;
42
43namespace OpenSim.Region.Framework.Scenes.Tests
44{
45 /// <summary>
46 /// Test copying of scene objects.
47 /// </summary>
48 /// <remarks>
49 /// This is at a level above the SceneObjectBasicTests, which act on the scene directly.
50 /// </remarks>
51 [TestFixture]
52 public class SceneObjectCopyTests : OpenSimTestCase
53 {
54 [TestFixtureSetUp]
55 public void FixtureInit()
56 {
57 // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
58 // This facility was added after the original async delete tests were written, so it may be possible now
59 // to not bother explicitly disabling their async (since everything will be running sync).
60 Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest;
61 }
62
63 [TestFixtureTearDown]
64 public void TearDown()
65 {
66 // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
67 // threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression
68 // tests really shouldn't).
69 Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
70 }
71
72 [Test]
73 public void TestTakeCopyWhenCopierIsOwnerWithPerms()
74 {
75 TestHelpers.InMethod();
76// TestHelpers.EnableLogging();
77
78 IConfigSource config = new IniConfigSource();
79 config.AddConfig("Modules");
80 config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule");
81
82 TestScene scene = new SceneHelpers().SetupScene("s1", TestHelpers.ParseTail(0x99), 1000, 1000, config);
83 SceneHelpers.SetupSceneModules(scene, config, new PermissionsModule(), new BasicInventoryAccessModule());
84 UserAccount ua = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(0x1));
85 TestClient client = (TestClient)SceneHelpers.AddScenePresence(scene, ua.PrincipalID).ControllingClient;
86
87 // Turn off the timer on the async sog deleter - we'll crank it by hand for this test.
88 AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter;
89 sogd.Enabled = false;
90
91 SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, "so1", ua.PrincipalID);
92 uint soLocalId = so.LocalId;
93// so.UpdatePermissions(
94// ua.PrincipalID, (byte)PermissionWho.Owner, so.LocalId, (uint)OpenMetaverse.PermissionMask.Copy, 1);
95// so.UpdatePermissions(
96// ua.PrincipalID, (byte)PermissionWho.Owner, so.LocalId, (uint)OpenMetaverse.PermissionMask.Transfer, 0);
97// so.UpdatePermissions(
98// ua.PrincipalID, (byte)PermissionWho.Base, so.LocalId, (uint)OpenMetaverse.PermissionMask.Transfer, 0);
99// scene.HandleObjectPermissionsUpdate(client, client.AgentId, client.SessionId, (byte)PermissionWho.Owner, so.LocalId, (uint)OpenMetaverse.PermissionMask.Transfer, 0);
100
101 // Ideally we might change these via client-focussed method calls as commented out above. However, this
102 // becomes very convoluted so we will set only the copy perm directly.
103 so.RootPart.BaseMask = (uint)OpenMetaverse.PermissionMask.Copy;
104// so.RootPart.OwnerMask = (uint)OpenMetaverse.PermissionMask.Copy;
105
106 List<uint> localIds = new List<uint>();
107 localIds.Add(so.LocalId);
108
109 // Specifying a UUID.Zero in this case will currently plop it in Lost and Found
110 scene.DeRezObjects(client, localIds, UUID.Zero, DeRezAction.TakeCopy, UUID.Zero);
111
112 // Check that object isn't copied until we crank the sogd handle.
113 SceneObjectPart retrievedPart = scene.GetSceneObjectPart(so.LocalId);
114 Assert.That(retrievedPart, Is.Not.Null);
115 Assert.That(retrievedPart.ParentGroup.IsDeleted, Is.False);
116
117 sogd.InventoryDeQueueAndDelete();
118
119 // Check that object is still there.
120 SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId);
121 Assert.That(retrievedPart2, Is.Not.Null);
122 Assert.That(client.ReceivedKills.Count, Is.EqualTo(0));
123
124 // Check that we have a copy in inventory
125 InventoryItemBase item
126 = UserInventoryHelpers.GetInventoryItem(scene.InventoryService, ua.PrincipalID, "Lost And Found/so1");
127 Assert.That(item, Is.Not.Null);
128 }
129
130 [Test]
131 public void TestTakeCopyWhenCopierIsOwnerWithoutPerms()
132 {
133 TestHelpers.InMethod();
134// TestHelpers.EnableLogging();
135
136 IConfigSource config = new IniConfigSource();
137 config.AddConfig("Modules");
138 config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule");
139
140 TestScene scene = new SceneHelpers().SetupScene("s1", TestHelpers.ParseTail(0x99), 1000, 1000, config);
141 SceneHelpers.SetupSceneModules(scene, config, new PermissionsModule(), new BasicInventoryAccessModule());
142 UserAccount ua = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(0x1));
143 TestClient client = (TestClient)SceneHelpers.AddScenePresence(scene, ua.PrincipalID).ControllingClient;
144
145 // Turn off the timer on the async sog deleter - we'll crank it by hand for this test.
146 AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter;
147 sogd.Enabled = false;
148
149 SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, "so1", ua.PrincipalID);
150 uint soLocalId = so.LocalId;
151
152 so.RootPart.BaseMask = (uint)(OpenMetaverse.PermissionMask.All & ~OpenMetaverse.PermissionMask.Copy);
153 //so.RootPart.OwnerMask = (uint)(OpenMetaverse.PermissionMask.Copy & ~OpenMetaverse.PermissionMask.Copy);
154
155 List<uint> localIds = new List<uint>();
156 localIds.Add(so.LocalId);
157
158 // Specifying a UUID.Zero in this case will currently plop it in Lost and Found
159 scene.DeRezObjects(client, localIds, UUID.Zero, DeRezAction.TakeCopy, UUID.Zero);
160
161 // Check that object isn't copied until we crank the sogd handle.
162 SceneObjectPart retrievedPart = scene.GetSceneObjectPart(so.LocalId);
163 Assert.That(retrievedPart, Is.Not.Null);
164 Assert.That(retrievedPart.ParentGroup.IsDeleted, Is.False);
165
166 sogd.InventoryDeQueueAndDelete();
167
168 // Check that object is still there.
169 SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId);
170 Assert.That(retrievedPart2, Is.Not.Null);
171 Assert.That(client.ReceivedKills.Count, Is.EqualTo(0));
172
173 // Check that we do not have a copy in inventory
174 InventoryItemBase item
175 = UserInventoryHelpers.GetInventoryItem(scene.InventoryService, ua.PrincipalID, "Lost And Found/so1");
176 Assert.That(item, Is.Null);
177 }
178
179 [Test]
180 public void TestTakeCopyWhenCopierIsNotOwnerWithPerms()
181 {
182 TestHelpers.InMethod();
183// TestHelpers.EnableLogging();
184
185 IConfigSource config = new IniConfigSource();
186 config.AddConfig("Modules");
187 config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule");
188
189 TestScene scene = new SceneHelpers().SetupScene("s1", TestHelpers.ParseTail(0x99), 1000, 1000, config);
190 SceneHelpers.SetupSceneModules(scene, config, new PermissionsModule(), new BasicInventoryAccessModule());
191 UserAccount ua = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(0x1));
192 TestClient client = (TestClient)SceneHelpers.AddScenePresence(scene, ua.PrincipalID).ControllingClient;
193
194 // Turn off the timer on the async sog deleter - we'll crank it by hand for this test.
195 AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter;
196 sogd.Enabled = false;
197
198 SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, "so1", TestHelpers.ParseTail(0x2));
199 uint soLocalId = so.LocalId;
200
201 // Base must allow transfer and copy
202 so.RootPart.BaseMask = (uint)(OpenMetaverse.PermissionMask.Copy | OpenMetaverse.PermissionMask.Transfer);
203 // Must be set so anyone can copy
204 so.RootPart.EveryoneMask = (uint)OpenMetaverse.PermissionMask.Copy;
205
206 List<uint> localIds = new List<uint>();
207 localIds.Add(so.LocalId);
208
209 // Specifying a UUID.Zero in this case will plop it in the Objects folder
210 scene.DeRezObjects(client, localIds, UUID.Zero, DeRezAction.TakeCopy, UUID.Zero);
211
212 // Check that object isn't copied until we crank the sogd handle.
213 SceneObjectPart retrievedPart = scene.GetSceneObjectPart(so.LocalId);
214 Assert.That(retrievedPart, Is.Not.Null);
215 Assert.That(retrievedPart.ParentGroup.IsDeleted, Is.False);
216
217 sogd.InventoryDeQueueAndDelete();
218
219 // Check that object is still there.
220 SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId);
221 Assert.That(retrievedPart2, Is.Not.Null);
222 Assert.That(client.ReceivedKills.Count, Is.EqualTo(0));
223
224 // Check that we have a copy in inventory
225 InventoryItemBase item
226 = UserInventoryHelpers.GetInventoryItem(scene.InventoryService, ua.PrincipalID, "Objects/so1");
227 Assert.That(item, Is.Not.Null);
228 }
229
230 [Test]
231 public void TestTakeCopyWhenCopierIsNotOwnerWithoutPerms()
232 {
233 TestHelpers.InMethod();
234// TestHelpers.EnableLogging();
235
236 IConfigSource config = new IniConfigSource();
237 config.AddConfig("Modules");
238 config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule");
239
240 TestScene scene = new SceneHelpers().SetupScene("s1", TestHelpers.ParseTail(0x99), 1000, 1000, config);
241 SceneHelpers.SetupSceneModules(scene, config, new PermissionsModule(), new BasicInventoryAccessModule());
242 UserAccount ua = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(0x1));
243 TestClient client = (TestClient)SceneHelpers.AddScenePresence(scene, ua.PrincipalID).ControllingClient;
244
245 // Turn off the timer on the async sog deleter - we'll crank it by hand for this test.
246 AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter;
247 sogd.Enabled = false;
248
249 SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, "so1", TestHelpers.ParseTail(0x2));
250 uint soLocalId = so.LocalId;
251
252 {
253 // Check that object is not copied if copy base perms is missing.
254 // Should not allow copy if base does not have this.
255 so.RootPart.BaseMask = (uint)OpenMetaverse.PermissionMask.Transfer;
256 // Must be set so anyone can copy
257 so.RootPart.EveryoneMask = (uint)OpenMetaverse.PermissionMask.Copy;
258
259 // Check that object is not copied
260 List<uint> localIds = new List<uint>();
261 localIds.Add(so.LocalId);
262
263 // Specifying a UUID.Zero in this case will plop it in the Objects folder if we have perms
264 scene.DeRezObjects(client, localIds, UUID.Zero, DeRezAction.TakeCopy, UUID.Zero);
265
266 // Check that object isn't copied until we crank the sogd handle.
267 SceneObjectPart retrievedPart = scene.GetSceneObjectPart(so.LocalId);
268 Assert.That(retrievedPart, Is.Not.Null);
269 Assert.That(retrievedPart.ParentGroup.IsDeleted, Is.False);
270
271 sogd.InventoryDeQueueAndDelete();
272 // Check that object is still there.
273 SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId);
274 Assert.That(retrievedPart2, Is.Not.Null);
275 Assert.That(client.ReceivedKills.Count, Is.EqualTo(0));
276
277 // Check that we have a copy in inventory
278 InventoryItemBase item
279 = UserInventoryHelpers.GetInventoryItem(scene.InventoryService, ua.PrincipalID, "Objects/so1");
280 Assert.That(item, Is.Null);
281 }
282
283 {
284 // Check that object is not copied if copy trans perms is missing.
285 // Should not allow copy if base does not have this.
286 so.RootPart.BaseMask = (uint)OpenMetaverse.PermissionMask.Copy;
287 // Must be set so anyone can copy
288 so.RootPart.EveryoneMask = (uint)OpenMetaverse.PermissionMask.Copy;
289
290 // Check that object is not copied
291 List<uint> localIds = new List<uint>();
292 localIds.Add(so.LocalId);
293
294 // Specifying a UUID.Zero in this case will plop it in the Objects folder if we have perms
295 scene.DeRezObjects(client, localIds, UUID.Zero, DeRezAction.TakeCopy, UUID.Zero);
296
297 // Check that object isn't copied until we crank the sogd handle.
298 SceneObjectPart retrievedPart = scene.GetSceneObjectPart(so.LocalId);
299 Assert.That(retrievedPart, Is.Not.Null);
300 Assert.That(retrievedPart.ParentGroup.IsDeleted, Is.False);
301
302 sogd.InventoryDeQueueAndDelete();
303 // Check that object is still there.
304 SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId);
305 Assert.That(retrievedPart2, Is.Not.Null);
306 Assert.That(client.ReceivedKills.Count, Is.EqualTo(0));
307
308 // Check that we have a copy in inventory
309 InventoryItemBase item
310 = UserInventoryHelpers.GetInventoryItem(scene.InventoryService, ua.PrincipalID, "Objects/so1");
311 Assert.That(item, Is.Null);
312 }
313
314 {
315 // Check that object is not copied if everyone copy perms is missing.
316 // Should not allow copy if base does not have this.
317 so.RootPart.BaseMask = (uint)(OpenMetaverse.PermissionMask.Copy | OpenMetaverse.PermissionMask.Transfer);
318 // Make sure everyone perm does not allow copy
319 so.RootPart.EveryoneMask = (uint)(OpenMetaverse.PermissionMask.All & ~OpenMetaverse.PermissionMask.Copy);
320
321 // Check that object is not copied
322 List<uint> localIds = new List<uint>();
323 localIds.Add(so.LocalId);
324
325 // Specifying a UUID.Zero in this case will plop it in the Objects folder if we have perms
326 scene.DeRezObjects(client, localIds, UUID.Zero, DeRezAction.TakeCopy, UUID.Zero);
327
328 // Check that object isn't copied until we crank the sogd handle.
329 SceneObjectPart retrievedPart = scene.GetSceneObjectPart(so.LocalId);
330 Assert.That(retrievedPart, Is.Not.Null);
331 Assert.That(retrievedPart.ParentGroup.IsDeleted, Is.False);
332
333 sogd.InventoryDeQueueAndDelete();
334 // Check that object is still there.
335 SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId);
336 Assert.That(retrievedPart2, Is.Not.Null);
337 Assert.That(client.ReceivedKills.Count, Is.EqualTo(0));
338
339 // Check that we have a copy in inventory
340 InventoryItemBase item
341 = UserInventoryHelpers.GetInventoryItem(scene.InventoryService, ua.PrincipalID, "Objects/so1");
342 Assert.That(item, Is.Null);
343 }
344 }
345 }
346} \ No newline at end of file
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectCrossingTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectCrossingTests.cs
new file mode 100644
index 0000000..5635c20
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectCrossingTests.cs
@@ -0,0 +1,259 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using Nini.Config;
31using NUnit.Framework;
32using OpenMetaverse;
33using OpenSim.Framework;
34using OpenSim.Region.CoreModules.Framework;
35using OpenSim.Region.CoreModules.Framework.EntityTransfer;
36using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation;
37using OpenSim.Region.CoreModules.World.Land;
38using OpenSim.Region.OptionalModules;
39using OpenSim.Tests.Common;
40
41namespace OpenSim.Region.Framework.Scenes.Tests
42{
43 public class SceneObjectCrossingTests : OpenSimTestCase
44 {
45 [TestFixtureSetUp]
46 public void FixtureInit()
47 {
48 // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
49 Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest;
50 }
51
52 [TestFixtureTearDown]
53 public void TearDown()
54 {
55 // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
56 // threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression
57 // tests really shouldn't).
58 Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
59 }
60
61 /// <summary>
62 /// Test cross with no prim limit module.
63 /// </summary>
64 [Test]
65 public void TestCrossOnSameSimulator()
66 {
67 TestHelpers.InMethod();
68// TestHelpers.EnableLogging();
69
70 UUID userId = TestHelpers.ParseTail(0x1);
71 int sceneObjectIdTail = 0x2;
72
73 EntityTransferModule etmA = new EntityTransferModule();
74 EntityTransferModule etmB = new EntityTransferModule();
75 LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule();
76
77 IConfigSource config = new IniConfigSource();
78 IConfig modulesConfig = config.AddConfig("Modules");
79 modulesConfig.Set("EntityTransferModule", etmA.Name);
80 modulesConfig.Set("SimulationServices", lscm.Name);
81
82 SceneHelpers sh = new SceneHelpers();
83 TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000);
84 TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1000, 999);
85
86 SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm);
87 SceneHelpers.SetupSceneModules(sceneA, config, etmA);
88 SceneHelpers.SetupSceneModules(sceneB, config, etmB);
89
90 SceneObjectGroup so1 = SceneHelpers.AddSceneObject(sceneA, 1, userId, "", sceneObjectIdTail);
91 UUID so1Id = so1.UUID;
92 so1.AbsolutePosition = new Vector3(128, 10, 20);
93
94 // Cross with a negative value
95 so1.AbsolutePosition = new Vector3(128, -10, 20);
96
97 Assert.IsNull(sceneA.GetSceneObjectGroup(so1Id));
98 Assert.NotNull(sceneB.GetSceneObjectGroup(so1Id));
99 }
100
101 /// <summary>
102 /// Test cross with no prim limit module.
103 /// </summary>
104 /// <remarks>
105 /// Possibly this should belong in ScenePresenceCrossingTests, though here it is the object that is being moved
106 /// where the avatar is just a passenger.
107 /// </remarks>
108 [Test]
109 public void TestCrossOnSameSimulatorWithSittingAvatar()
110 {
111 TestHelpers.InMethod();
112// TestHelpers.EnableLogging();
113
114 UUID userId = TestHelpers.ParseTail(0x1);
115 int sceneObjectIdTail = 0x2;
116 Vector3 so1StartPos = new Vector3(128, 10, 20);
117
118 EntityTransferModule etmA = new EntityTransferModule();
119 EntityTransferModule etmB = new EntityTransferModule();
120 LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule();
121
122 IConfigSource config = new IniConfigSource();
123 IConfig modulesConfig = config.AddConfig("Modules");
124 modulesConfig.Set("EntityTransferModule", etmA.Name);
125 modulesConfig.Set("SimulationServices", lscm.Name);
126 IConfig entityTransferConfig = config.AddConfig("EntityTransfer");
127
128 // In order to run a single threaded regression test we do not want the entity transfer module waiting
129 // for a callback from the destination scene before removing its avatar data.
130 entityTransferConfig.Set("wait_for_callback", false);
131
132 SceneHelpers sh = new SceneHelpers();
133 TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000);
134 TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1000, 999);
135
136 SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm);
137 SceneHelpers.SetupSceneModules(sceneA, config, new CapabilitiesModule(), etmA);
138 SceneHelpers.SetupSceneModules(sceneB, config, new CapabilitiesModule(), etmB);
139
140 SceneObjectGroup so1 = SceneHelpers.AddSceneObject(sceneA, 1, userId, "", sceneObjectIdTail);
141 UUID so1Id = so1.UUID;
142 so1.AbsolutePosition = so1StartPos;
143
144 AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId);
145 TestClient tc = new TestClient(acd, sceneA);
146 List<TestClient> destinationTestClients = new List<TestClient>();
147 EntityTransferHelpers.SetupInformClientOfNeighbourTriggersNeighbourClientCreate(tc, destinationTestClients);
148
149 ScenePresence sp1SceneA = SceneHelpers.AddScenePresence(sceneA, tc, acd);
150 sp1SceneA.AbsolutePosition = so1StartPos;
151 sp1SceneA.HandleAgentRequestSit(sp1SceneA.ControllingClient, sp1SceneA.UUID, so1.UUID, Vector3.Zero);
152
153 // Cross
154 sceneA.SceneGraph.UpdatePrimGroupPosition(
155 so1.LocalId, new Vector3(so1StartPos.X, so1StartPos.Y - 20, so1StartPos.Z), userId);
156
157 SceneObjectGroup so1PostCross;
158
159 {
160 ScenePresence sp1SceneAPostCross = sceneA.GetScenePresence(userId);
161 Assert.IsTrue(sp1SceneAPostCross.IsChildAgent, "sp1SceneAPostCross.IsChildAgent unexpectedly false");
162
163 ScenePresence sp1SceneBPostCross = sceneB.GetScenePresence(userId);
164 TestClient sceneBTc = ((TestClient)sp1SceneBPostCross.ControllingClient);
165 sceneBTc.CompleteMovement();
166
167 Assert.IsFalse(sp1SceneBPostCross.IsChildAgent, "sp1SceneAPostCross.IsChildAgent unexpectedly true");
168 Assert.IsTrue(sp1SceneBPostCross.IsSatOnObject);
169
170 Assert.IsNull(sceneA.GetSceneObjectGroup(so1Id), "uck");
171 so1PostCross = sceneB.GetSceneObjectGroup(so1Id);
172 Assert.NotNull(so1PostCross);
173 Assert.AreEqual(1, so1PostCross.GetSittingAvatarsCount());
174 }
175
176 Vector3 so1PostCrossPos = so1PostCross.AbsolutePosition;
177
178// Console.WriteLine("CRISSCROSS");
179
180 // Recross
181 sceneB.SceneGraph.UpdatePrimGroupPosition(
182 so1PostCross.LocalId, new Vector3(so1PostCrossPos.X, so1PostCrossPos.Y + 20, so1PostCrossPos.Z), userId);
183
184 {
185 ScenePresence sp1SceneBPostReCross = sceneB.GetScenePresence(userId);
186 Assert.IsTrue(sp1SceneBPostReCross.IsChildAgent, "sp1SceneBPostReCross.IsChildAgent unexpectedly false");
187
188 ScenePresence sp1SceneAPostReCross = sceneA.GetScenePresence(userId);
189 TestClient sceneATc = ((TestClient)sp1SceneAPostReCross.ControllingClient);
190 sceneATc.CompleteMovement();
191
192 Assert.IsFalse(sp1SceneAPostReCross.IsChildAgent, "sp1SceneAPostCross.IsChildAgent unexpectedly true");
193 Assert.IsTrue(sp1SceneAPostReCross.IsSatOnObject);
194
195 Assert.IsNull(sceneB.GetSceneObjectGroup(so1Id), "uck2");
196 SceneObjectGroup so1PostReCross = sceneA.GetSceneObjectGroup(so1Id);
197 Assert.NotNull(so1PostReCross);
198 Assert.AreEqual(1, so1PostReCross.GetSittingAvatarsCount());
199 }
200 }
201
202 /// <summary>
203 /// Test cross with no prim limit module.
204 /// </summary>
205 /// <remarks>
206 /// XXX: This test may FCbe better off in a specific PrimLimitsModuleTest class in optional module tests in the
207 /// future (though it is configured as active by default, so not really optional).
208 /// </remarks>
209 [Test]
210 public void TestCrossOnSameSimulatorPrimLimitsOkay()
211 {
212 TestHelpers.InMethod();
213// TestHelpers.EnableLogging();
214
215 UUID userId = TestHelpers.ParseTail(0x1);
216 int sceneObjectIdTail = 0x2;
217
218 EntityTransferModule etmA = new EntityTransferModule();
219 EntityTransferModule etmB = new EntityTransferModule();
220 LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule();
221 LandManagementModule lmmA = new LandManagementModule();
222 LandManagementModule lmmB = new LandManagementModule();
223
224 IConfigSource config = new IniConfigSource();
225 IConfig modulesConfig = config.AddConfig("Modules");
226 modulesConfig.Set("EntityTransferModule", etmA.Name);
227 modulesConfig.Set("SimulationServices", lscm.Name);
228
229 IConfig permissionsConfig = config.AddConfig("Permissions");
230 permissionsConfig.Set("permissionmodules", "PrimLimitsModule");
231
232 SceneHelpers sh = new SceneHelpers();
233 TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000);
234 TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1000, 999);
235
236 SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm);
237 SceneHelpers.SetupSceneModules(
238 sceneA, config, etmA, lmmA, new PrimLimitsModule(), new PrimCountModule());
239 SceneHelpers.SetupSceneModules(
240 sceneB, config, etmB, lmmB, new PrimLimitsModule(), new PrimCountModule());
241
242 // We must set up the parcel for this to work. Normally this is taken care of by OpenSimulator startup
243 // code which is not yet easily invoked by tests.
244 lmmA.EventManagerOnNoLandDataFromStorage();
245 lmmB.EventManagerOnNoLandDataFromStorage();
246
247 SceneObjectGroup so1 = SceneHelpers.AddSceneObject(sceneA, 1, userId, "", sceneObjectIdTail);
248 UUID so1Id = so1.UUID;
249 so1.AbsolutePosition = new Vector3(128, 10, 20);
250
251 // Cross with a negative value. We must make this call rather than setting AbsolutePosition directly
252 // because only this will execute permission checks in the source region.
253 sceneA.SceneGraph.UpdatePrimGroupPosition(so1.LocalId, new Vector3(128, -10, 20), userId);
254
255 Assert.IsNull(sceneA.GetSceneObjectGroup(so1Id));
256 Assert.NotNull(sceneB.GetSceneObjectGroup(so1Id));
257 }
258 }
259} \ No newline at end of file
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs
index c1522e7..1c396ac 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs
@@ -32,13 +32,13 @@ using Nini.Config;
32using NUnit.Framework; 32using NUnit.Framework;
33using OpenMetaverse; 33using OpenMetaverse;
34using OpenSim.Framework; 34using OpenSim.Framework;
35using OpenSim.Framework.Communications; 35using OpenSim.Region.CoreModules.Framework.EntityTransfer;
36using OpenSim.Region.CoreModules.Framework.InventoryAccess; 36using OpenSim.Region.CoreModules.Framework.InventoryAccess;
37using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation;
37using OpenSim.Region.CoreModules.World.Permissions; 38using OpenSim.Region.CoreModules.World.Permissions;
38using OpenSim.Region.Framework.Scenes; 39using OpenSim.Region.Framework.Scenes;
39using OpenSim.Services.Interfaces; 40using OpenSim.Services.Interfaces;
40using OpenSim.Tests.Common; 41using OpenSim.Tests.Common;
41using OpenSim.Tests.Common.Mock;
42 42
43namespace OpenSim.Region.Framework.Scenes.Tests 43namespace OpenSim.Region.Framework.Scenes.Tests
44{ 44{
@@ -52,6 +52,24 @@ namespace OpenSim.Region.Framework.Scenes.Tests
52 [TestFixture] 52 [TestFixture]
53 public class SceneObjectDeRezTests : OpenSimTestCase 53 public class SceneObjectDeRezTests : OpenSimTestCase
54 { 54 {
55 [TestFixtureSetUp]
56 public void FixtureInit()
57 {
58 // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
59 // This facility was added after the original async delete tests were written, so it may be possible now
60 // to not bother explicitly disabling their async (since everything will be running sync).
61 Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest;
62 }
63
64 [TestFixtureTearDown]
65 public void TearDown()
66 {
67 // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
68 // threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression
69 // tests really shouldn't).
70 Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
71 }
72
55 /// <summary> 73 /// <summary>
56 /// Test deleting an object from a scene. 74 /// Test deleting an object from a scene.
57 /// </summary> 75 /// </summary>
@@ -59,46 +77,96 @@ namespace OpenSim.Region.Framework.Scenes.Tests
59 public void TestDeRezSceneObject() 77 public void TestDeRezSceneObject()
60 { 78 {
61 TestHelpers.InMethod(); 79 TestHelpers.InMethod();
62// log4net.Config.XmlConfigurator.Configure();
63 80
64 UUID userId = UUID.Parse("10000000-0000-0000-0000-000000000001"); 81 UUID userId = UUID.Parse("10000000-0000-0000-0000-000000000001");
65 82
66 TestScene scene = new SceneHelpers().SetupScene(); 83 TestScene scene = new SceneHelpers().SetupScene();
67 IConfigSource configSource = new IniConfigSource(); 84 SceneHelpers.SetupSceneModules(scene, new PermissionsModule());
68 IConfig config = configSource.AddConfig("Startup"); 85 TestClient client = (TestClient)SceneHelpers.AddScenePresence(scene, userId).ControllingClient;
69 config.Set("serverside_object_permissions", true);
70 SceneHelpers.SetupSceneModules(scene, configSource, new object[] { new PermissionsModule() });
71 IClientAPI client = SceneHelpers.AddScenePresence(scene, userId).ControllingClient;
72 86
73 // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. 87 // Turn off the timer on the async sog deleter - we'll crank it by hand for this test.
74 AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter; 88 AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter;
75 sogd.Enabled = false; 89 sogd.Enabled = false;
76 90
77 SceneObjectPart part 91 SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, "so1", userId);
78 = new SceneObjectPart(userId, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero); 92 uint soLocalId = so.LocalId;
79 part.Name = "obj1";
80 scene.AddNewSceneObject(new SceneObjectGroup(part), false);
81 93
82 List<uint> localIds = new List<uint>(); 94 List<uint> localIds = new List<uint>();
83 localIds.Add(part.LocalId); 95 localIds.Add(so.LocalId);
84 scene.DeRezObjects(client, localIds, UUID.Zero, DeRezAction.Delete, UUID.Zero); 96 scene.DeRezObjects(client, localIds, UUID.Zero, DeRezAction.Delete, UUID.Zero);
85 97
86 // Check that object isn't deleted until we crank the sogd handle. 98 // Check that object isn't deleted until we crank the sogd handle.
87 SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId); 99 SceneObjectPart retrievedPart = scene.GetSceneObjectPart(so.LocalId);
88 Assert.That(retrievedPart, Is.Not.Null); 100 Assert.That(retrievedPart, Is.Not.Null);
89 Assert.That(retrievedPart.ParentGroup.IsDeleted, Is.False); 101 Assert.That(retrievedPart.ParentGroup.IsDeleted, Is.False);
90 102
91 sogd.InventoryDeQueueAndDelete(); 103 sogd.InventoryDeQueueAndDelete();
92 104
93 SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(part.LocalId); 105 SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId);
94 Assert.That(retrievedPart2, Is.Null); 106 Assert.That(retrievedPart2, Is.Null);
107
108 Assert.That(client.ReceivedKills.Count, Is.EqualTo(1));
109 Assert.That(client.ReceivedKills[0], Is.EqualTo(soLocalId));
110 }
111
112 /// <summary>
113 /// Test that child and root agents correctly receive KillObject notifications.
114 /// </summary>
115 [Test]
116 public void TestDeRezSceneObjectToAgents()
117 {
118 TestHelpers.InMethod();
119// TestHelpers.EnableLogging();
120
121 SceneHelpers sh = new SceneHelpers();
122 TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000);
123 TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1000, 999);
124
125 // We need this so that the creation of the root client for userB in sceneB can trigger the creation of a child client in sceneA
126 LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule();
127 EntityTransferModule etmB = new EntityTransferModule();
128 IConfigSource config = new IniConfigSource();
129 IConfig modulesConfig = config.AddConfig("Modules");
130 modulesConfig.Set("EntityTransferModule", etmB.Name);
131 modulesConfig.Set("SimulationServices", lscm.Name);
132 SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm);
133 SceneHelpers.SetupSceneModules(sceneB, config, etmB);
134
135 // We need this for derez
136 SceneHelpers.SetupSceneModules(sceneA, new PermissionsModule());
137
138 UserAccount uaA = UserAccountHelpers.CreateUserWithInventory(sceneA, "Andy", "AAA", 0x1, "");
139 UserAccount uaB = UserAccountHelpers.CreateUserWithInventory(sceneA, "Brian", "BBB", 0x2, "");
140
141 TestClient clientA = (TestClient)SceneHelpers.AddScenePresence(sceneA, uaA).ControllingClient;
142
143 // This is the more long-winded route we have to take to get a child client created for userB in sceneA
144 // rather than just calling AddScenePresence() as for userA
145 AgentCircuitData acd = SceneHelpers.GenerateAgentData(uaB);
146 TestClient clientB = new TestClient(acd, sceneB);
147 List<TestClient> childClientsB = new List<TestClient>();
148 EntityTransferHelpers.SetupInformClientOfNeighbourTriggersNeighbourClientCreate(clientB, childClientsB);
149
150 SceneHelpers.AddScenePresence(sceneB, clientB, acd);
151
152 SceneObjectGroup so = SceneHelpers.AddSceneObject(sceneA);
153 uint soLocalId = so.LocalId;
154
155 sceneA.DeleteSceneObject(so, false);
156
157 Assert.That(clientA.ReceivedKills.Count, Is.EqualTo(1));
158 Assert.That(clientA.ReceivedKills[0], Is.EqualTo(soLocalId));
159
160 Assert.That(childClientsB[0].ReceivedKills.Count, Is.EqualTo(1));
161 Assert.That(childClientsB[0].ReceivedKills[0], Is.EqualTo(soLocalId));
95 } 162 }
96 163
97 /// <summary> 164 /// <summary>
98 /// Test deleting an object from a scene where the deleter is not the owner 165 /// Test deleting an object from a scene where the deleter is not the owner
99 /// </summary> 166 /// </summary>
100 /// 167 /// <remarks>
101 /// This test assumes that the deleter is not a god. 168 /// This test assumes that the deleter is not a god.
169 /// </remarks>
102 [Test] 170 [Test]
103 public void TestDeRezSceneObjectNotOwner() 171 public void TestDeRezSceneObjectNotOwner()
104 { 172 {
@@ -109,10 +177,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
109 UUID objectOwnerId = UUID.Parse("20000000-0000-0000-0000-000000000001"); 177 UUID objectOwnerId = UUID.Parse("20000000-0000-0000-0000-000000000001");
110 178
111 TestScene scene = new SceneHelpers().SetupScene(); 179 TestScene scene = new SceneHelpers().SetupScene();
112 IConfigSource configSource = new IniConfigSource(); 180 SceneHelpers.SetupSceneModules(scene, new PermissionsModule());
113 IConfig config = configSource.AddConfig("Startup");
114 config.Set("serverside_object_permissions", true);
115 SceneHelpers.SetupSceneModules(scene, configSource, new object[] { new PermissionsModule() });
116 IClientAPI client = SceneHelpers.AddScenePresence(scene, userId).ControllingClient; 181 IClientAPI client = SceneHelpers.AddScenePresence(scene, userId).ControllingClient;
117 182
118 // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. 183 // Turn off the timer on the async sog deleter - we'll crank it by hand for this test.
@@ -164,7 +229,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
164 229
165 UserAccount ua = UserAccountHelpers.CreateUserWithInventory(scene, agentId); 230 UserAccount ua = UserAccountHelpers.CreateUserWithInventory(scene, agentId);
166 InventoryFolderBase folder1 231 InventoryFolderBase folder1
167 = UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, ua.PrincipalID, "folder1"); 232 = UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, ua.PrincipalID, "folder1", false);
168 233
169 IClientAPI client = SceneHelpers.AddScenePresence(scene, agentId).ControllingClient; 234 IClientAPI client = SceneHelpers.AddScenePresence(scene, agentId).ControllingClient;
170 scene.DeRezObjects(client, new List<uint>() { so.LocalId }, UUID.Zero, DeRezAction.Take, folder1.ID); 235 scene.DeRezObjects(client, new List<uint>() { so.LocalId }, UUID.Zero, DeRezAction.Take, folder1.ID);
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs
index 9378e20..e6d5a2f 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs
@@ -31,10 +31,8 @@ using System.Reflection;
31using NUnit.Framework; 31using NUnit.Framework;
32using OpenMetaverse; 32using OpenMetaverse;
33using OpenSim.Framework; 33using OpenSim.Framework;
34using OpenSim.Framework.Communications;
35using OpenSim.Region.Framework.Scenes; 34using OpenSim.Region.Framework.Scenes;
36using OpenSim.Tests.Common; 35using OpenSim.Tests.Common;
37using OpenSim.Tests.Common.Mock;
38using log4net; 36using log4net;
39 37
40namespace OpenSim.Region.Framework.Scenes.Tests 38namespace OpenSim.Region.Framework.Scenes.Tests
@@ -91,7 +89,12 @@ namespace OpenSim.Region.Framework.Scenes.Tests
91 grp2.RootPart.ClearUpdateSchedule(); 89 grp2.RootPart.ClearUpdateSchedule();
92 90
93 // Link grp2 to grp1. part2 becomes child prim to grp1. grp2 is eliminated. 91 // Link grp2 to grp1. part2 becomes child prim to grp1. grp2 is eliminated.
92 Assert.IsFalse(grp1.GroupContainsForeignPrims);
94 grp1.LinkToGroup(grp2); 93 grp1.LinkToGroup(grp2);
94 Assert.IsTrue(grp1.GroupContainsForeignPrims);
95
96 scene.Backup(true);
97 Assert.IsFalse(grp1.GroupContainsForeignPrims);
95 98
96 // FIXME: Can't do this test yet since group 2 still has its root part! We can't yet null this since 99 // FIXME: Can't do this test yet since group 2 still has its root part! We can't yet null this since
97 // it might cause SOG.ProcessBackup() to fail due to the race condition. This really needs to be fixed. 100 // it might cause SOG.ProcessBackup() to fail due to the race condition. This really needs to be fixed.
@@ -143,7 +146,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
143 146
144 Assert.That(grp1.Parts.Length, Is.EqualTo(1), "Group 1 still contained part2 after delink."); 147 Assert.That(grp1.Parts.Length, Is.EqualTo(1), "Group 1 still contained part2 after delink.");
145 Assert.That(part2.AbsolutePosition == Vector3.Zero, "The absolute position should be zero"); 148 Assert.That(part2.AbsolutePosition == Vector3.Zero, "The absolute position should be zero");
146 Assert.That(grp3.HasGroupChangedDueToDelink, Is.True); 149 Assert.NotNull(grp3);
147 } 150 }
148 151
149 [Test] 152 [Test]
@@ -335,30 +338,34 @@ namespace OpenSim.Region.Framework.Scenes.Tests
335 SceneObjectPart rootPart 338 SceneObjectPart rootPart
336 = new SceneObjectPart(UUID.Zero, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero) 339 = new SceneObjectPart(UUID.Zero, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero)
337 { Name = rootPartName, UUID = rootPartUuid }; 340 { Name = rootPartName, UUID = rootPartUuid };
341
338 SceneObjectPart linkPart 342 SceneObjectPart linkPart
339 = new SceneObjectPart(UUID.Zero, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero) 343 = new SceneObjectPart(UUID.Zero, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero)
340 { Name = linkPartName, UUID = linkPartUuid }; 344 { Name = linkPartName, UUID = linkPartUuid };
345 SceneObjectGroup linkGroup = new SceneObjectGroup(linkPart);
346 scene.AddNewSceneObject(linkGroup, true);
341 347
342 SceneObjectGroup sog = new SceneObjectGroup(rootPart); 348 SceneObjectGroup sog = new SceneObjectGroup(rootPart);
343 sog.AddPart(linkPart); 349 scene.AddNewSceneObject(sog, true);
344 scene.AddNewSceneObject(sog, true); 350
345 351 Assert.IsFalse(sog.GroupContainsForeignPrims);
346 // In a test, we have to crank the backup handle manually. Normally this would be done by the timer invoked 352 sog.LinkToGroup(linkGroup);
347 // scene backup thread. 353 Assert.IsTrue(sog.GroupContainsForeignPrims);
354
348 scene.Backup(true); 355 scene.Backup(true);
349 356 Assert.AreEqual(1, scene.SimulationDataService.LoadObjects(scene.RegionInfo.RegionID).Count);
357
350 // These changes should occur immediately without waiting for a backup pass 358 // These changes should occur immediately without waiting for a backup pass
351 SceneObjectGroup groupToDelete = sog.DelinkFromGroup(linkPart, false); 359 SceneObjectGroup groupToDelete = sog.DelinkFromGroup(linkPart, false);
352 360 Assert.IsFalse(groupToDelete.GroupContainsForeignPrims);
353 Assert.That(groupToDelete.HasGroupChangedDueToDelink, Is.True); 361
354 scene.DeleteSceneObject(groupToDelete, false); 362 scene.DeleteSceneObject(groupToDelete, false);
355 Assert.That(groupToDelete.HasGroupChangedDueToDelink, Is.False);
356 363
357 List<SceneObjectGroup> storedObjects = scene.SimulationDataService.LoadObjects(scene.RegionInfo.RegionID); 364 List<SceneObjectGroup> storedObjects = scene.SimulationDataService.LoadObjects(scene.RegionInfo.RegionID);
358 365
359 Assert.That(storedObjects.Count, Is.EqualTo(1)); 366 Assert.AreEqual(1, storedObjects.Count);
360 Assert.That(storedObjects[0].Parts.Length, Is.EqualTo(1)); 367 Assert.AreEqual(1, storedObjects[0].Parts.Length);
361 Assert.That(storedObjects[0].ContainsPart(rootPartUuid)); 368 Assert.IsTrue(storedObjects[0].ContainsPart(rootPartUuid));
362 } 369 }
363 } 370 }
364} 371}
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectResizeTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectResizeTests.cs
index c264433..975c4d9 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectResizeTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectResizeTests.cs
@@ -30,10 +30,8 @@ using System.Reflection;
30using NUnit.Framework; 30using NUnit.Framework;
31using OpenMetaverse; 31using OpenMetaverse;
32using OpenSim.Framework; 32using OpenSim.Framework;
33using OpenSim.Framework.Communications;
34using OpenSim.Region.Framework.Scenes; 33using OpenSim.Region.Framework.Scenes;
35using OpenSim.Tests.Common; 34using OpenSim.Tests.Common;
36using OpenSim.Tests.Common.Mock;
37 35
38namespace OpenSim.Region.Framework.Scenes.Tests 36namespace OpenSim.Region.Framework.Scenes.Tests
39{ 37{
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectScriptTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectScriptTests.cs
index a58e735..8a2d2af 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectScriptTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectScriptTests.cs
@@ -31,11 +31,9 @@ using System.Reflection;
31using NUnit.Framework; 31using NUnit.Framework;
32using OpenMetaverse; 32using OpenMetaverse;
33using OpenSim.Framework; 33using OpenSim.Framework;
34using OpenSim.Framework.Communications;
35using OpenSim.Region.Framework.Interfaces; 34using OpenSim.Region.Framework.Interfaces;
36using OpenSim.Region.Framework.Scenes; 35using OpenSim.Region.Framework.Scenes;
37using OpenSim.Tests.Common; 36using OpenSim.Tests.Common;
38using OpenSim.Tests.Common.Mock;
39 37
40namespace OpenSim.Region.Framework.Scenes.Tests 38namespace OpenSim.Region.Framework.Scenes.Tests
41{ 39{
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectSerializationTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectSerializationTests.cs
new file mode 100644
index 0000000..e3ceb04
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectSerializationTests.cs
@@ -0,0 +1,135 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Threading;
32using System.Xml;
33using System.Linq;
34using Nini.Config;
35using NUnit.Framework;
36using OpenMetaverse;
37using OpenSim.Framework;
38using OpenSim.Framework.Serialization.External;
39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Region.Framework.Scenes.Serialization;
41using OpenSim.Services.Interfaces;
42using OpenSim.Tests.Common;
43
44namespace OpenSim.Region.Framework.Scenes.Tests
45{
46 /// <summary>
47 /// Basic scene object serialization tests.
48 /// </summary>
49 [TestFixture]
50 public class SceneObjectSerializationTests : OpenSimTestCase
51 {
52
53 /// <summary>
54 /// Serialize and deserialize.
55 /// </summary>
56 [Test]
57 public void TestSerialDeserial()
58 {
59 TestHelpers.InMethod();
60
61 Scene scene = new SceneHelpers().SetupScene();
62 int partsToTestCount = 3;
63
64 SceneObjectGroup so
65 = SceneHelpers.CreateSceneObject(partsToTestCount, TestHelpers.ParseTail(0x1), "obj1", 0x10);
66 SceneObjectPart[] parts = so.Parts;
67 so.Name = "obj1";
68 so.Description = "xpto";
69
70 string xml = SceneObjectSerializer.ToXml2Format(so);
71 Assert.That(!string.IsNullOrEmpty(xml), "SOG serialization resulted in empty or null string");
72
73 XmlDocument doc = new XmlDocument();
74 doc.LoadXml(xml);
75 XmlNodeList nodes = doc.GetElementsByTagName("SceneObjectPart");
76 Assert.That(nodes.Count, Is.EqualTo(3), "SOG serialization resulted in wrong number of SOPs");
77
78 SceneObjectGroup so2 = SceneObjectSerializer.FromXml2Format(xml);
79 Assert.IsNotNull(so2, "SOG deserialization resulted in null object");
80 Assert.That(so2.Name == so.Name, "Name of deserialized object does not match original name");
81 Assert.That(so2.Description == so.Description, "Description of deserialized object does not match original name");
82 }
83
84 /// <summary>
85 /// This checks for a bug reported in mantis #7514
86 /// </summary>
87 [Test]
88 public void TestNamespaceAttribute()
89 {
90 TestHelpers.InMethod();
91
92 Scene scene = new SceneHelpers().SetupScene();
93 UserAccount account = new UserAccount(UUID.Zero, UUID.Random(), "Test", "User", string.Empty);
94 scene.UserAccountService.StoreUserAccount(account);
95 int partsToTestCount = 1;
96
97 SceneObjectGroup so
98 = SceneHelpers.CreateSceneObject(partsToTestCount, TestHelpers.ParseTail(0x1), "obj1", 0x10);
99 SceneObjectPart[] parts = so.Parts;
100 so.Name = "obj1";
101 so.Description = "xpto";
102 so.OwnerID = account.PrincipalID;
103 so.RootPart.CreatorID = so.OwnerID;
104
105 string xml = SceneObjectSerializer.ToXml2Format(so);
106 Assert.That(!string.IsNullOrEmpty(xml), "SOG serialization resulted in empty or null string");
107
108 xml = ExternalRepresentationUtils.RewriteSOP(xml, "Test Scene", "http://localhost", scene.UserAccountService, UUID.Zero);
109 //Console.WriteLine(xml);
110
111 XmlDocument doc = new XmlDocument();
112 doc.LoadXml(xml);
113
114 XmlNodeList nodes = doc.GetElementsByTagName("SceneObjectPart");
115 Assert.That(nodes.Count, Is.GreaterThan(0), "SOG serialization resulted in no SOPs");
116 foreach (XmlAttribute a in nodes[0].Attributes)
117 {
118 int count = a.Name.Count(c => c == ':');
119 Assert.That(count, Is.EqualTo(1), "Cannot have multiple ':' in attribute name in SOP");
120 }
121 nodes = doc.GetElementsByTagName("CreatorData");
122 Assert.That(nodes.Count, Is.GreaterThan(0), "SOG serialization resulted in no CreatorData");
123 foreach (XmlAttribute a in nodes[0].Attributes)
124 {
125 int count = a.Name.Count(c => c == ':');
126 Assert.That(count, Is.EqualTo(1), "Cannot have multiple ':' in attribute name in CreatorData");
127 }
128
129 SceneObjectGroup so2 = SceneObjectSerializer.FromXml2Format(xml);
130 Assert.IsNotNull(so2, "SOG deserialization resulted in null object");
131 Assert.AreNotEqual(so.RootPart.CreatorIdentification, so2.RootPart.CreatorIdentification, "RewriteSOP failed to transform CreatorData.");
132 Assert.That(so2.RootPart.CreatorIdentification.Contains("http://"), "RewriteSOP failed to add the homeURL to CreatorData");
133 }
134 }
135} \ No newline at end of file
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectSpatialTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectSpatialTests.cs
index abaa1d1..e00defd 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectSpatialTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectSpatialTests.cs
@@ -31,10 +31,8 @@ using System.Threading;
31using NUnit.Framework; 31using NUnit.Framework;
32using OpenMetaverse; 32using OpenMetaverse;
33using OpenSim.Framework; 33using OpenSim.Framework;
34using OpenSim.Framework.Communications;
35using OpenSim.Region.Framework.Scenes; 34using OpenSim.Region.Framework.Scenes;
36using OpenSim.Tests.Common; 35using OpenSim.Tests.Common;
37using OpenSim.Tests.Common.Mock;
38 36
39namespace OpenSim.Region.Framework.Scenes.Tests 37namespace OpenSim.Region.Framework.Scenes.Tests
40{ 38{
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs
index 8eb3191..1737e3c 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs
@@ -31,10 +31,8 @@ using System.Reflection;
31using NUnit.Framework; 31using NUnit.Framework;
32using OpenMetaverse; 32using OpenMetaverse;
33using OpenSim.Framework; 33using OpenSim.Framework;
34using OpenSim.Framework.Communications;
35using OpenSim.Region.Framework.Scenes; 34using OpenSim.Region.Framework.Scenes;
36using OpenSim.Tests.Common; 35using OpenSim.Tests.Common;
37using OpenSim.Tests.Common.Mock;
38 36
39namespace OpenSim.Region.Framework.Scenes.Tests 37namespace OpenSim.Region.Framework.Scenes.Tests
40{ 38{
@@ -58,6 +56,25 @@ namespace OpenSim.Region.Framework.Scenes.Tests
58 } 56 }
59 57
60 [Test] 58 [Test]
59 public void TestSetTemporary()
60 {
61 TestHelpers.InMethod();
62
63 m_scene.AddSceneObject(m_so1);
64 m_so1.ScriptSetTemporaryStatus(true);
65
66 // Is this really the correct flag?
67 Assert.That(m_so1.RootPart.Flags, Is.EqualTo(PrimFlags.TemporaryOnRez));
68 Assert.That(m_so1.Backup, Is.False);
69
70 // Test setting back to non-temporary
71 m_so1.ScriptSetTemporaryStatus(false);
72
73 Assert.That(m_so1.RootPart.Flags, Is.EqualTo(PrimFlags.None));
74 Assert.That(m_so1.Backup, Is.True);
75 }
76
77 [Test]
61 public void TestSetPhantomSinglePrim() 78 public void TestSetPhantomSinglePrim()
62 { 79 {
63 TestHelpers.InMethod(); 80 TestHelpers.InMethod();
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectUndoRedoTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectUndoRedoTests.cs
index 96973de..af3ce8e 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectUndoRedoTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectUndoRedoTests.cs
@@ -30,10 +30,8 @@ using System.Reflection;
30using NUnit.Framework; 30using NUnit.Framework;
31using OpenMetaverse; 31using OpenMetaverse;
32using OpenSim.Framework; 32using OpenSim.Framework;
33using OpenSim.Framework.Communications;
34using OpenSim.Region.Framework.Scenes; 33using OpenSim.Region.Framework.Scenes;
35using OpenSim.Tests.Common; 34using OpenSim.Tests.Common;
36using OpenSim.Tests.Common.Mock;
37 35
38namespace OpenSim.Region.Framework.Scenes.Tests 36namespace OpenSim.Region.Framework.Scenes.Tests
39{ 37{
@@ -110,8 +108,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests
110 108
111 Vector3 firstSize = new Vector3(2, 3, 4); 109 Vector3 firstSize = new Vector3(2, 3, 4);
112 Vector3 secondSize = new Vector3(5, 6, 7); 110 Vector3 secondSize = new Vector3(5, 6, 7);
113 Vector3 thirdSize = new Vector3(8, 9, 10); 111// Vector3 thirdSize = new Vector3(8, 9, 10);
114 Vector3 fourthSize = new Vector3(11, 12, 13); 112// Vector3 fourthSize = new Vector3(11, 12, 13);
115 113
116 Scene scene = new SceneHelpers().SetupScene(); 114 Scene scene = new SceneHelpers().SetupScene();
117 scene.MaxUndoCount = 20; 115 scene.MaxUndoCount = 20;
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectUserGroupTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectUserGroupTests.cs
index 2b79271..aadf7c6 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectUserGroupTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectUserGroupTests.cs
@@ -32,14 +32,12 @@ using Nini.Config;
32using NUnit.Framework; 32using NUnit.Framework;
33using OpenMetaverse; 33using OpenMetaverse;
34using OpenSim.Framework; 34using OpenSim.Framework;
35using OpenSim.Framework.Communications;
36using OpenSim.Region.CoreModules.Avatar.InstantMessage; 35using OpenSim.Region.CoreModules.Avatar.InstantMessage;
37using OpenSim.Region.CoreModules.World.Permissions; 36using OpenSim.Region.CoreModules.World.Permissions;
38using OpenSim.Region.Framework.Interfaces; 37using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes; 38using OpenSim.Region.Framework.Scenes;
40using OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups; 39using OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups;
41using OpenSim.Tests.Common; 40using OpenSim.Tests.Common;
42using OpenSim.Tests.Common.Mock;
43 41
44namespace OpenSim.Region.Framework.Scenes.Tests 42namespace OpenSim.Region.Framework.Scenes.Tests
45{ 43{
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs
index 5faf131..96d112d 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs
@@ -36,7 +36,6 @@ using Nini.Config;
36using NUnit.Framework; 36using NUnit.Framework;
37using OpenMetaverse; 37using OpenMetaverse;
38using OpenSim.Framework; 38using OpenSim.Framework;
39using OpenSim.Framework.Communications;
40using OpenSim.Region.Framework.Scenes; 39using OpenSim.Region.Framework.Scenes;
41using OpenSim.Region.Framework.Interfaces; 40using OpenSim.Region.Framework.Interfaces;
42using OpenSim.Region.ClientStack.Linden; 41using OpenSim.Region.ClientStack.Linden;
@@ -44,7 +43,6 @@ using OpenSim.Region.CoreModules.Framework.EntityTransfer;
44using OpenSim.Region.CoreModules.World.Serialiser; 43using OpenSim.Region.CoreModules.World.Serialiser;
45using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; 44using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation;
46using OpenSim.Tests.Common; 45using OpenSim.Tests.Common;
47using OpenSim.Tests.Common.Mock;
48using GridRegion = OpenSim.Services.Interfaces.GridRegion; 46using GridRegion = OpenSim.Services.Interfaces.GridRegion;
49 47
50namespace OpenSim.Region.Framework.Scenes.Tests 48namespace OpenSim.Region.Framework.Scenes.Tests
@@ -111,6 +109,45 @@ namespace OpenSim.Region.Framework.Scenes.Tests
111 Assert.That(scene.GetScenePresences().Count, Is.EqualTo(1)); 109 Assert.That(scene.GetScenePresences().Count, Is.EqualTo(1));
112 } 110 }
113 111
112 /// <summary>
113 /// Test that duplicate complete movement calls are ignored.
114 /// </summary>
115 /// <remarks>
116 /// If duplicate calls are not ignored then there is a risk of race conditions or other unexpected effects.
117 /// </remarks>
118 [Test]
119 public void TestDupeCompleteMovementCalls()
120 {
121 TestHelpers.InMethod();
122// TestHelpers.EnableLogging();
123
124 UUID spUuid = TestHelpers.ParseTail(0x1);
125
126 TestScene scene = new SceneHelpers().SetupScene();
127
128 int makeRootAgentEvents = 0;
129 scene.EventManager.OnMakeRootAgent += spi => makeRootAgentEvents++;
130
131 ScenePresence sp = SceneHelpers.AddScenePresence(scene, spUuid);
132
133 Assert.That(makeRootAgentEvents, Is.EqualTo(1));
134
135 // Normally these would be invoked by a CompleteMovement message coming in to the UDP stack. But for
136 // convenience, here we will invoke it manually.
137 sp.CompleteMovement(sp.ControllingClient, true);
138
139 Assert.That(makeRootAgentEvents, Is.EqualTo(1));
140
141 // Check rest of exepcted parameters.
142 Assert.That(scene.AuthenticateHandler.GetAgentCircuitData(spUuid), Is.Not.Null);
143 Assert.That(scene.AuthenticateHandler.GetAgentCircuits().Count, Is.EqualTo(1));
144
145 Assert.That(sp.IsChildAgent, Is.False);
146 Assert.That(sp.UUID, Is.EqualTo(spUuid));
147
148 Assert.That(scene.GetScenePresences().Count, Is.EqualTo(1));
149 }
150
114 [Test] 151 [Test]
115 public void TestCreateDuplicateRootScenePresence() 152 public void TestCreateDuplicateRootScenePresence()
116 { 153 {
@@ -119,7 +156,20 @@ namespace OpenSim.Region.Framework.Scenes.Tests
119 156
120 UUID spUuid = TestHelpers.ParseTail(0x1); 157 UUID spUuid = TestHelpers.ParseTail(0x1);
121 158
159 // The etm is only invoked by this test to check whether an agent is still in transit if there is a dupe
160 EntityTransferModule etm = new EntityTransferModule();
161
162 IConfigSource config = new IniConfigSource();
163 IConfig modulesConfig = config.AddConfig("Modules");
164 modulesConfig.Set("EntityTransferModule", etm.Name);
165 IConfig entityTransferConfig = config.AddConfig("EntityTransfer");
166
167 // In order to run a single threaded regression test we do not want the entity transfer module waiting
168 // for a callback from the destination scene before removing its avatar data.
169 entityTransferConfig.Set("wait_for_callback", false);
170
122 TestScene scene = new SceneHelpers().SetupScene(); 171 TestScene scene = new SceneHelpers().SetupScene();
172 SceneHelpers.SetupSceneModules(scene, config, etm);
123 SceneHelpers.AddScenePresence(scene, spUuid); 173 SceneHelpers.AddScenePresence(scene, spUuid);
124 SceneHelpers.AddScenePresence(scene, spUuid); 174 SceneHelpers.AddScenePresence(scene, spUuid);
125 175
@@ -133,7 +183,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
133 } 183 }
134 184
135 [Test] 185 [Test]
136 public void TestCloseAgent() 186 public void TestCloseClient()
137 { 187 {
138 TestHelpers.InMethod(); 188 TestHelpers.InMethod();
139// TestHelpers.EnableLogging(); 189// TestHelpers.EnableLogging();
@@ -141,7 +191,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
141 TestScene scene = new SceneHelpers().SetupScene(); 191 TestScene scene = new SceneHelpers().SetupScene();
142 ScenePresence sp = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseTail(0x1)); 192 ScenePresence sp = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseTail(0x1));
143 193
144 scene.IncomingCloseAgent(sp.UUID, false); 194 scene.CloseAgent(sp.UUID, false);
145 195
146 Assert.That(scene.GetScenePresence(sp.UUID), Is.Null); 196 Assert.That(scene.GetScenePresence(sp.UUID), Is.Null);
147 Assert.That(scene.AuthenticateHandler.GetAgentCircuitData(sp.UUID), Is.Null); 197 Assert.That(scene.AuthenticateHandler.GetAgentCircuitData(sp.UUID), Is.Null);
@@ -176,7 +226,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
176 // *** This is the first stage, when a neighbouring region is told that a viewer is about to try and 226 // *** This is the first stage, when a neighbouring region is told that a viewer is about to try and
177 // establish a child scene presence. We pass in the circuit code that the client has to connect with *** 227 // establish a child scene presence. We pass in the circuit code that the client has to connect with ***
178 // XXX: ViaLogin may not be correct here. 228 // XXX: ViaLogin may not be correct here.
179 scene.SimulationService.CreateAgent(region, acd, (uint)TeleportFlags.ViaLogin, out reason); 229 scene.SimulationService.CreateAgent(null, region, acd, (uint)TeleportFlags.ViaLogin, out reason);
180 230
181 Assert.That(scene.AuthenticateHandler.GetAgentCircuitData(agentId), Is.Not.Null); 231 Assert.That(scene.AuthenticateHandler.GetAgentCircuitData(agentId), Is.Not.Null);
182 Assert.That(scene.AuthenticateHandler.GetAgentCircuits().Count, Is.EqualTo(1)); 232 Assert.That(scene.AuthenticateHandler.GetAgentCircuits().Count, Is.EqualTo(1));
@@ -187,7 +237,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
187 // *** This is the second stage, where the client established a child agent/scene presence using the 237 // *** This is the second stage, where the client established a child agent/scene presence using the
188 // circuit code given to the scene in stage 1 *** 238 // circuit code given to the scene in stage 1 ***
189 TestClient client = new TestClient(acd, scene); 239 TestClient client = new TestClient(acd, scene);
190 scene.AddNewClient(client, PresenceType.User); 240 scene.AddNewAgent(client, PresenceType.User);
191 241
192 Assert.That(scene.AuthenticateHandler.GetAgentCircuitData(agentId), Is.Not.Null); 242 Assert.That(scene.AuthenticateHandler.GetAgentCircuitData(agentId), Is.Not.Null);
193 Assert.That(scene.AuthenticateHandler.GetAgentCircuits().Count, Is.EqualTo(1)); 243 Assert.That(scene.AuthenticateHandler.GetAgentCircuits().Count, Is.EqualTo(1));
@@ -236,161 +286,5 @@ namespace OpenSim.Region.Framework.Scenes.Tests
236// Assert.That(childPresence, Is.Not.Null); 286// Assert.That(childPresence, Is.Not.Null);
237// Assert.That(childPresence.IsChildAgent, Is.True); 287// Assert.That(childPresence.IsChildAgent, Is.True);
238 } 288 }
239
240// /// <summary>
241// /// Test adding a root agent to a scene. Doesn't yet actually complete crossing the agent into the scene.
242// /// </summary>
243// [Test]
244// public void T010_TestAddRootAgent()
245// {
246// TestHelpers.InMethod();
247//
248// string firstName = "testfirstname";
249//
250// AgentCircuitData agent = new AgentCircuitData();
251// agent.AgentID = agent1;
252// agent.firstname = firstName;
253// agent.lastname = "testlastname";
254// agent.SessionID = UUID.Random();
255// agent.SecureSessionID = UUID.Random();
256// agent.circuitcode = 123;
257// agent.BaseFolder = UUID.Zero;
258// agent.InventoryFolder = UUID.Zero;
259// agent.startpos = Vector3.Zero;
260// agent.CapsPath = GetRandomCapsObjectPath();
261// agent.ChildrenCapSeeds = new Dictionary<ulong, string>();
262// agent.child = true;
263//
264// scene.PresenceService.LoginAgent(agent.AgentID.ToString(), agent.SessionID, agent.SecureSessionID);
265//
266// string reason;
267// scene.NewUserConnection(agent, (uint)TeleportFlags.ViaLogin, out reason);
268// testclient = new TestClient(agent, scene);
269// scene.AddNewClient(testclient);
270//
271// ScenePresence presence = scene.GetScenePresence(agent1);
272//
273// Assert.That(presence, Is.Not.Null, "presence is null");
274// Assert.That(presence.Firstname, Is.EqualTo(firstName), "First name not same");
275// acd1 = agent;
276// }
277//
278// /// <summary>
279// /// Test removing an uncrossed root agent from a scene.
280// /// </summary>
281// [Test]
282// public void T011_TestRemoveRootAgent()
283// {
284// TestHelpers.InMethod();
285//
286// scene.RemoveClient(agent1);
287//
288// ScenePresence presence = scene.GetScenePresence(agent1);
289//
290// Assert.That(presence, Is.Null, "presence is not null");
291// }
292
293 // I'm commenting this test because it does not represent
294 // crossings. The Thread.Sleep's in here are not meaningful mocks,
295 // and they sometimes fail in panda.
296 // We need to talk in order to develop a test
297 // that really tests region crossings. There are 3 async components,
298 // but things are synchronous among them. So there should be
299 // 3 threads in here.
300 //[Test]
301// public void T021_TestCrossToNewRegion()
302// {
303// TestHelpers.InMethod();
304//
305// scene.RegisterRegionWithGrid();
306// scene2.RegisterRegionWithGrid();
307//
308// // Adding child agent to region 1001
309// string reason;
310// scene2.NewUserConnection(acd1,0, out reason);
311// scene2.AddNewClient(testclient, PresenceType.User);
312//
313// ScenePresence presence = scene.GetScenePresence(agent1);
314// presence.MakeRootAgent(new Vector3(0,unchecked(Constants.RegionSize-1),0), true);
315//
316// ScenePresence presence2 = scene2.GetScenePresence(agent1);
317//
318// // Adding neighbour region caps info to presence2
319//
320// string cap = presence.ControllingClient.RequestClientInfo().CapsPath;
321// presence2.AddNeighbourRegion(region1, cap);
322//
323// Assert.That(presence.IsChildAgent, Is.False, "Did not start root in origin region.");
324// Assert.That(presence2.IsChildAgent, Is.True, "Is not a child on destination region.");
325//
326// // Cross to x+1
327// presence.AbsolutePosition = new Vector3(Constants.RegionSize+1,3,100);
328// presence.Update();
329//
330// EventWaitHandle wh = new EventWaitHandle (false, EventResetMode.AutoReset, "Crossing");
331//
332// // Mimicking communication between client and server, by waiting OK from client
333// // sent by TestClient.CrossRegion call. Originally, this is network comm.
334// if (!wh.WaitOne(5000,false))
335// {
336// presence.Update();
337// if (!wh.WaitOne(8000,false))
338// throw new ArgumentException("1 - Timeout waiting for signal/variable.");
339// }
340//
341// // This is a TestClient specific method that fires OnCompleteMovementToRegion event, which
342// // would normally be fired after receiving the reply packet from comm. done on the last line.
343// testclient.CompleteMovement();
344//
345// // Crossings are asynchronous
346// int timer = 10;
347//
348// // Make sure cross hasn't already finished
349// if (!presence.IsInTransit && !presence.IsChildAgent)
350// {
351// // If not and not in transit yet, give it some more time
352// Thread.Sleep(5000);
353// }
354//
355// // Enough time, should at least be in transit by now.
356// while (presence.IsInTransit && timer > 0)
357// {
358// Thread.Sleep(1000);
359// timer-=1;
360// }
361//
362// Assert.That(timer,Is.GreaterThan(0),"Timed out waiting to cross 2->1.");
363// Assert.That(presence.IsChildAgent, Is.True, "Did not complete region cross as expected.");
364// Assert.That(presence2.IsChildAgent, Is.False, "Did not receive root status after receiving agent.");
365//
366// // Cross Back
367// presence2.AbsolutePosition = new Vector3(-10, 3, 100);
368// presence2.Update();
369//
370// if (!wh.WaitOne(5000,false))
371// {
372// presence2.Update();
373// if (!wh.WaitOne(8000,false))
374// throw new ArgumentException("2 - Timeout waiting for signal/variable.");
375// }
376// testclient.CompleteMovement();
377//
378// if (!presence2.IsInTransit && !presence2.IsChildAgent)
379// {
380// // If not and not in transit yet, give it some more time
381// Thread.Sleep(5000);
382// }
383//
384// // Enough time, should at least be in transit by now.
385// while (presence2.IsInTransit && timer > 0)
386// {
387// Thread.Sleep(1000);
388// timer-=1;
389// }
390//
391// Assert.That(timer,Is.GreaterThan(0),"Timed out waiting to cross 1->2.");
392// Assert.That(presence2.IsChildAgent, Is.True, "Did not return from region as expected.");
393// Assert.That(presence.IsChildAgent, Is.False, "Presence was not made root in old region again.");
394// }
395 } 289 }
396} \ No newline at end of file 290} \ No newline at end of file
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAnimationTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAnimationTests.cs
index 1cd8ae9..42d91b9 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAnimationTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAnimationTests.cs
@@ -35,15 +35,13 @@ using Nini.Config;
35using NUnit.Framework; 35using NUnit.Framework;
36using OpenMetaverse; 36using OpenMetaverse;
37using OpenSim.Framework; 37using OpenSim.Framework;
38using OpenSim.Framework.Communications;
39using OpenSim.Region.Framework.Scenes; 38using OpenSim.Region.Framework.Scenes;
40using OpenSim.Region.Framework.Interfaces; 39using OpenSim.Region.Framework.Interfaces;
41using OpenSim.Region.CoreModules.Framework.EntityTransfer; 40using OpenSim.Region.CoreModules.Framework.EntityTransfer;
42using OpenSim.Region.CoreModules.World.Serialiser; 41using OpenSim.Region.CoreModules.World.Serialiser;
43using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; 42using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation;
44using OpenSim.Region.Physics.Manager; 43using OpenSim.Region.PhysicsModules.SharedBase;
45using OpenSim.Tests.Common; 44using OpenSim.Tests.Common;
46using OpenSim.Tests.Common.Mock;
47 45
48namespace OpenSim.Region.Framework.Scenes.Tests 46namespace OpenSim.Region.Framework.Scenes.Tests
49{ 47{
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAutopilotTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAutopilotTests.cs
index d80afd3..e5c847e 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAutopilotTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAutopilotTests.cs
@@ -33,11 +33,9 @@ using Nini.Config;
33using NUnit.Framework; 33using NUnit.Framework;
34using OpenMetaverse; 34using OpenMetaverse;
35using OpenSim.Framework; 35using OpenSim.Framework;
36using OpenSim.Framework.Communications;
37using OpenSim.Region.Framework.Interfaces; 36using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Region.Framework.Scenes; 37using OpenSim.Region.Framework.Scenes;
39using OpenSim.Tests.Common; 38using OpenSim.Tests.Common;
40using OpenSim.Tests.Common.Mock;
41 39
42namespace OpenSim.Region.Framework.Scenes.Tests 40namespace OpenSim.Region.Framework.Scenes.Tests
43{ 41{
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCapabilityTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCapabilityTests.cs
new file mode 100644
index 0000000..2e6dc70
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCapabilityTests.cs
@@ -0,0 +1,86 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Text;
32using System.Threading;
33using System.Timers;
34using Timer = System.Timers.Timer;
35using Nini.Config;
36using NUnit.Framework;
37using OpenMetaverse;
38using OpenSim.Framework;
39using OpenSim.Framework.Servers;
40using OpenSim.Framework.Servers.HttpServer;
41using OpenSim.Region.ClientStack.Linden;
42using OpenSim.Region.CoreModules.Framework;
43using OpenSim.Region.CoreModules.Framework.EntityTransfer;
44using OpenSim.Region.CoreModules.World.Serialiser;
45using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation;
46using OpenSim.Region.Framework.Scenes;
47using OpenSim.Region.Framework.Interfaces;
48using OpenSim.Tests.Common;
49using GridRegion = OpenSim.Services.Interfaces.GridRegion;
50
51namespace OpenSim.Region.Framework.Scenes.Tests
52{
53 [TestFixture]
54 public class ScenePresenceCapabilityTests : OpenSimTestCase
55 {
56 [Test]
57 public void TestChildAgentSingleRegionCapabilities()
58 {
59 TestHelpers.InMethod();
60// TestHelpers.EnableLogging();
61
62 UUID spUuid = TestHelpers.ParseTail(0x1);
63
64 // XXX: This is not great since the use of statics will mean that this has to be manually cleaned up for
65 // any subsequent test.
66 // XXX: May replace with a mock IHttpServer later.
67 BaseHttpServer httpServer = new BaseHttpServer(99999);
68 MainServer.AddHttpServer(httpServer);
69 MainServer.Instance = httpServer;
70
71 CapabilitiesModule capsMod = new CapabilitiesModule();
72 TestScene scene = new SceneHelpers().SetupScene();
73 SceneHelpers.SetupSceneModules(scene, capsMod);
74
75 ScenePresence sp = SceneHelpers.AddChildScenePresence(scene, spUuid);
76 Assert.That(capsMod.GetCapsForUser(spUuid), Is.Not.Null);
77
78 // TODO: Need to add tests for other ICapabiltiesModule methods.
79
80 scene.CloseAgent(sp.UUID, false);
81 Assert.That(capsMod.GetCapsForUser(spUuid), Is.Null);
82
83 // TODO: Need to add tests for other ICapabiltiesModule methods.
84 }
85 }
86} \ No newline at end of file
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs
new file mode 100644
index 0000000..7127644
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs
@@ -0,0 +1,247 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using Nini.Config;
32using NUnit.Framework;
33using OpenMetaverse;
34using OpenSim.Framework;
35using OpenSim.Framework.Servers;
36using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Region.CoreModules.Framework;
38using OpenSim.Region.CoreModules.Framework.EntityTransfer;
39using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation;
40using OpenSim.Region.CoreModules.World.Permissions;
41using OpenSim.Tests.Common;
42
43namespace OpenSim.Region.Framework.Scenes.Tests
44{
45 [TestFixture]
46 public class ScenePresenceCrossingTests : OpenSimTestCase
47 {
48 [TestFixtureSetUp]
49 public void FixtureInit()
50 {
51 // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
52 Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest;
53 }
54
55 [TestFixtureTearDown]
56 public void TearDown()
57 {
58 // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
59 // threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression
60 // tests really shouldn't).
61 Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
62 }
63
64 [Test]
65 public void TestCrossOnSameSimulator()
66 {
67 TestHelpers.InMethod();
68// TestHelpers.EnableLogging();
69
70 UUID userId = TestHelpers.ParseTail(0x1);
71
72// TestEventQueueGetModule eqmA = new TestEventQueueGetModule();
73 EntityTransferModule etmA = new EntityTransferModule();
74 EntityTransferModule etmB = new EntityTransferModule();
75 LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule();
76
77 IConfigSource config = new IniConfigSource();
78 IConfig modulesConfig = config.AddConfig("Modules");
79 modulesConfig.Set("EntityTransferModule", etmA.Name);
80 modulesConfig.Set("SimulationServices", lscm.Name);
81// IConfig entityTransferConfig = config.AddConfig("EntityTransfer");
82
83 // In order to run a single threaded regression test we do not want the entity transfer module waiting
84 // for a callback from the destination scene before removing its avatar data.
85// entityTransferConfig.Set("wait_for_callback", false);
86
87 SceneHelpers sh = new SceneHelpers();
88 TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000);
89 TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1000, 999);
90
91 SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm);
92 SceneHelpers.SetupSceneModules(sceneA, config, new CapabilitiesModule(), etmA);
93// SceneHelpers.SetupSceneModules(sceneA, config, new CapabilitiesModule(), etmA, eqmA);
94 SceneHelpers.SetupSceneModules(sceneB, config, new CapabilitiesModule(), etmB);
95
96 AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId);
97 TestClient tc = new TestClient(acd, sceneA);
98 List<TestClient> destinationTestClients = new List<TestClient>();
99 EntityTransferHelpers.SetupInformClientOfNeighbourTriggersNeighbourClientCreate(tc, destinationTestClients);
100
101 ScenePresence originalSp = SceneHelpers.AddScenePresence(sceneA, tc, acd);
102 originalSp.AbsolutePosition = new Vector3(128, 32, 10);
103
104// originalSp.Flying = true;
105
106// Console.WriteLine("First pos {0}", originalSp.AbsolutePosition);
107
108// eqmA.ClearEvents();
109
110 AgentUpdateArgs moveArgs = new AgentUpdateArgs();
111 //moveArgs.BodyRotation = Quaternion.CreateFromEulers(Vector3.Zero);
112 moveArgs.BodyRotation = Quaternion.CreateFromEulers(new Vector3(0, 0, (float)-(Math.PI / 2)));
113 moveArgs.ControlFlags = (uint)AgentManager.ControlFlags.AGENT_CONTROL_AT_POS;
114 moveArgs.SessionID = acd.SessionID;
115
116 originalSp.HandleAgentUpdate(originalSp.ControllingClient, moveArgs);
117
118 sceneA.Update(1);
119
120// Console.WriteLine("Second pos {0}", originalSp.AbsolutePosition);
121
122 // FIXME: This is a sufficient number of updates to for the presence to reach the northern border.
123 // But really we want to do this in a more robust way.
124 for (int i = 0; i < 100; i++)
125 {
126 sceneA.Update(1);
127// Console.WriteLine("Pos {0}", originalSp.AbsolutePosition);
128 }
129
130 // Need to sort processing of EnableSimulator message on adding scene presences before we can test eqm
131 // messages
132// Dictionary<UUID, List<TestEventQueueGetModule.Event>> eqmEvents = eqmA.Events;
133//
134// Assert.That(eqmEvents.Count, Is.EqualTo(1));
135// Assert.That(eqmEvents.ContainsKey(originalSp.UUID), Is.True);
136//
137// List<TestEventQueueGetModule.Event> spEqmEvents = eqmEvents[originalSp.UUID];
138//
139// Assert.That(spEqmEvents.Count, Is.EqualTo(1));
140// Assert.That(spEqmEvents[0].Name, Is.EqualTo("CrossRegion"));
141
142 // sceneA should now only have a child agent
143 ScenePresence spAfterCrossSceneA = sceneA.GetScenePresence(originalSp.UUID);
144 Assert.That(spAfterCrossSceneA.IsChildAgent, Is.True);
145
146 ScenePresence spAfterCrossSceneB = sceneB.GetScenePresence(originalSp.UUID);
147
148 // Agent remains a child until the client triggers complete movement
149 Assert.That(spAfterCrossSceneB.IsChildAgent, Is.True);
150
151 TestClient sceneBTc = ((TestClient)spAfterCrossSceneB.ControllingClient);
152
153 int agentMovementCompleteReceived = 0;
154 sceneBTc.OnReceivedMoveAgentIntoRegion += (ri, pos, look) => agentMovementCompleteReceived++;
155
156 sceneBTc.CompleteMovement();
157
158 Assert.That(agentMovementCompleteReceived, Is.EqualTo(1));
159 Assert.That(spAfterCrossSceneB.IsChildAgent, Is.False);
160 }
161
162 /// <summary>
163 /// Test a cross attempt where the user can see into the neighbour but does not have permission to become
164 /// root there.
165 /// </summary>
166 [Test]
167 public void TestCrossOnSameSimulatorNoRootDestPerm()
168 {
169 TestHelpers.InMethod();
170// TestHelpers.EnableLogging();
171
172 UUID userId = TestHelpers.ParseTail(0x1);
173
174 EntityTransferModule etmA = new EntityTransferModule();
175 EntityTransferModule etmB = new EntityTransferModule();
176 LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule();
177
178 IConfigSource config = new IniConfigSource();
179 IConfig modulesConfig = config.AddConfig("Modules");
180 modulesConfig.Set("EntityTransferModule", etmA.Name);
181 modulesConfig.Set("SimulationServices", lscm.Name);
182
183 SceneHelpers sh = new SceneHelpers();
184 TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000);
185 TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1000, 999);
186
187 SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm);
188 SceneHelpers.SetupSceneModules(sceneA, config, new CapabilitiesModule(), etmA);
189
190 // We need to set up the permisions module on scene B so that our later use of agent limit to deny
191 // QueryAccess won't succeed anyway because administrators are always allowed in and the default
192 // IsAdministrator if no permissions module is present is true.
193 SceneHelpers.SetupSceneModules(sceneB, config, new CapabilitiesModule(), new PermissionsModule(), etmB);
194
195 AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId);
196 TestClient tc = new TestClient(acd, sceneA);
197 List<TestClient> destinationTestClients = new List<TestClient>();
198 EntityTransferHelpers.SetupInformClientOfNeighbourTriggersNeighbourClientCreate(tc, destinationTestClients);
199
200 // Make sure sceneB will not accept this avatar.
201 sceneB.RegionInfo.EstateSettings.PublicAccess = false;
202
203 ScenePresence originalSp = SceneHelpers.AddScenePresence(sceneA, tc, acd);
204 originalSp.AbsolutePosition = new Vector3(128, 32, 10);
205
206 AgentUpdateArgs moveArgs = new AgentUpdateArgs();
207 //moveArgs.BodyRotation = Quaternion.CreateFromEulers(Vector3.Zero);
208 moveArgs.BodyRotation = Quaternion.CreateFromEulers(new Vector3(0, 0, (float)-(Math.PI / 2)));
209 moveArgs.ControlFlags = (uint)AgentManager.ControlFlags.AGENT_CONTROL_AT_POS;
210 moveArgs.SessionID = acd.SessionID;
211
212 originalSp.HandleAgentUpdate(originalSp.ControllingClient, moveArgs);
213
214 sceneA.Update(1);
215
216// Console.WriteLine("Second pos {0}", originalSp.AbsolutePosition);
217
218 // FIXME: This is a sufficient number of updates to for the presence to reach the northern border.
219 // But really we want to do this in a more robust way.
220 for (int i = 0; i < 100; i++)
221 {
222 sceneA.Update(1);
223// Console.WriteLine("Pos {0}", originalSp.AbsolutePosition);
224 }
225
226 // sceneA agent should still be root
227 ScenePresence spAfterCrossSceneA = sceneA.GetScenePresence(originalSp.UUID);
228 Assert.That(spAfterCrossSceneA.IsChildAgent, Is.False);
229
230 ScenePresence spAfterCrossSceneB = sceneB.GetScenePresence(originalSp.UUID);
231
232 // sceneB agent should also still be root
233 Assert.That(spAfterCrossSceneB.IsChildAgent, Is.True);
234
235 // sceneB should ignore unauthorized attempt to upgrade agent to root
236 TestClient sceneBTc = ((TestClient)spAfterCrossSceneB.ControllingClient);
237
238 int agentMovementCompleteReceived = 0;
239 sceneBTc.OnReceivedMoveAgentIntoRegion += (ri, pos, look) => agentMovementCompleteReceived++;
240
241 sceneBTc.CompleteMovement();
242
243 Assert.That(agentMovementCompleteReceived, Is.EqualTo(0));
244 Assert.That(spAfterCrossSceneB.IsChildAgent, Is.True);
245 }
246 }
247} \ No newline at end of file
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceSitTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceSitTests.cs
index acaeb90..b232a44 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceSitTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceSitTests.cs
@@ -32,12 +32,10 @@ using Nini.Config;
32using NUnit.Framework; 32using NUnit.Framework;
33using OpenMetaverse; 33using OpenMetaverse;
34using OpenSim.Framework; 34using OpenSim.Framework;
35using OpenSim.Framework.Communications;
36using OpenSim.Framework.Servers; 35using OpenSim.Framework.Servers;
37using OpenSim.Region.Framework.Interfaces; 36using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; 37using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation;
39using OpenSim.Tests.Common; 38using OpenSim.Tests.Common;
40using OpenSim.Tests.Common.Mock;
41using System.Threading; 39using System.Threading;
42 40
43namespace OpenSim.Region.Framework.Scenes.Tests 41namespace OpenSim.Region.Framework.Scenes.Tests
@@ -73,6 +71,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
73 Assert.That(part.GetSittingAvatarsCount(), Is.EqualTo(0)); 71 Assert.That(part.GetSittingAvatarsCount(), Is.EqualTo(0));
74 Assert.That(part.GetSittingAvatars(), Is.Null); 72 Assert.That(part.GetSittingAvatars(), Is.Null);
75 Assert.That(m_sp.ParentID, Is.EqualTo(0)); 73 Assert.That(m_sp.ParentID, Is.EqualTo(0));
74 Assert.AreEqual(startPos, m_sp.AbsolutePosition);
76 } 75 }
77 76
78 [Test] 77 [Test]
@@ -87,15 +86,21 @@ namespace OpenSim.Region.Framework.Scenes.Tests
87 86
88 SceneObjectPart part = SceneHelpers.AddSceneObject(m_scene).RootPart; 87 SceneObjectPart part = SceneHelpers.AddSceneObject(m_scene).RootPart;
89 88
89 // We need to preserve this here because phys actor is removed by the sit.
90 Vector3 spPhysActorSize = m_sp.PhysicsActor.Size;
90 m_sp.HandleAgentRequestSit(m_sp.ControllingClient, m_sp.UUID, part.UUID, Vector3.Zero); 91 m_sp.HandleAgentRequestSit(m_sp.ControllingClient, m_sp.UUID, part.UUID, Vector3.Zero);
91 92
92 Assert.That(m_sp.PhysicsActor, Is.Null); 93 Assert.That(m_sp.PhysicsActor, Is.Null);
93 94
95 Assert.That(
96 m_sp.AbsolutePosition,
97 Is.EqualTo(part.AbsolutePosition + new Vector3(0, 0, spPhysActorSize.Z / 2)));
98
94 Assert.That(part.SitTargetAvatar, Is.EqualTo(UUID.Zero)); 99 Assert.That(part.SitTargetAvatar, Is.EqualTo(UUID.Zero));
95 Assert.That(part.GetSittingAvatarsCount(), Is.EqualTo(1)); 100 Assert.That(part.GetSittingAvatarsCount(), Is.EqualTo(1));
96 HashSet<UUID> sittingAvatars = part.GetSittingAvatars(); 101 HashSet<ScenePresence> sittingAvatars = part.GetSittingAvatars();
97 Assert.That(sittingAvatars.Count, Is.EqualTo(1)); 102 Assert.That(sittingAvatars.Count, Is.EqualTo(1));
98 Assert.That(sittingAvatars.Contains(m_sp.UUID)); 103 Assert.That(sittingAvatars.Contains(m_sp));
99 Assert.That(m_sp.ParentID, Is.EqualTo(part.LocalId)); 104 Assert.That(m_sp.ParentID, Is.EqualTo(part.LocalId));
100 } 105 }
101 106
@@ -111,15 +116,43 @@ namespace OpenSim.Region.Framework.Scenes.Tests
111 116
112 SceneObjectPart part = SceneHelpers.AddSceneObject(m_scene).RootPart; 117 SceneObjectPart part = SceneHelpers.AddSceneObject(m_scene).RootPart;
113 118
119 // We need to preserve this here because phys actor is removed by the sit.
120 Vector3 spPhysActorSize = m_sp.PhysicsActor.Size;
121 m_sp.HandleAgentRequestSit(m_sp.ControllingClient, m_sp.UUID, part.UUID, Vector3.Zero);
122
123 Assert.That(
124 m_sp.AbsolutePosition,
125 Is.EqualTo(part.AbsolutePosition + new Vector3(0, 0, spPhysActorSize.Z / 2)));
126
127 m_sp.StandUp();
128
129 Assert.That(part.SitTargetAvatar, Is.EqualTo(UUID.Zero));
130 Assert.That(part.GetSittingAvatarsCount(), Is.EqualTo(0));
131 Assert.That(part.GetSittingAvatars(), Is.Null);
132 Assert.That(m_sp.ParentID, Is.EqualTo(0));
133 Assert.That(m_sp.PhysicsActor, Is.Not.Null);
134 }
135
136 [Test]
137 public void TestSitAndStandWithNoSitTargetChildPrim()
138 {
139 TestHelpers.InMethod();
140// log4net.Config.XmlConfigurator.Configure();
141
142 // Make sure we're within range to sit
143 Vector3 startPos = new Vector3(1, 1, 1);
144 m_sp.AbsolutePosition = startPos;
145
146 SceneObjectPart part = SceneHelpers.AddSceneObject(m_scene, 2, m_sp.UUID, "part", 0x10).Parts[1];
147 part.OffsetPosition = new Vector3(2, 3, 4);
148
149 // We need to preserve this here because phys actor is removed by the sit.
150 Vector3 spPhysActorSize = m_sp.PhysicsActor.Size;
114 m_sp.HandleAgentRequestSit(m_sp.ControllingClient, m_sp.UUID, part.UUID, Vector3.Zero); 151 m_sp.HandleAgentRequestSit(m_sp.ControllingClient, m_sp.UUID, part.UUID, Vector3.Zero);
115 152
116 // FIXME: This is different for live avatars - z position is adjusted. This is half the height of the
117 // default avatar.
118 // Curiously, Vector3.ToString() will not display the last two places of the float. For example,
119 // printing out npc.AbsolutePosition will give <0, 0, 0.8454993> not <0, 0, 0.845499337>
120 Assert.That( 153 Assert.That(
121 m_sp.AbsolutePosition, 154 m_sp.AbsolutePosition,
122 Is.EqualTo(part.AbsolutePosition + new Vector3(0, 0, 0.845499337f))); 155 Is.EqualTo(part.AbsolutePosition + new Vector3(0, 0, spPhysActorSize.Z / 2)));
123 156
124 m_sp.StandUp(); 157 m_sp.StandUp();
125 158
@@ -147,15 +180,39 @@ namespace OpenSim.Region.Framework.Scenes.Tests
147 180
148 Assert.That(part.SitTargetAvatar, Is.EqualTo(m_sp.UUID)); 181 Assert.That(part.SitTargetAvatar, Is.EqualTo(m_sp.UUID));
149 Assert.That(m_sp.ParentID, Is.EqualTo(part.LocalId)); 182 Assert.That(m_sp.ParentID, Is.EqualTo(part.LocalId));
183
184 // This section is copied from ScenePresence.HandleAgentSit(). Correctness is not guaranteed.
185 double x, y, z, m1, m2;
186
187 Quaternion r = part.SitTargetOrientation;;
188 m1 = r.X * r.X + r.Y * r.Y;
189 m2 = r.Z * r.Z + r.W * r.W;
190
191 // Rotate the vector <0, 0, 1>
192 x = 2 * (r.X * r.Z + r.Y * r.W);
193 y = 2 * (-r.X * r.W + r.Y * r.Z);
194 z = m2 - m1;
195
196 // Set m to be the square of the norm of r.
197 double m = m1 + m2;
198
199 // This constant is emperically determined to be what is used in SL.
200 // See also http://opensimulator.org/mantis/view.php?id=7096
201 double offset = 0.05;
202
203 Vector3 up = new Vector3((float)x, (float)y, (float)z);
204 Vector3 sitOffset = up * (float)offset;
205 // End of copied section.
206
150 Assert.That( 207 Assert.That(
151 m_sp.AbsolutePosition, 208 m_sp.AbsolutePosition,
152 Is.EqualTo(part.AbsolutePosition + part.SitTargetPosition + ScenePresence.SIT_TARGET_ADJUSTMENT)); 209 Is.EqualTo(part.AbsolutePosition + part.SitTargetPosition - sitOffset + ScenePresence.SIT_TARGET_ADJUSTMENT));
153 Assert.That(m_sp.PhysicsActor, Is.Null); 210 Assert.That(m_sp.PhysicsActor, Is.Null);
154 211
155 Assert.That(part.GetSittingAvatarsCount(), Is.EqualTo(1)); 212 Assert.That(part.GetSittingAvatarsCount(), Is.EqualTo(1));
156 HashSet<UUID> sittingAvatars = part.GetSittingAvatars(); 213 HashSet<ScenePresence> sittingAvatars = part.GetSittingAvatars();
157 Assert.That(sittingAvatars.Count, Is.EqualTo(1)); 214 Assert.That(sittingAvatars.Count, Is.EqualTo(1));
158 Assert.That(sittingAvatars.Contains(m_sp.UUID)); 215 Assert.That(sittingAvatars.Contains(m_sp));
159 216
160 m_sp.StandUp(); 217 m_sp.StandUp();
161 218
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs
index 8dd1f3d..443ec51 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs
@@ -26,12 +26,15 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Reflection; 29using System.Collections.Generic;
30using System.IO;
31using System.Net;
32using System.Text;
33using System.Threading;
30using Nini.Config; 34using Nini.Config;
31using NUnit.Framework; 35using NUnit.Framework;
32using OpenMetaverse; 36using OpenMetaverse;
33using OpenSim.Framework; 37using OpenSim.Framework;
34using OpenSim.Framework.Communications;
35using OpenSim.Framework.Servers; 38using OpenSim.Framework.Servers;
36using OpenSim.Region.Framework.Interfaces; 39using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Region.CoreModules.Framework; 40using OpenSim.Region.CoreModules.Framework;
@@ -39,9 +42,6 @@ using OpenSim.Region.CoreModules.Framework.EntityTransfer;
39using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; 42using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation;
40using OpenSim.Region.CoreModules.World.Permissions; 43using OpenSim.Region.CoreModules.World.Permissions;
41using OpenSim.Tests.Common; 44using OpenSim.Tests.Common;
42using OpenSim.Tests.Common.Mock;
43using System.IO;
44using System.Text;
45 45
46namespace OpenSim.Region.Framework.Scenes.Tests 46namespace OpenSim.Region.Framework.Scenes.Tests
47{ 47{
@@ -68,7 +68,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
68 } 68 }
69 69
70 [Test] 70 [Test]
71 public void TestSameRegionTeleport() 71 public void TestSameRegion()
72 { 72 {
73 TestHelpers.InMethod(); 73 TestHelpers.InMethod();
74// log4net.Config.XmlConfigurator.Configure(); 74// log4net.Config.XmlConfigurator.Configure();
@@ -105,11 +105,12 @@ namespace OpenSim.Region.Framework.Scenes.Tests
105// Assert.That(sp.Lookat, Is.EqualTo(teleportLookAt)); 105// Assert.That(sp.Lookat, Is.EqualTo(teleportLookAt));
106 } 106 }
107 107
108/*
108 [Test] 109 [Test]
109 public void TestSameSimulatorSeparatedRegionsTeleport() 110 public void TestSameSimulatorIsolatedRegionsV1()
110 { 111 {
111 TestHelpers.InMethod(); 112 TestHelpers.InMethod();
112// log4net.Config.XmlConfigurator.Configure(); 113// TestHelpers.EnableLogging();
113 114
114 UUID userId = TestHelpers.ParseTail(0x1); 115 UUID userId = TestHelpers.ParseTail(0x1);
115 116
@@ -135,15 +136,18 @@ namespace OpenSim.Region.Framework.Scenes.Tests
135 SceneHelpers.SetupSceneModules(sceneB, config, etmB); 136 SceneHelpers.SetupSceneModules(sceneB, config, etmB);
136 SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm); 137 SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm);
137 138
139 // FIXME: Hack - this is here temporarily to revert back to older entity transfer behaviour
140 lscm.ServiceVersion = 0.1f;
141
138 Vector3 teleportPosition = new Vector3(10, 11, 12); 142 Vector3 teleportPosition = new Vector3(10, 11, 12);
139 Vector3 teleportLookAt = new Vector3(20, 21, 22); 143 Vector3 teleportLookAt = new Vector3(20, 21, 22);
140 144
141 ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager); 145 ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId);
142 sp.AbsolutePosition = new Vector3(30, 31, 32); 146 sp.AbsolutePosition = new Vector3(30, 31, 32);
143 147
144 // XXX: A very nasty hack to tell the client about the destination scene without having to crank the whole 148 List<TestClient> destinationTestClients = new List<TestClient>();
145 // UDP stack (?) 149 EntityTransferHelpers.SetupInformClientOfNeighbourTriggersNeighbourClientCreate(
146// ((TestClient)sp.ControllingClient).TeleportTargetScene = sceneB; 150 (TestClient)sp.ControllingClient, destinationTestClients);
147 151
148 sceneA.RequestTeleportLocation( 152 sceneA.RequestTeleportLocation(
149 sp.ControllingClient, 153 sp.ControllingClient,
@@ -152,7 +156,72 @@ namespace OpenSim.Region.Framework.Scenes.Tests
152 teleportLookAt, 156 teleportLookAt,
153 (uint)TeleportFlags.ViaLocation); 157 (uint)TeleportFlags.ViaLocation);
154 158
155 ((TestClient)sp.ControllingClient).CompleteTeleportClientSide(); 159 // SetupInformClientOfNeighbour() will have handled the callback into the target scene to setup the child
160 // agent. This call will now complete the movement of the user into the destination and upgrade the agent
161 // from child to root.
162 destinationTestClients[0].CompleteMovement();
163
164 Assert.That(sceneA.GetScenePresence(userId), Is.Null);
165
166 ScenePresence sceneBSp = sceneB.GetScenePresence(userId);
167 Assert.That(sceneBSp, Is.Not.Null);
168 Assert.That(sceneBSp.Scene.RegionInfo.RegionName, Is.EqualTo(sceneB.RegionInfo.RegionName));
169 Assert.That(sceneBSp.AbsolutePosition, Is.EqualTo(teleportPosition));
170
171 Assert.That(sceneA.GetRootAgentCount(), Is.EqualTo(0));
172 Assert.That(sceneA.GetChildAgentCount(), Is.EqualTo(0));
173 Assert.That(sceneB.GetRootAgentCount(), Is.EqualTo(1));
174 Assert.That(sceneB.GetChildAgentCount(), Is.EqualTo(0));
175
176 // TODO: Add assertions to check correct circuit details in both scenes.
177
178 // Lookat is sent to the client only - sp.Lookat does not yield the same thing (calculation from camera
179 // position instead).
180// Assert.That(sp.Lookat, Is.EqualTo(teleportLookAt));
181 }
182*/
183
184 [Test]
185 public void TestSameSimulatorIsolatedRegionsV2()
186 {
187 TestHelpers.InMethod();
188// TestHelpers.EnableLogging();
189
190 UUID userId = TestHelpers.ParseTail(0x1);
191
192 EntityTransferModule etmA = new EntityTransferModule();
193 EntityTransferModule etmB = new EntityTransferModule();
194 LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule();
195
196 IConfigSource config = new IniConfigSource();
197 IConfig modulesConfig = config.AddConfig("Modules");
198 modulesConfig.Set("EntityTransferModule", etmA.Name);
199 modulesConfig.Set("SimulationServices", lscm.Name);
200
201 SceneHelpers sh = new SceneHelpers();
202 TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000);
203 TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1002, 1000);
204
205 SceneHelpers.SetupSceneModules(sceneA, config, etmA);
206 SceneHelpers.SetupSceneModules(sceneB, config, etmB);
207 SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm);
208
209 Vector3 teleportPosition = new Vector3(10, 11, 12);
210 Vector3 teleportLookAt = new Vector3(20, 21, 22);
211
212 ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId);
213 sp.AbsolutePosition = new Vector3(30, 31, 32);
214
215 List<TestClient> destinationTestClients = new List<TestClient>();
216 EntityTransferHelpers.SetupSendRegionTeleportTriggersDestinationClientCreateAndCompleteMovement(
217 (TestClient)sp.ControllingClient, destinationTestClients);
218
219 sceneA.RequestTeleportLocation(
220 sp.ControllingClient,
221 sceneB.RegionInfo.RegionHandle,
222 teleportPosition,
223 teleportLookAt,
224 (uint)TeleportFlags.ViaLocation);
156 225
157 Assert.That(sceneA.GetScenePresence(userId), Is.Null); 226 Assert.That(sceneA.GetScenePresence(userId), Is.Null);
158 227
@@ -177,7 +246,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
177 /// Test teleport procedures when the target simulator returns false when queried about access. 246 /// Test teleport procedures when the target simulator returns false when queried about access.
178 /// </summary> 247 /// </summary>
179 [Test] 248 [Test]
180 public void TestSameSimulatorSeparatedRegionsQueryAccessFails() 249 public void TestSameSimulatorIsolatedRegions_DeniedOnQueryAccess()
181 { 250 {
182 TestHelpers.InMethod(); 251 TestHelpers.InMethod();
183// TestHelpers.EnableLogging(); 252// TestHelpers.EnableLogging();
@@ -221,7 +290,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
221 Vector3 teleportPosition = new Vector3(10, 11, 12); 290 Vector3 teleportPosition = new Vector3(10, 11, 12);
222 Vector3 teleportLookAt = new Vector3(20, 21, 22); 291 Vector3 teleportLookAt = new Vector3(20, 21, 22);
223 292
224 ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager); 293 ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId);
225 sp.AbsolutePosition = preTeleportPosition; 294 sp.AbsolutePosition = preTeleportPosition;
226 295
227 // Make sceneB return false on query access 296 // Make sceneB return false on query access
@@ -261,7 +330,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
261 /// Test teleport procedures when the target simulator create agent step is refused. 330 /// Test teleport procedures when the target simulator create agent step is refused.
262 /// </summary> 331 /// </summary>
263 [Test] 332 [Test]
264 public void TestSameSimulatorSeparatedRegionsCreateAgentFails() 333 public void TestSameSimulatorIsolatedRegions_DeniedOnCreateAgent()
265 { 334 {
266 TestHelpers.InMethod(); 335 TestHelpers.InMethod();
267// TestHelpers.EnableLogging(); 336// TestHelpers.EnableLogging();
@@ -297,7 +366,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
297 Vector3 teleportPosition = new Vector3(10, 11, 12); 366 Vector3 teleportPosition = new Vector3(10, 11, 12);
298 Vector3 teleportLookAt = new Vector3(20, 21, 22); 367 Vector3 teleportLookAt = new Vector3(20, 21, 22);
299 368
300 ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager); 369 ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId);
301 sp.AbsolutePosition = preTeleportPosition; 370 sp.AbsolutePosition = preTeleportPosition;
302 371
303 // Make sceneB refuse CreateAgent 372 // Make sceneB refuse CreateAgent
@@ -333,8 +402,97 @@ namespace OpenSim.Region.Framework.Scenes.Tests
333// TestHelpers.DisableLogging(); 402// TestHelpers.DisableLogging();
334 } 403 }
335 404
405 /// <summary>
406 /// Test teleport when the destination region does not process (or does not receive) the connection attempt
407 /// from the viewer.
408 /// </summary>
409 /// <remarks>
410 /// This could be quite a common case where the source region can connect to a remove destination region
411 /// (for CreateAgent) but the viewer cannot reach the destination region due to network issues.
412 /// </remarks>
336 [Test] 413 [Test]
337 public void TestSameSimulatorNeighbouringRegionsTeleport() 414 public void TestSameSimulatorIsolatedRegions_DestinationDidNotProcessViewerConnection()
415 {
416 TestHelpers.InMethod();
417// TestHelpers.EnableLogging();
418
419 UUID userId = TestHelpers.ParseTail(0x1);
420 Vector3 preTeleportPosition = new Vector3(30, 31, 32);
421
422 EntityTransferModule etmA = new EntityTransferModule();
423 EntityTransferModule etmB = new EntityTransferModule();
424
425 LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule();
426
427 IConfigSource config = new IniConfigSource();
428 config.AddConfig("Modules");
429 config.Configs["Modules"].Set("EntityTransferModule", etmA.Name);
430 config.Configs["Modules"].Set("SimulationServices", lscm.Name);
431
432 config.AddConfig("EntityTransfer");
433
434 // In order to run a single threaded regression test we do not want the entity transfer module waiting
435 // for a callback from the destination scene before removing its avatar data.
436 config.Configs["EntityTransfer"].Set("wait_for_callback", false);
437
438// config.AddConfig("Startup");
439// config.Configs["Startup"].Set("serverside_object_permissions", true);
440
441 SceneHelpers sh = new SceneHelpers();
442 TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000);
443 TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1002, 1000);
444
445 SceneHelpers.SetupSceneModules(sceneA, config, etmA );
446
447 // We need to set up the permisions module on scene B so that our later use of agent limit to deny
448 // QueryAccess won't succeed anyway because administrators are always allowed in and the default
449 // IsAdministrator if no permissions module is present is true.
450 SceneHelpers.SetupSceneModules(sceneB, config, new object[] { new PermissionsModule(), etmB });
451
452 // Shared scene modules
453 SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm);
454
455 Vector3 teleportPosition = new Vector3(10, 11, 12);
456 Vector3 teleportLookAt = new Vector3(20, 21, 22);
457
458 ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId);
459 sp.AbsolutePosition = preTeleportPosition;
460
461 sceneA.RequestTeleportLocation(
462 sp.ControllingClient,
463 sceneB.RegionInfo.RegionHandle,
464 teleportPosition,
465 teleportLookAt,
466 (uint)TeleportFlags.ViaLocation);
467
468 // FIXME: Not setting up InformClientOfNeighbour on the TestClient means that it does not initiate
469 // communication with the destination region. But this is a very non-obvious way of doing it - really we
470 // should be forced to expicitly set this up.
471
472 Assert.That(sceneB.GetScenePresence(userId), Is.Null);
473
474 ScenePresence sceneASp = sceneA.GetScenePresence(userId);
475 Assert.That(sceneASp, Is.Not.Null);
476 Assert.That(sceneASp.Scene.RegionInfo.RegionName, Is.EqualTo(sceneA.RegionInfo.RegionName));
477 Assert.That(sceneASp.AbsolutePosition, Is.EqualTo(preTeleportPosition));
478
479 Assert.That(sceneA.GetRootAgentCount(), Is.EqualTo(1));
480 Assert.That(sceneA.GetChildAgentCount(), Is.EqualTo(0));
481 Assert.That(sceneB.GetRootAgentCount(), Is.EqualTo(0));
482 Assert.That(sceneB.GetChildAgentCount(), Is.EqualTo(0));
483
484 // TODO: Add assertions to check correct circuit details in both scenes.
485
486 // Lookat is sent to the client only - sp.Lookat does not yield the same thing (calculation from camera
487 // position instead).
488// Assert.That(sp.Lookat, Is.EqualTo(teleportLookAt));
489
490// TestHelpers.DisableLogging();
491 }
492
493/*
494 [Test]
495 public void TestSameSimulatorNeighbouringRegionsV1()
338 { 496 {
339 TestHelpers.InMethod(); 497 TestHelpers.InMethod();
340// TestHelpers.EnableLogging(); 498// TestHelpers.EnableLogging();
@@ -363,13 +521,20 @@ namespace OpenSim.Region.Framework.Scenes.Tests
363 SceneHelpers.SetupSceneModules(sceneA, config, new CapabilitiesModule(), etmA); 521 SceneHelpers.SetupSceneModules(sceneA, config, new CapabilitiesModule(), etmA);
364 SceneHelpers.SetupSceneModules(sceneB, config, new CapabilitiesModule(), etmB); 522 SceneHelpers.SetupSceneModules(sceneB, config, new CapabilitiesModule(), etmB);
365 523
524 // FIXME: Hack - this is here temporarily to revert back to older entity transfer behaviour
525 lscm.ServiceVersion = 0.1f;
526
366 Vector3 teleportPosition = new Vector3(10, 11, 12); 527 Vector3 teleportPosition = new Vector3(10, 11, 12);
367 Vector3 teleportLookAt = new Vector3(20, 21, 22); 528 Vector3 teleportLookAt = new Vector3(20, 21, 22);
368 529
369 ScenePresence originalSp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager); 530 AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId);
370 originalSp.AbsolutePosition = new Vector3(30, 31, 32); 531 TestClient tc = new TestClient(acd, sceneA);
532 List<TestClient> destinationTestClients = new List<TestClient>();
533 EntityTransferHelpers.SetupInformClientOfNeighbourTriggersNeighbourClientCreate(tc, destinationTestClients);
534
535 ScenePresence beforeSceneASp = SceneHelpers.AddScenePresence(sceneA, tc, acd);
536 beforeSceneASp.AbsolutePosition = new Vector3(30, 31, 32);
371 537
372 ScenePresence beforeSceneASp = sceneA.GetScenePresence(userId);
373 Assert.That(beforeSceneASp, Is.Not.Null); 538 Assert.That(beforeSceneASp, Is.Not.Null);
374 Assert.That(beforeSceneASp.IsChildAgent, Is.False); 539 Assert.That(beforeSceneASp.IsChildAgent, Is.False);
375 540
@@ -377,10 +542,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests
377 Assert.That(beforeSceneBSp, Is.Not.Null); 542 Assert.That(beforeSceneBSp, Is.Not.Null);
378 Assert.That(beforeSceneBSp.IsChildAgent, Is.True); 543 Assert.That(beforeSceneBSp.IsChildAgent, Is.True);
379 544
380 // XXX: A very nasty hack to tell the client about the destination scene without having to crank the whole 545 // In this case, we will not receieve a second InformClientOfNeighbour since the viewer already knows
381 // UDP stack (?) 546 // about the neighbour region it is teleporting to.
382// ((TestClient)beforeSceneASp.ControllingClient).TeleportTargetScene = sceneB;
383
384 sceneA.RequestTeleportLocation( 547 sceneA.RequestTeleportLocation(
385 beforeSceneASp.ControllingClient, 548 beforeSceneASp.ControllingClient,
386 sceneB.RegionInfo.RegionHandle, 549 sceneB.RegionInfo.RegionHandle,
@@ -388,7 +551,92 @@ namespace OpenSim.Region.Framework.Scenes.Tests
388 teleportLookAt, 551 teleportLookAt,
389 (uint)TeleportFlags.ViaLocation); 552 (uint)TeleportFlags.ViaLocation);
390 553
391 ((TestClient)beforeSceneASp.ControllingClient).CompleteTeleportClientSide(); 554 destinationTestClients[0].CompleteMovement();
555
556 ScenePresence afterSceneASp = sceneA.GetScenePresence(userId);
557 Assert.That(afterSceneASp, Is.Not.Null);
558 Assert.That(afterSceneASp.IsChildAgent, Is.True);
559
560 ScenePresence afterSceneBSp = sceneB.GetScenePresence(userId);
561 Assert.That(afterSceneBSp, Is.Not.Null);
562 Assert.That(afterSceneBSp.IsChildAgent, Is.False);
563 Assert.That(afterSceneBSp.Scene.RegionInfo.RegionName, Is.EqualTo(sceneB.RegionInfo.RegionName));
564 Assert.That(afterSceneBSp.AbsolutePosition, Is.EqualTo(teleportPosition));
565
566 Assert.That(sceneA.GetRootAgentCount(), Is.EqualTo(0));
567 Assert.That(sceneA.GetChildAgentCount(), Is.EqualTo(1));
568 Assert.That(sceneB.GetRootAgentCount(), Is.EqualTo(1));
569 Assert.That(sceneB.GetChildAgentCount(), Is.EqualTo(0));
570
571 // TODO: Add assertions to check correct circuit details in both scenes.
572
573 // Lookat is sent to the client only - sp.Lookat does not yield the same thing (calculation from camera
574 // position instead).
575// Assert.That(sp.Lookat, Is.EqualTo(teleportLookAt));
576
577// TestHelpers.DisableLogging();
578 }
579*/
580
581 [Test]
582 public void TestSameSimulatorNeighbouringRegionsV2()
583 {
584 TestHelpers.InMethod();
585// TestHelpers.EnableLogging();
586
587 UUID userId = TestHelpers.ParseTail(0x1);
588
589 EntityTransferModule etmA = new EntityTransferModule();
590 EntityTransferModule etmB = new EntityTransferModule();
591 LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule();
592
593 IConfigSource config = new IniConfigSource();
594 IConfig modulesConfig = config.AddConfig("Modules");
595 modulesConfig.Set("EntityTransferModule", etmA.Name);
596 modulesConfig.Set("SimulationServices", lscm.Name);
597
598 SceneHelpers sh = new SceneHelpers();
599 TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000);
600 TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1001, 1000);
601
602 SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm);
603 SceneHelpers.SetupSceneModules(sceneA, config, new CapabilitiesModule(), etmA);
604 SceneHelpers.SetupSceneModules(sceneB, config, new CapabilitiesModule(), etmB);
605
606 Vector3 teleportPosition = new Vector3(10, 11, 12);
607 Vector3 teleportLookAt = new Vector3(20, 21, 22);
608
609 AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId);
610 TestClient tc = new TestClient(acd, sceneA);
611 List<TestClient> destinationTestClients = new List<TestClient>();
612 EntityTransferHelpers.SetupInformClientOfNeighbourTriggersNeighbourClientCreate(tc, destinationTestClients);
613
614 ScenePresence beforeSceneASp = SceneHelpers.AddScenePresence(sceneA, tc, acd);
615 beforeSceneASp.AbsolutePosition = new Vector3(30, 31, 32);
616
617 Assert.That(beforeSceneASp, Is.Not.Null);
618 Assert.That(beforeSceneASp.IsChildAgent, Is.False);
619
620 ScenePresence beforeSceneBSp = sceneB.GetScenePresence(userId);
621 Assert.That(beforeSceneBSp, Is.Not.Null);
622 Assert.That(beforeSceneBSp.IsChildAgent, Is.True);
623
624 // Here, we need to make clientA's receipt of SendRegionTeleport trigger clientB's CompleteMovement(). This
625 // is to operate the teleport V2 mechanism where the EntityTransferModule will first request the client to
626 // CompleteMovement to the region and then call UpdateAgent to the destination region to confirm the receipt
627 // Both these operations will occur on different threads and will wait for each other.
628 // We have to do this via ThreadPool directly since FireAndForget has been switched to sync for the V1
629 // test protocol, where we are trying to avoid unpredictable async operations in regression tests.
630 tc.OnTestClientSendRegionTeleport
631 += (regionHandle, simAccess, regionExternalEndPoint, locationID, flags, capsURL)
632 => ThreadPool.UnsafeQueueUserWorkItem(o => destinationTestClients[0].CompleteMovement(), null);
633
634 sceneA.RequestTeleportLocation(
635 beforeSceneASp.ControllingClient,
636 sceneB.RegionInfo.RegionHandle,
637 teleportPosition,
638 teleportLookAt,
639 (uint)TeleportFlags.ViaLocation);
392 640
393 ScenePresence afterSceneASp = sceneA.GetScenePresence(userId); 641 ScenePresence afterSceneASp = sceneA.GetScenePresence(userId);
394 Assert.That(afterSceneASp, Is.Not.Null); 642 Assert.That(afterSceneASp, Is.Not.Null);
@@ -414,4 +662,4 @@ namespace OpenSim.Region.Framework.Scenes.Tests
414// TestHelpers.DisableLogging(); 662// TestHelpers.DisableLogging();
415 } 663 }
416 } 664 }
417} \ No newline at end of file 665}
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneStatisticsTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneStatisticsTests.cs
new file mode 100644
index 0000000..045fd3c
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/Tests/SceneStatisticsTests.cs
@@ -0,0 +1,69 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using NUnit.Framework;
32using OpenMetaverse;
33using OpenSim.Framework;
34using OpenSim.Region.Framework.Scenes;
35using OpenSim.Tests.Common;
36
37namespace OpenSim.Region.Framework.Scenes.Tests
38{
39 [TestFixture]
40 public class SceneStatisticsTests : OpenSimTestCase
41 {
42 private TestScene m_scene;
43
44 [SetUp]
45 public void Init()
46 {
47 m_scene = new SceneHelpers().SetupScene();
48 }
49
50 [Test]
51 public void TestAddRemovePhysicalLinkset()
52 {
53 Assert.That(m_scene.SceneGraph.GetActiveObjectsCount(), Is.EqualTo(0));
54
55 UUID ownerId = TestHelpers.ParseTail(0x1);
56 SceneObjectGroup so1 = SceneHelpers.CreateSceneObject(3, ownerId, "so1", 0x10);
57 so1.ScriptSetPhysicsStatus(true);
58 m_scene.AddSceneObject(so1);
59
60 Assert.That(m_scene.SceneGraph.GetTotalObjectsCount(), Is.EqualTo(3));
61 Assert.That(m_scene.SceneGraph.GetActiveObjectsCount(), Is.EqualTo(3));
62
63 m_scene.DeleteSceneObject(so1, false);
64
65 Assert.That(m_scene.SceneGraph.GetTotalObjectsCount(), Is.EqualTo(0));
66 Assert.That(m_scene.SceneGraph.GetActiveObjectsCount(), Is.EqualTo(0));
67 }
68 }
69} \ No newline at end of file
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneTelehubTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneTelehubTests.cs
new file mode 100644
index 0000000..584a03c
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/Tests/SceneTelehubTests.cs
@@ -0,0 +1,118 @@
1/*
2 * Redistribution and use in source and binary forms, with or without
3 * modification, are permitted provided that the following conditions are met:
4 * * Redistributions of source code must retain the above copyright
5 * notice, this list of conditions and the following disclaimer.
6 * * Redistributions in binary form must reproduce the above copyright
7 * notice, this list of conditions and the following disclaimer in the
8 * documentation and/or other materials provided with the distribution.
9 * * Neither the name of the OpenSimulator Project nor the
10 * names of its contributors may be used to endorse or promote products
11 * derived from this software without specific prior written permission.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
25using System;
26using Nini.Config;
27using NUnit.Framework;
28using OpenMetaverse;
29using OpenSim.Framework;
30using OpenSim.Region.CoreModules.World.Estate;
31using OpenSim.Region.Framework.Scenes;
32using OpenSim.Region.Framework.Interfaces;
33using OpenSim.Services.Interfaces;
34using OpenSim.Tests.Common;
35
36namespace OpenSim.Region.Framework.Scenes.Tests
37{
38 /// <summary>
39 /// Scene telehub tests
40 /// </summary>
41 /// <remarks>
42 /// TODO: Tests which run through normal functionality. Currently, the only test is one that checks behaviour
43 /// in the case of an error condition
44 /// </remarks>
45 [TestFixture]
46 public class SceneTelehubTests : OpenSimTestCase
47 {
48 /// <summary>
49 /// Test for desired behaviour when a telehub has no spawn points
50 /// </summary>
51 [Test]
52 public void TestNoTelehubSpawnPoints()
53 {
54 TestHelpers.InMethod();
55// TestHelpers.EnableLogging();
56
57 EstateManagementModule emm = new EstateManagementModule();
58
59 SceneHelpers sh = new SceneHelpers();
60 Scene scene = sh.SetupScene();
61 SceneHelpers.SetupSceneModules(scene, emm);
62
63 UUID telehubSceneObjectOwner = TestHelpers.ParseTail(0x1);
64
65 SceneObjectGroup telehubSo = SceneHelpers.AddSceneObject(scene, "telehubObject", telehubSceneObjectOwner);
66
67 emm.HandleOnEstateManageTelehub(null, UUID.Zero, UUID.Zero, "connect", telehubSo.LocalId);
68 scene.RegionInfo.EstateSettings.AllowDirectTeleport = false;
69
70 // Must still be possible to successfully log in
71 UUID loggingInUserId = TestHelpers.ParseTail(0x2);
72
73 UserAccount ua
74 = UserAccountHelpers.CreateUserWithInventory(scene, "Test", "User", loggingInUserId, "password");
75
76 SceneHelpers.AddScenePresence(scene, ua);
77
78 Assert.That(scene.GetScenePresence(loggingInUserId), Is.Not.Null);
79 }
80
81 /// <summary>
82 /// Test for desired behaviour when the scene object nominated as a telehub object does not exist.
83 /// </summary>
84 [Test]
85 public void TestNoTelehubSceneObject()
86 {
87 TestHelpers.InMethod();
88// TestHelpers.EnableLogging();
89
90 EstateManagementModule emm = new EstateManagementModule();
91
92 SceneHelpers sh = new SceneHelpers();
93 Scene scene = sh.SetupScene();
94 SceneHelpers.SetupSceneModules(scene, emm);
95
96 UUID telehubSceneObjectOwner = TestHelpers.ParseTail(0x1);
97
98 SceneObjectGroup telehubSo = SceneHelpers.AddSceneObject(scene, "telehubObject", telehubSceneObjectOwner);
99 SceneObjectGroup spawnPointSo = SceneHelpers.AddSceneObject(scene, "spawnpointObject", telehubSceneObjectOwner);
100
101 emm.HandleOnEstateManageTelehub(null, UUID.Zero, UUID.Zero, "connect", telehubSo.LocalId);
102 emm.HandleOnEstateManageTelehub(null, UUID.Zero, UUID.Zero, "spawnpoint add", spawnPointSo.LocalId);
103 scene.RegionInfo.EstateSettings.AllowDirectTeleport = false;
104
105 scene.DeleteSceneObject(telehubSo, false);
106
107 // Must still be possible to successfully log in
108 UUID loggingInUserId = TestHelpers.ParseTail(0x2);
109
110 UserAccount ua
111 = UserAccountHelpers.CreateUserWithInventory(scene, "Test", "User", loggingInUserId, "password");
112
113 SceneHelpers.AddScenePresence(scene, ua);
114
115 Assert.That(scene.GetScenePresence(loggingInUserId), Is.Not.Null);
116 }
117 }
118} \ No newline at end of file
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs
index 9d8eb0b..517faf1 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs
@@ -36,13 +36,11 @@ using Nini.Config;
36using NUnit.Framework; 36using NUnit.Framework;
37using OpenMetaverse; 37using OpenMetaverse;
38using OpenSim.Framework; 38using OpenSim.Framework;
39using OpenSim.Framework.Communications;
40using OpenSim.Region.Framework.Scenes; 39using OpenSim.Region.Framework.Scenes;
41using OpenSim.Region.Framework.Interfaces; 40using OpenSim.Region.Framework.Interfaces;
42using OpenSim.Region.CoreModules.World.Serialiser; 41using OpenSim.Region.CoreModules.World.Serialiser;
43using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; 42using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation;
44using OpenSim.Tests.Common; 43using OpenSim.Tests.Common;
45using OpenSim.Tests.Common.Mock;
46 44
47namespace OpenSim.Region.Framework.Scenes.Tests 45namespace OpenSim.Region.Framework.Scenes.Tests
48{ 46{
@@ -52,6 +50,29 @@ namespace OpenSim.Region.Framework.Scenes.Tests
52 [TestFixture] 50 [TestFixture]
53 public class SceneTests : OpenSimTestCase 51 public class SceneTests : OpenSimTestCase
54 { 52 {
53 [Test]
54 public void TestCreateScene()
55 {
56 TestHelpers.InMethod();
57
58 new SceneHelpers().SetupScene();
59 }
60
61 [Test]
62 public void TestCreateVarScene()
63 {
64 TestHelpers.InMethod();
65 UUID regionUuid = TestHelpers.ParseTail(0x1);
66 uint sizeX = 512;
67 uint sizeY = 512;
68
69 Scene scene
70 = new SceneHelpers().SetupScene("scene", regionUuid, 1000, 1000, sizeX, sizeY, new IniConfigSource());
71
72 Assert.AreEqual(sizeX, scene.RegionInfo.RegionSizeX);
73 Assert.AreEqual(sizeY, scene.RegionInfo.RegionSizeY);
74 }
75
55 /// <summary> 76 /// <summary>
56 /// Very basic scene update test. Should become more elaborate with time. 77 /// Very basic scene update test. Should become more elaborate with time.
57 /// </summary> 78 /// </summary>
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SharedRegionModuleTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SharedRegionModuleTests.cs
new file mode 100644
index 0000000..eeda84f
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/Tests/SharedRegionModuleTests.cs
@@ -0,0 +1,249 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Net;
31using Mono.Addins;
32using Nini.Config;
33using NUnit.Framework;
34using OpenMetaverse;
35using OpenSim;
36using OpenSim.ApplicationPlugins.RegionModulesController;
37using OpenSim.Framework;
38using OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid;
39using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Tests.Common;
41
42namespace OpenSim.Region.Framework.Scenes.Tests
43{
44 public class SharedRegionModuleTests : OpenSimTestCase
45 {
46// [Test]
47 public void TestLifecycle()
48 {
49 TestHelpers.InMethod();
50 TestHelpers.EnableLogging();
51
52 UUID estateOwnerId = TestHelpers.ParseTail(0x1);
53 UUID regionId = TestHelpers.ParseTail(0x10);
54
55 IConfigSource configSource = new IniConfigSource();
56 configSource.AddConfig("Startup");
57 configSource.AddConfig("Modules");
58
59// // We use this to skip estate questions
60 // Turns out not to be needed is estate owner id is pre-set in region information.
61// IConfig estateConfig = configSource.AddConfig(OpenSimBase.ESTATE_SECTION_NAME);
62// estateConfig.Set("DefaultEstateOwnerName", "Zaphod Beeblebrox");
63// estateConfig.Set("DefaultEstateOwnerUUID", estateOwnerId);
64// estateConfig.Set("DefaultEstateOwnerEMail", "zaphod@galaxy.com");
65// estateConfig.Set("DefaultEstateOwnerPassword", "two heads");
66
67 // For grid servic
68 configSource.AddConfig("GridService");
69 configSource.Configs["Modules"].Set("GridServices", "LocalGridServicesConnector");
70 configSource.Configs["GridService"].Set("StorageProvider", "OpenSim.Data.Null.dll:NullRegionData");
71 configSource.Configs["GridService"].Set("LocalServiceModule", "OpenSim.Services.GridService.dll:GridService");
72 configSource.Configs["GridService"].Set("ConnectionString", "!static");
73
74 LocalGridServicesConnector gridService = new LocalGridServicesConnector();
75//
76 OpenSim sim = new OpenSim(configSource);
77
78 sim.SuppressExit = true;
79 sim.EnableInitialPluginLoad = false;
80 sim.LoadEstateDataService = false;
81 sim.NetServersInfo.HttpListenerPort = 0;
82
83 IRegistryCore reg = sim.ApplicationRegistry;
84
85 RegionInfo ri = new RegionInfo();
86 ri.RegionID = regionId;
87 ri.EstateSettings.EstateOwner = estateOwnerId;
88 ri.InternalEndPoint = new IPEndPoint(0, 0);
89
90 MockRegionModulesControllerPlugin rmcp = new MockRegionModulesControllerPlugin();
91 sim.m_plugins = new List<IApplicationPlugin>() { rmcp };
92 reg.RegisterInterface<IRegionModulesController>(rmcp);
93
94 // XXX: Have to initialize directly for now
95 rmcp.Initialise(sim);
96
97 rmcp.AddNode(gridService);
98
99 TestSharedRegion tsr = new TestSharedRegion();
100 rmcp.AddNode(tsr);
101
102 // FIXME: Want to use the real one eventually but this is currently directly tied into Mono.Addins
103 // which has been written in such a way that makes it impossible to use for regression tests.
104// RegionModulesControllerPlugin rmcp = new RegionModulesControllerPlugin();
105// rmcp.LoadModulesFromAddins = false;
106//// reg.RegisterInterface<IRegionModulesController>(rmcp);
107// rmcp.Initialise(sim);
108// rmcp.PostInitialise();
109// TypeExtensionNode node = new TypeExtensionNode();
110// node.
111// rmcp.AddNode(node, configSource.Configs["Modules"], new Dictionary<RuntimeAddin, IList<int>>());
112
113 sim.Startup();
114 IScene scene;
115 sim.CreateRegion(ri, out scene);
116
117 sim.Shutdown();
118
119 List<string> co = tsr.CallOrder;
120 int expectedEventCount = 6;
121
122 Assert.AreEqual(
123 expectedEventCount,
124 co.Count,
125 "Expected {0} events but only got {1} ({2})",
126 expectedEventCount, co.Count, string.Join(",", co));
127 Assert.AreEqual("Initialise", co[0]);
128 Assert.AreEqual("PostInitialise", co[1]);
129 Assert.AreEqual("AddRegion", co[2]);
130 Assert.AreEqual("RegionLoaded", co[3]);
131 Assert.AreEqual("RemoveRegion", co[4]);
132 Assert.AreEqual("Close", co[5]);
133 }
134 }
135
136 class TestSharedRegion : ISharedRegionModule
137 {
138 // FIXME: Should really use MethodInfo
139 public List<string> CallOrder = new List<string>();
140
141 public string Name { get { return "TestSharedRegion"; } }
142
143 public Type ReplaceableInterface { get { return null; } }
144
145 public void PostInitialise()
146 {
147 CallOrder.Add("PostInitialise");
148 }
149
150 public void Initialise(IConfigSource source)
151 {
152 CallOrder.Add("Initialise");
153 }
154
155 public void Close()
156 {
157 CallOrder.Add("Close");
158 }
159
160 public void AddRegion(Scene scene)
161 {
162 CallOrder.Add("AddRegion");
163 }
164
165 public void RemoveRegion(Scene scene)
166 {
167 CallOrder.Add("RemoveRegion");
168 }
169
170 public void RegionLoaded(Scene scene)
171 {
172 CallOrder.Add("RegionLoaded");
173 }
174 }
175
176 class MockRegionModulesControllerPlugin : IRegionModulesController, IApplicationPlugin
177 {
178 // List of shared module instances, for adding to Scenes
179 private List<ISharedRegionModule> m_sharedInstances = new List<ISharedRegionModule>();
180
181 // Config access
182 private OpenSimBase m_openSim;
183
184 public string Version { get { return "0"; } }
185 public string Name { get { return "MockRegionModulesControllerPlugin"; } }
186
187 public void Initialise() {}
188
189 public void Initialise(OpenSimBase sim)
190 {
191 m_openSim = sim;
192 }
193
194 /// <summary>
195 /// Called when the application loading is completed
196 /// </summary>
197 public void PostInitialise()
198 {
199 foreach (ISharedRegionModule module in m_sharedInstances)
200 module.PostInitialise();
201 }
202
203 public void AddRegionToModules(Scene scene)
204 {
205 List<ISharedRegionModule> sharedlist = new List<ISharedRegionModule>();
206
207 foreach (ISharedRegionModule module in m_sharedInstances)
208 {
209 module.AddRegion(scene);
210 scene.AddRegionModule(module.Name, module);
211
212 sharedlist.Add(module);
213 }
214
215 foreach (ISharedRegionModule module in sharedlist)
216 {
217 module.RegionLoaded(scene);
218 }
219 }
220
221 public void RemoveRegionFromModules(Scene scene)
222 {
223 foreach (IRegionModuleBase module in scene.RegionModules.Values)
224 {
225// m_log.DebugFormat("[REGIONMODULE]: Removing scene {0} from module {1}",
226// scene.RegionInfo.RegionName, module.Name);
227 module.RemoveRegion(scene);
228 }
229
230 scene.RegionModules.Clear();
231 }
232
233 public void AddNode(ISharedRegionModule module)
234 {
235 m_sharedInstances.Add(module);
236 module.Initialise(m_openSim.ConfigSource.Source);
237 }
238
239 public void Dispose()
240 {
241 // We expect that all regions have been removed already
242 while (m_sharedInstances.Count > 0)
243 {
244 m_sharedInstances[0].Close();
245 m_sharedInstances.RemoveAt(0);
246 }
247 }
248 }
249} \ No newline at end of file
diff --git a/OpenSim/Region/Framework/Scenes/Tests/TaskInventoryTests.cs b/OpenSim/Region/Framework/Scenes/Tests/TaskInventoryTests.cs
index 0b461f5..b01088d 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/TaskInventoryTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/TaskInventoryTests.cs
@@ -37,7 +37,6 @@ using NUnit.Framework;
37using OpenMetaverse; 37using OpenMetaverse;
38using OpenMetaverse.Assets; 38using OpenMetaverse.Assets;
39using OpenSim.Framework; 39using OpenSim.Framework;
40using OpenSim.Framework.Communications;
41using OpenSim.Region.Framework.Scenes; 40using OpenSim.Region.Framework.Scenes;
42using OpenSim.Region.Framework.Interfaces; 41using OpenSim.Region.Framework.Interfaces;
43using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver; 42using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver;
@@ -45,7 +44,6 @@ using OpenSim.Region.CoreModules.World.Serialiser;
45using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; 44using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation;
46using OpenSim.Services.Interfaces; 45using OpenSim.Services.Interfaces;
47using OpenSim.Tests.Common; 46using OpenSim.Tests.Common;
48using OpenSim.Tests.Common.Mock;
49 47
50namespace OpenSim.Region.Framework.Tests 48namespace OpenSim.Region.Framework.Tests
51{ 49{
@@ -65,7 +63,7 @@ namespace OpenSim.Region.Framework.Tests
65 63
66 // Create an object embedded inside the first 64 // Create an object embedded inside the first
67 UUID taskSceneObjectItemId = UUID.Parse("00000000-0000-0000-0000-100000000000"); 65 UUID taskSceneObjectItemId = UUID.Parse("00000000-0000-0000-0000-100000000000");
68 TaskInventoryHelpers.AddSceneObject(scene, sop1, "tso", taskSceneObjectItemId, user1.PrincipalID); 66 TaskInventoryHelpers.AddSceneObject(scene.AssetService, sop1, "tso", taskSceneObjectItemId, user1.PrincipalID);
69 67
70 TaskInventoryItem addedItem = sop1.Inventory.GetInventoryItem(taskSceneObjectItemId); 68 TaskInventoryItem addedItem = sop1.Inventory.GetInventoryItem(taskSceneObjectItemId);
71 Assert.That(addedItem.ItemID, Is.EqualTo(taskSceneObjectItemId)); 69 Assert.That(addedItem.ItemID, Is.EqualTo(taskSceneObjectItemId));
@@ -89,7 +87,7 @@ namespace OpenSim.Region.Framework.Tests
89 // Create an object embedded inside the first 87 // Create an object embedded inside the first
90 UUID taskSceneObjectItemId = UUID.Parse("00000000-0000-0000-0000-100000000000"); 88 UUID taskSceneObjectItemId = UUID.Parse("00000000-0000-0000-0000-100000000000");
91 TaskInventoryItem taskSceneObjectItem 89 TaskInventoryItem taskSceneObjectItem
92 = TaskInventoryHelpers.AddSceneObject(scene, sop1, "tso", taskSceneObjectItemId, user1.PrincipalID); 90 = TaskInventoryHelpers.AddSceneObject(scene.AssetService, sop1, "tso", taskSceneObjectItemId, user1.PrincipalID);
93 91
94 scene.AddSceneObject(sog1); 92 scene.AddSceneObject(sog1);
95 93
@@ -130,13 +128,14 @@ namespace OpenSim.Region.Framework.Tests
130 SceneObjectPart sop1 = sog1.RootPart; 128 SceneObjectPart sop1 = sog1.RootPart;
131 TaskInventoryItem sopItem1 129 TaskInventoryItem sopItem1
132 = TaskInventoryHelpers.AddNotecard( 130 = TaskInventoryHelpers.AddNotecard(
133 scene, sop1, "ncItem", TestHelpers.ParseTail(0x800), TestHelpers.ParseTail(0x900)); 131 scene.AssetService, sop1, "ncItem", TestHelpers.ParseTail(0x800), TestHelpers.ParseTail(0x900), "Hello World!");
134 132
135 InventoryFolderBase folder 133 InventoryFolderBase folder
136 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, user1.PrincipalID, "Objects")[0]; 134 = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, user1.PrincipalID, "Objects")[0];
137 135
138 // Perform test 136 // Perform test
139 scene.MoveTaskInventoryItem(user1.PrincipalID, folder.ID, sop1, sopItem1.ItemID); 137 string message;
138 scene.MoveTaskInventoryItem(user1.PrincipalID, folder.ID, sop1, sopItem1.ItemID, out message);
140 139
141 InventoryItemBase ncUserItem 140 InventoryItemBase ncUserItem
142 = InventoryArchiveUtils.FindItemByPath(scene.InventoryService, user1.PrincipalID, "Objects/ncItem"); 141 = InventoryArchiveUtils.FindItemByPath(scene.InventoryService, user1.PrincipalID, "Objects/ncItem");
@@ -162,10 +161,11 @@ namespace OpenSim.Region.Framework.Tests
162 SceneObjectPart sop1 = sog1.RootPart; 161 SceneObjectPart sop1 = sog1.RootPart;
163 TaskInventoryItem sopItem1 162 TaskInventoryItem sopItem1
164 = TaskInventoryHelpers.AddNotecard( 163 = TaskInventoryHelpers.AddNotecard(
165 scene, sop1, "ncItem", TestHelpers.ParseTail(0x800), TestHelpers.ParseTail(0x900)); 164 scene.AssetService, sop1, "ncItem", TestHelpers.ParseTail(0x800), TestHelpers.ParseTail(0x900), "Hello World!");
166 165
167 // Perform test 166 // Perform test
168 scene.MoveTaskInventoryItem(user1.PrincipalID, UUID.Zero, sop1, sopItem1.ItemID); 167 string message;
168 scene.MoveTaskInventoryItem(user1.PrincipalID, UUID.Zero, sop1, sopItem1.ItemID, out message);
169 169
170 InventoryItemBase ncUserItem 170 InventoryItemBase ncUserItem
171 = InventoryArchiveUtils.FindItemByPath(scene.InventoryService, user1.PrincipalID, "Notecards/ncItem"); 171 = InventoryArchiveUtils.FindItemByPath(scene.InventoryService, user1.PrincipalID, "Notecards/ncItem");
diff --git a/OpenSim/Region/Framework/Scenes/Tests/UserInventoryTests.cs b/OpenSim/Region/Framework/Scenes/Tests/UserInventoryTests.cs
index 9457ebb..8250e6c 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/UserInventoryTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/UserInventoryTests.cs
@@ -37,7 +37,6 @@ using NUnit.Framework;
37using OpenMetaverse; 37using OpenMetaverse;
38using OpenMetaverse.Assets; 38using OpenMetaverse.Assets;
39using OpenSim.Framework; 39using OpenSim.Framework;
40using OpenSim.Framework.Communications;
41using OpenSim.Region.Framework.Scenes; 40using OpenSim.Region.Framework.Scenes;
42using OpenSim.Region.Framework.Interfaces; 41using OpenSim.Region.Framework.Interfaces;
43using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver; 42using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver;
@@ -45,7 +44,6 @@ using OpenSim.Region.CoreModules.World.Serialiser;
45using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; 44using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation;
46using OpenSim.Services.Interfaces; 45using OpenSim.Services.Interfaces;
47using OpenSim.Tests.Common; 46using OpenSim.Tests.Common;
48using OpenSim.Tests.Common.Mock;
49 47
50namespace OpenSim.Region.Framework.Tests 48namespace OpenSim.Region.Framework.Tests
51{ 49{
@@ -64,7 +62,7 @@ namespace OpenSim.Region.Framework.Tests
64 Scene scene = new SceneHelpers().SetupScene(); 62 Scene scene = new SceneHelpers().SetupScene();
65 UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1001)); 63 UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1001));
66 64
67 UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, user1.PrincipalID, foldersName); 65 UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, user1.PrincipalID, foldersName, false);
68 66
69 List<InventoryFolderBase> oneFolder 67 List<InventoryFolderBase> oneFolder
70 = UserInventoryHelpers.GetInventoryFolders(scene.InventoryService, user1.PrincipalID, foldersName); 68 = UserInventoryHelpers.GetInventoryFolders(scene.InventoryService, user1.PrincipalID, foldersName);
@@ -73,7 +71,7 @@ namespace OpenSim.Region.Framework.Tests
73 InventoryFolderBase firstRetrievedFolder = oneFolder[0]; 71 InventoryFolderBase firstRetrievedFolder = oneFolder[0];
74 Assert.That(firstRetrievedFolder.Name, Is.EqualTo(foldersName)); 72 Assert.That(firstRetrievedFolder.Name, Is.EqualTo(foldersName));
75 73
76 UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, user1.PrincipalID, foldersName); 74 UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, user1.PrincipalID, foldersName, false);
77 75
78 List<InventoryFolderBase> twoFolders 76 List<InventoryFolderBase> twoFolders
79 = UserInventoryHelpers.GetInventoryFolders(scene.InventoryService, user1.PrincipalID, foldersName); 77 = UserInventoryHelpers.GetInventoryFolders(scene.InventoryService, user1.PrincipalID, foldersName);
@@ -95,7 +93,9 @@ namespace OpenSim.Region.Framework.Tests
95 UserAccount user2 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1002)); 93 UserAccount user2 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1002));
96 InventoryItemBase item1 = UserInventoryHelpers.CreateInventoryItem(scene, "item1", user1.PrincipalID); 94 InventoryItemBase item1 = UserInventoryHelpers.CreateInventoryItem(scene, "item1", user1.PrincipalID);
97 95
98 scene.GiveInventoryItem(user2.PrincipalID, user1.PrincipalID, item1.ID); 96 string message;
97
98 scene.GiveInventoryItem(user2.PrincipalID, user1.PrincipalID, item1.ID, out message);
99 99
100 InventoryItemBase retrievedItem1 100 InventoryItemBase retrievedItem1
101 = UserInventoryHelpers.GetInventoryItem(scene.InventoryService, user2.PrincipalID, "Notecards/item1"); 101 = UserInventoryHelpers.GetInventoryItem(scene.InventoryService, user2.PrincipalID, "Notecards/item1");
@@ -103,7 +103,7 @@ namespace OpenSim.Region.Framework.Tests
103 Assert.That(retrievedItem1, Is.Not.Null); 103 Assert.That(retrievedItem1, Is.Not.Null);
104 104
105 // Try giving back the freshly received item 105 // Try giving back the freshly received item
106 scene.GiveInventoryItem(user1.PrincipalID, user2.PrincipalID, retrievedItem1.ID); 106 scene.GiveInventoryItem(user1.PrincipalID, user2.PrincipalID, retrievedItem1.ID, out message);
107 107
108 List<InventoryItemBase> reretrievedItems 108 List<InventoryItemBase> reretrievedItems
109 = UserInventoryHelpers.GetInventoryItems(scene.InventoryService, user1.PrincipalID, "Notecards/item1"); 109 = UserInventoryHelpers.GetInventoryItems(scene.InventoryService, user1.PrincipalID, "Notecards/item1");
@@ -121,9 +121,9 @@ namespace OpenSim.Region.Framework.Tests
121 UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1001)); 121 UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1001));
122 UserAccount user2 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1002)); 122 UserAccount user2 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1002));
123 InventoryFolderBase folder1 123 InventoryFolderBase folder1
124 = UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, user1.PrincipalID, "folder1"); 124 = UserInventoryHelpers.CreateInventoryFolder(scene.InventoryService, user1.PrincipalID, "folder1", false);
125 125
126 scene.GiveInventoryFolder(user2.PrincipalID, user1.PrincipalID, folder1.ID, UUID.Zero); 126 scene.GiveInventoryFolder(null, user2.PrincipalID, user1.PrincipalID, folder1.ID, UUID.Zero);
127 127
128 InventoryFolderBase retrievedFolder1 128 InventoryFolderBase retrievedFolder1
129 = UserInventoryHelpers.GetInventoryFolder(scene.InventoryService, user2.PrincipalID, "folder1"); 129 = UserInventoryHelpers.GetInventoryFolder(scene.InventoryService, user2.PrincipalID, "folder1");
@@ -131,7 +131,7 @@ namespace OpenSim.Region.Framework.Tests
131 Assert.That(retrievedFolder1, Is.Not.Null); 131 Assert.That(retrievedFolder1, Is.Not.Null);
132 132
133 // Try giving back the freshly received folder 133 // Try giving back the freshly received folder
134 scene.GiveInventoryFolder(user1.PrincipalID, user2.PrincipalID, retrievedFolder1.ID, UUID.Zero); 134 scene.GiveInventoryFolder(null, user1.PrincipalID, user2.PrincipalID, retrievedFolder1.ID, UUID.Zero);
135 135
136 List<InventoryFolderBase> reretrievedFolders 136 List<InventoryFolderBase> reretrievedFolders
137 = UserInventoryHelpers.GetInventoryFolders(scene.InventoryService, user1.PrincipalID, "folder1"); 137 = UserInventoryHelpers.GetInventoryFolders(scene.InventoryService, user1.PrincipalID, "folder1");
diff --git a/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs b/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs
index dd27294..937c414 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs
@@ -33,7 +33,6 @@ using OpenSim.Framework;
33using OpenSim.Region.Framework.Scenes; 33using OpenSim.Region.Framework.Scenes;
34using OpenSim.Services.Interfaces; 34using OpenSim.Services.Interfaces;
35using OpenSim.Tests.Common; 35using OpenSim.Tests.Common;
36using OpenSim.Tests.Common.Mock;
37 36
38namespace OpenSim.Region.Framework.Scenes.Tests 37namespace OpenSim.Region.Framework.Scenes.Tests
39{ 38{
@@ -62,11 +61,11 @@ namespace OpenSim.Region.Framework.Scenes.Tests
62 = AssetHelpers.CreateAsset(corruptAssetUuid, AssetType.Notecard, "CORRUPT ASSET", UUID.Zero); 61 = AssetHelpers.CreateAsset(corruptAssetUuid, AssetType.Notecard, "CORRUPT ASSET", UUID.Zero);
63 m_assetService.Store(corruptAsset); 62 m_assetService.Store(corruptAsset);
64 63
65 IDictionary<UUID, AssetType> foundAssetUuids = new Dictionary<UUID, AssetType>(); 64 m_uuidGatherer.AddForInspection(corruptAssetUuid);
66 m_uuidGatherer.GatherAssetUuids(corruptAssetUuid, AssetType.Object, foundAssetUuids); 65 m_uuidGatherer.GatherAll();
67 66
68 // We count the uuid as gathered even if the asset itself is corrupt. 67 // We count the uuid as gathered even if the asset itself is corrupt.
69 Assert.That(foundAssetUuids.Count, Is.EqualTo(1)); 68 Assert.That(m_uuidGatherer.GatheredUuids.Count, Is.EqualTo(1));
70 } 69 }
71 70
72 /// <summary> 71 /// <summary>
@@ -78,38 +77,82 @@ namespace OpenSim.Region.Framework.Scenes.Tests
78 TestHelpers.InMethod(); 77 TestHelpers.InMethod();
79 78
80 UUID missingAssetUuid = UUID.Parse("00000000-0000-0000-0000-000000000666"); 79 UUID missingAssetUuid = UUID.Parse("00000000-0000-0000-0000-000000000666");
81 IDictionary<UUID, AssetType> foundAssetUuids = new Dictionary<UUID, AssetType>();
82
83 m_uuidGatherer.GatherAssetUuids(missingAssetUuid, AssetType.Object, foundAssetUuids);
84 80
85 // We count the uuid as gathered even if the asset itself is missing. 81 m_uuidGatherer.AddForInspection(missingAssetUuid);
86 Assert.That(foundAssetUuids.Count, Is.EqualTo(1)); 82 m_uuidGatherer.GatherAll();
83
84 Assert.That(m_uuidGatherer.GatheredUuids.Count, Is.EqualTo(0));
87 } 85 }
88 86
89 [Test] 87 [Test]
90 public void TestNotecardAsset() 88 public void TestNotecardAsset()
91 { 89 {
92 TestHelpers.InMethod(); 90 TestHelpers.InMethod();
93// log4net.Config.XmlConfigurator.Configure(); 91// TestHelpers.EnableLogging();
94 92
95 UUID ownerId = TestHelpers.ParseTail(0x10); 93 UUID ownerId = TestHelpers.ParseTail(0x10);
96 UUID soAssetId = TestHelpers.ParseTail(0x20); 94 UUID embeddedId = TestHelpers.ParseTail(0x20);
95 UUID secondLevelEmbeddedId = TestHelpers.ParseTail(0x21);
96 UUID missingEmbeddedId = TestHelpers.ParseTail(0x22);
97 UUID ncAssetId = TestHelpers.ParseTail(0x30); 97 UUID ncAssetId = TestHelpers.ParseTail(0x30);
98 98
99 SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, ownerId); 99 AssetBase ncAsset
100 AssetBase soAsset = AssetHelpers.CreateAsset(soAssetId, so); 100 = AssetHelpers.CreateNotecardAsset(
101 m_assetService.Store(soAsset); 101 ncAssetId, string.Format("Hello{0}World{1}", embeddedId, missingEmbeddedId));
102
103 AssetBase ncAsset = AssetHelpers.CreateNotecardAsset(ncAssetId, soAssetId.ToString());
104 m_assetService.Store(ncAsset); 102 m_assetService.Store(ncAsset);
105 103
106 IDictionary<UUID, AssetType> foundAssetUuids = new Dictionary<UUID, AssetType>(); 104 AssetBase embeddedAsset
107 m_uuidGatherer.GatherAssetUuids(ncAssetId, AssetType.Notecard, foundAssetUuids); 105 = AssetHelpers.CreateNotecardAsset(embeddedId, string.Format("{0} We'll meet again.", secondLevelEmbeddedId));
106 m_assetService.Store(embeddedAsset);
108 107
109 // We count the uuid as gathered even if the asset itself is corrupt. 108 AssetBase secondLevelEmbeddedAsset
110 Assert.That(foundAssetUuids.Count, Is.EqualTo(2)); 109 = AssetHelpers.CreateNotecardAsset(secondLevelEmbeddedId, "Don't know where, don't know when.");
111 Assert.That(foundAssetUuids.ContainsKey(ncAssetId)); 110 m_assetService.Store(secondLevelEmbeddedAsset);
112 Assert.That(foundAssetUuids.ContainsKey(soAssetId)); 111
112 m_uuidGatherer.AddForInspection(ncAssetId);
113 m_uuidGatherer.GatherAll();
114
115// foreach (UUID key in m_uuidGatherer.GatheredUuids.Keys)
116// System.Console.WriteLine("key : {0}", key);
117
118 Assert.That(m_uuidGatherer.GatheredUuids.Count, Is.EqualTo(3));
119 Assert.That(m_uuidGatherer.GatheredUuids.ContainsKey(ncAssetId));
120 Assert.That(m_uuidGatherer.GatheredUuids.ContainsKey(embeddedId));
121 Assert.That(m_uuidGatherer.GatheredUuids.ContainsKey(secondLevelEmbeddedId));
122 }
123
124 [Test]
125 public void TestTaskItems()
126 {
127 TestHelpers.InMethod();
128// TestHelpers.EnableLogging();
129
130 UUID ownerId = TestHelpers.ParseTail(0x10);
131
132 SceneObjectGroup soL0 = SceneHelpers.CreateSceneObject(1, ownerId, "l0", 0x20);
133 SceneObjectGroup soL1 = SceneHelpers.CreateSceneObject(1, ownerId, "l1", 0x21);
134 SceneObjectGroup soL2 = SceneHelpers.CreateSceneObject(1, ownerId, "l2", 0x22);
135
136 TaskInventoryHelpers.AddScript(
137 m_assetService, soL2.RootPart, TestHelpers.ParseTail(0x33), TestHelpers.ParseTail(0x43), "l3-script", "gibberish");
138
139 TaskInventoryHelpers.AddSceneObject(
140 m_assetService, soL1.RootPart, "l2-item", TestHelpers.ParseTail(0x32), soL2, TestHelpers.ParseTail(0x42));
141 TaskInventoryHelpers.AddSceneObject(
142 m_assetService, soL0.RootPart, "l1-item", TestHelpers.ParseTail(0x31), soL1, TestHelpers.ParseTail(0x41));
143
144 m_uuidGatherer.AddForInspection(soL0);
145 m_uuidGatherer.GatherAll();
146
147// foreach (UUID key in m_uuidGatherer.GatheredUuids.Keys)
148// System.Console.WriteLine("key : {0}", key);
149
150 // We expect to see the default prim texture and the assets of the contained task items
151 Assert.That(m_uuidGatherer.GatheredUuids.Count, Is.EqualTo(4));
152 Assert.That(m_uuidGatherer.GatheredUuids.ContainsKey(new UUID(Constants.DefaultTexture)));
153 Assert.That(m_uuidGatherer.GatheredUuids.ContainsKey(TestHelpers.ParseTail(0x41)));
154 Assert.That(m_uuidGatherer.GatheredUuids.ContainsKey(TestHelpers.ParseTail(0x42)));
155 Assert.That(m_uuidGatherer.GatheredUuids.ContainsKey(TestHelpers.ParseTail(0x43)));
113 } 156 }
114 } 157 }
115} 158} \ No newline at end of file
diff --git a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs
index e238d01..9ec4e1d 100644
--- a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs
+++ b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs
@@ -34,9 +34,11 @@ using System.Threading;
34using log4net; 34using log4net;
35using OpenMetaverse; 35using OpenMetaverse;
36using OpenMetaverse.Assets; 36using OpenMetaverse.Assets;
37using OpenMetaverse.StructuredData;
37using OpenSim.Framework; 38using OpenSim.Framework;
38using OpenSim.Region.Framework.Scenes.Serialization; 39using OpenSim.Region.Framework.Scenes.Serialization;
39using OpenSim.Services.Interfaces; 40using OpenSim.Services.Interfaces;
41using OpenSimAssetType = OpenSim.Framework.SLUtil.OpenSimAssetType;
40 42
41namespace OpenSim.Region.Framework.Scenes 43namespace OpenSim.Region.Framework.Scenes
42{ 44{
@@ -53,75 +55,81 @@ namespace OpenSim.Region.Framework.Scenes
53 { 55 {
54 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 56 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
55 57
58 /// <summary>
59 /// Is gathering complete?
60 /// </summary>
61 public bool Complete { get { return m_assetUuidsToInspect.Count <= 0; } }
62
63 /// <summary>
64 /// The dictionary of UUIDs gathered so far. If Complete == true then this is all the reachable UUIDs.
65 /// </summary>
66 /// <value>The gathered uuids.</value>
67 public IDictionary<UUID, sbyte> GatheredUuids { get; private set; }
68
69 /// <summary>
70 /// Gets the next UUID to inspect.
71 /// </summary>
72 /// <value>If there is no next UUID then returns null</value>
73 public UUID? NextUuidToInspect
74 {
75 get
76 {
77 if (Complete)
78 return null;
79 else
80 return m_assetUuidsToInspect.Peek();
81 }
82 }
83
56 protected IAssetService m_assetService; 84 protected IAssetService m_assetService;
57 85
58// /// <summary> 86 protected Queue<UUID> m_assetUuidsToInspect;
59// /// Used as a temporary store of an asset which represents an object. This can be a null if no appropriate 87
60// /// asset was found by the asset service. 88 /// <summary>
61// /// </summary> 89 /// Initializes a new instance of the <see cref="OpenSim.Region.Framework.Scenes.UuidGatherer"/> class.
62// private AssetBase m_requestedObjectAsset; 90 /// </summary>
63// 91 /// <remarks>In this case the collection of gathered assets will start out blank.</remarks>
64// /// <summary> 92 /// <param name="assetService">
65// /// Signal whether we are currently waiting for the asset service to deliver an asset. 93 /// Asset service.
66// /// </summary> 94 /// </param>
67// private bool m_waitingForObjectAsset; 95 public UuidGatherer(IAssetService assetService) : this(assetService, new Dictionary<UUID, sbyte>()) {}
68 96
69 public UuidGatherer(IAssetService assetService) 97 /// <summary>
98 /// Initializes a new instance of the <see cref="OpenSim.Region.Framework.Scenes.UuidGatherer"/> class.
99 /// </summary>
100 /// <param name="assetService">
101 /// Asset service.
102 /// </param>
103 /// <param name="collector">
104 /// Gathered UUIDs will be collected in this dictinaory.
105 /// It can be pre-populated if you want to stop the gatherer from analyzing assets that have already been fetched and inspected.
106 /// </param>
107 public UuidGatherer(IAssetService assetService, IDictionary<UUID, sbyte> collector)
70 { 108 {
71 m_assetService = assetService; 109 m_assetService = assetService;
110 GatheredUuids = collector;
111
112 // FIXME: Not efficient for searching, can improve.
113 m_assetUuidsToInspect = new Queue<UUID>();
72 } 114 }
73 115
74 /// <summary> 116 /// <summary>
75 /// Gather all the asset uuids associated with the asset referenced by a given uuid 117 /// Adds the asset uuid for inspection during the gathering process.
76 /// </summary> 118 /// </summary>
77 /// <remarks> 119 /// <returns><c>true</c>, if for inspection was added, <c>false</c> otherwise.</returns>
78 /// This includes both those directly associated with 120 /// <param name="uuid">UUID.</param>
79 /// it (e.g. face textures) and recursively, those of items within it's inventory (e.g. objects contained 121 public bool AddForInspection(UUID uuid)
80 /// within this object).
81 /// </remarks>
82 /// <param name="assetUuid">The uuid of the asset for which to gather referenced assets</param>
83 /// <param name="assetType">The type of the asset for the uuid given</param>
84 /// <param name="assetUuids">The assets gathered</param>
85 public void GatherAssetUuids(UUID assetUuid, AssetType assetType, IDictionary<UUID, AssetType> assetUuids)
86 { 122 {
87 // avoid infinite loops 123 if (m_assetUuidsToInspect.Contains(uuid))
88 if (assetUuids.ContainsKey(assetUuid)) 124 return false;
89 return;
90 125
91 try 126// m_log.DebugFormat("[UUID GATHERER]: Adding asset {0} for inspection", uuid);
92 { 127
93 assetUuids[assetUuid] = assetType; 128 m_assetUuidsToInspect.Enqueue(uuid);
94
95 if (AssetType.Bodypart == assetType || AssetType.Clothing == assetType)
96 {
97 GetWearableAssetUuids(assetUuid, assetUuids);
98 }
99 else if (AssetType.Gesture == assetType)
100 {
101 GetGestureAssetUuids(assetUuid, assetUuids);
102 }
103 else if (AssetType.Notecard == assetType)
104 {
105 GetTextEmbeddedAssetUuids(assetUuid, assetUuids);
106 }
107 else if (AssetType.LSLText == assetType)
108 {
109 GetTextEmbeddedAssetUuids(assetUuid, assetUuids);
110 }
111 else if (AssetType.Object == assetType)
112 {
113 GetSceneObjectAssetUuids(assetUuid, assetUuids);
114 }
115 }
116 catch (Exception)
117 {
118 m_log.ErrorFormat(
119 "[UUID GATHERER]: Failed to gather uuids for asset id {0}, type {1}",
120 assetUuid, assetType);
121 throw;
122 }
123 }
124 129
130 return true;
131 }
132
125 /// <summary> 133 /// <summary>
126 /// Gather all the asset uuids associated with a given object. 134 /// Gather all the asset uuids associated with a given object.
127 /// </summary> 135 /// </summary>
@@ -131,19 +139,18 @@ namespace OpenSim.Region.Framework.Scenes
131 /// within this object). 139 /// within this object).
132 /// </remarks> 140 /// </remarks>
133 /// <param name="sceneObject">The scene object for which to gather assets</param> 141 /// <param name="sceneObject">The scene object for which to gather assets</param>
134 /// <param name="assetUuids">The assets gathered</param> 142 public void AddForInspection(SceneObjectGroup sceneObject)
135 public void GatherAssetUuids(SceneObjectGroup sceneObject, IDictionary<UUID, AssetType> assetUuids)
136 { 143 {
137// m_log.DebugFormat( 144 // m_log.DebugFormat(
138// "[ASSET GATHERER]: Getting assets for object {0}, {1}", sceneObject.Name, sceneObject.UUID); 145 // "[ASSET GATHERER]: Getting assets for object {0}, {1}", sceneObject.Name, sceneObject.UUID);
139 146
140 SceneObjectPart[] parts = sceneObject.Parts; 147 SceneObjectPart[] parts = sceneObject.Parts;
141 for (int i = 0; i < parts.Length; i++) 148 for (int i = 0; i < parts.Length; i++)
142 { 149 {
143 SceneObjectPart part = parts[i]; 150 SceneObjectPart part = parts[i];
144 151
145// m_log.DebugFormat( 152 // m_log.DebugFormat(
146// "[ARCHIVER]: Getting part {0}, {1} for object {2}", part.Name, part.UUID, sceneObject.UUID); 153 // "[ARCHIVER]: Getting part {0}, {1} for object {2}", part.Name, part.UUID, sceneObject.UUID);
147 154
148 try 155 try
149 { 156 {
@@ -152,7 +159,7 @@ namespace OpenSim.Region.Framework.Scenes
152 { 159 {
153 // Get the prim's default texture. This will be used for faces which don't have their own texture 160 // Get the prim's default texture. This will be used for faces which don't have their own texture
154 if (textureEntry.DefaultTexture != null) 161 if (textureEntry.DefaultTexture != null)
155 assetUuids[textureEntry.DefaultTexture.TextureID] = AssetType.Texture; 162 RecordTextureEntryAssetUuids(textureEntry.DefaultTexture);
156 163
157 if (textureEntry.FaceTextures != null) 164 if (textureEntry.FaceTextures != null)
158 { 165 {
@@ -160,27 +167,59 @@ namespace OpenSim.Region.Framework.Scenes
160 foreach (Primitive.TextureEntryFace texture in textureEntry.FaceTextures) 167 foreach (Primitive.TextureEntryFace texture in textureEntry.FaceTextures)
161 { 168 {
162 if (texture != null) 169 if (texture != null)
163 assetUuids[texture.TextureID] = AssetType.Texture; 170 RecordTextureEntryAssetUuids(texture);
164 } 171 }
165 } 172 }
166 } 173 }
167 174
168 // If the prim is a sculpt then preserve this information too 175 // If the prim is a sculpt then preserve this information too
169 if (part.Shape.SculptTexture != UUID.Zero) 176 if (part.Shape.SculptTexture != UUID.Zero)
170 assetUuids[part.Shape.SculptTexture] = AssetType.Texture; 177 GatheredUuids[part.Shape.SculptTexture] = (sbyte)AssetType.Texture;
171 178
179 if (part.Shape.ProjectionTextureUUID != UUID.Zero)
180 GatheredUuids[part.Shape.ProjectionTextureUUID] = (sbyte)AssetType.Texture;
181
182 if (part.CollisionSound != UUID.Zero)
183 GatheredUuids[part.CollisionSound] = (sbyte)AssetType.Sound;
184
185 if (part.ParticleSystem.Length > 0)
186 {
187 try
188 {
189 Primitive.ParticleSystem ps = new Primitive.ParticleSystem(part.ParticleSystem, 0);
190 if (ps.Texture != UUID.Zero)
191 GatheredUuids[ps.Texture] = (sbyte)AssetType.Texture;
192 }
193 catch (Exception)
194 {
195 m_log.WarnFormat(
196 "[UUID GATHERER]: Could not check particle system for part {0} {1} in object {2} {3} since it is corrupt. Continuing.",
197 part.Name, part.UUID, sceneObject.Name, sceneObject.UUID);
198 }
199 }
200
172 TaskInventoryDictionary taskDictionary = (TaskInventoryDictionary)part.TaskInventory.Clone(); 201 TaskInventoryDictionary taskDictionary = (TaskInventoryDictionary)part.TaskInventory.Clone();
173 202
174 // Now analyze this prim's inventory items to preserve all the uuids that they reference 203 // Now analyze this prim's inventory items to preserve all the uuids that they reference
175 foreach (TaskInventoryItem tii in taskDictionary.Values) 204 foreach (TaskInventoryItem tii in taskDictionary.Values)
176 { 205 {
177// m_log.DebugFormat( 206 // m_log.DebugFormat(
178// "[ARCHIVER]: Analysing item {0} asset type {1} in {2} {3}", 207 // "[ARCHIVER]: Analysing item {0} asset type {1} in {2} {3}",
179// tii.Name, tii.Type, part.Name, part.UUID); 208 // tii.Name, tii.Type, part.Name, part.UUID);
180 209
181 if (!assetUuids.ContainsKey(tii.AssetID)) 210 if (!GatheredUuids.ContainsKey(tii.AssetID))
182 GatherAssetUuids(tii.AssetID, (AssetType)tii.Type, assetUuids); 211 AddForInspection(tii.AssetID, (sbyte)tii.Type);
183 } 212 }
213
214 // FIXME: We need to make gathering modular but we cannot yet, since gatherers are not guaranteed
215 // to be called with scene objects that are in a scene (e.g. in the case of hg asset mapping and
216 // inventory transfer. There needs to be a way for a module to register a method without assuming a
217 // Scene.EventManager is present.
218 // part.ParentGroup.Scene.EventManager.TriggerGatherUuids(part, assetUuids);
219
220
221 // still needed to retrieve textures used as materials for any parts containing legacy materials stored in DynAttrs
222 RecordMaterialsUuids(part);
184 } 223 }
185 catch (Exception e) 224 catch (Exception e)
186 { 225 {
@@ -191,179 +230,334 @@ namespace OpenSim.Region.Framework.Scenes
191 } 230 }
192 } 231 }
193 } 232 }
194
195// /// <summary>
196// /// The callback made when we request the asset for an object from the asset service.
197// /// </summary>
198// private void AssetReceived(string id, Object sender, AssetBase asset)
199// {
200// lock (this)
201// {
202// m_requestedObjectAsset = asset;
203// m_waitingForObjectAsset = false;
204// Monitor.Pulse(this);
205// }
206// }
207 233
208 /// <summary> 234 /// <summary>
209 /// Get an asset synchronously, potentially using an asynchronous callback. If the 235 /// Gathers the next set of assets returned by the next uuid to get from the asset service.
210 /// asynchronous callback is used, we will wait for it to complete.
211 /// </summary> 236 /// </summary>
212 /// <param name="uuid"></param> 237 /// <returns>false if gathering is already complete, true otherwise</returns>
213 /// <returns></returns> 238 public bool GatherNext()
214 protected virtual AssetBase GetAsset(UUID uuid)
215 { 239 {
216 return m_assetService.Get(uuid.ToString()); 240 if (Complete)
241 return false;
242
243 UUID nextToInspect = m_assetUuidsToInspect.Dequeue();
244
245// m_log.DebugFormat("[UUID GATHERER]: Inspecting asset {0}", nextToInspect);
246
247 GetAssetUuids(nextToInspect);
217 248
218 // XXX: Switching to do this synchronously where the call was async before but we always waited for it 249 return true;
219 // to complete anyway!
220// m_waitingForObjectAsset = true;
221// m_assetCache.Get(uuid.ToString(), this, AssetReceived);
222//
223// // The asset cache callback can either
224// //
225// // 1. Complete on the same thread (if the asset is already in the cache) or
226// // 2. Come in via a different thread (if we need to go fetch it).
227// //
228// // The code below handles both these alternatives.
229// lock (this)
230// {
231// if (m_waitingForObjectAsset)
232// {
233// Monitor.Wait(this);
234// m_waitingForObjectAsset = false;
235// }
236// }
237//
238// return m_requestedObjectAsset;
239 } 250 }
240 251
241 /// <summary> 252 /// <summary>
242 /// Record the asset uuids embedded within the given script. 253 /// Gathers all remaining asset UUIDS no matter how many calls are required to the asset service.
243 /// </summary> 254 /// </summary>
244 /// <param name="scriptUuid"></param> 255 /// <returns>false if gathering is already complete, true otherwise</returns>
245 /// <param name="assetUuids">Dictionary in which to record the references</param> 256 public bool GatherAll()
246 private void GetTextEmbeddedAssetUuids(UUID embeddingAssetId, IDictionary<UUID, AssetType> assetUuids)
247 { 257 {
248// m_log.DebugFormat("[ASSET GATHERER]: Getting assets for uuid references in asset {0}", embeddingAssetId); 258 if (Complete)
259 return false;
249 260
250 AssetBase embeddingAsset = GetAsset(embeddingAssetId); 261 while (GatherNext());
251 262
252 if (null != embeddingAsset) 263 return true;
253 { 264 }
254 string script = Utils.BytesToString(embeddingAsset.Data);
255// m_log.DebugFormat("[ARCHIVER]: Script {0}", script);
256 MatchCollection uuidMatches = Util.PermissiveUUIDPattern.Matches(script);
257// m_log.DebugFormat("[ARCHIVER]: Found {0} matches in text", uuidMatches.Count);
258 265
259 foreach (Match uuidMatch in uuidMatches) 266 /// <summary>
267 /// Gather all the asset uuids associated with the asset referenced by a given uuid
268 /// </summary>
269 /// <remarks>
270 /// This includes both those directly associated with
271 /// it (e.g. face textures) and recursively, those of items within it's inventory (e.g. objects contained
272 /// within this object).
273 /// This method assumes that the asset type associated with this asset in persistent storage is correct (which
274 /// should always be the case). So with this method we always need to retrieve asset data even if the asset
275 /// is of a type which is known not to reference any other assets
276 /// </remarks>
277 /// <param name="assetUuid">The uuid of the asset for which to gather referenced assets</param>
278 private void GetAssetUuids(UUID assetUuid)
279 {
280 // avoid infinite loops
281 if (GatheredUuids.ContainsKey(assetUuid))
282 return;
283
284 try
285 {
286 AssetBase assetBase = GetAsset(assetUuid);
287
288 if (null != assetBase)
260 { 289 {
261 UUID uuid = new UUID(uuidMatch.Value); 290 sbyte assetType = assetBase.Type;
262// m_log.DebugFormat("[ARCHIVER]: Recording {0} in text", uuid); 291 GatheredUuids[assetUuid] = assetType;
292
293 if ((sbyte)AssetType.Bodypart == assetType || (sbyte)AssetType.Clothing == assetType)
294 {
295 RecordWearableAssetUuids(assetBase);
296 }
297 else if ((sbyte)AssetType.Gesture == assetType)
298 {
299 RecordGestureAssetUuids(assetBase);
300 }
301 else if ((sbyte)AssetType.Notecard == assetType)
302 {
303 RecordTextEmbeddedAssetUuids(assetBase);
304 }
305 else if ((sbyte)AssetType.LSLText == assetType)
306 {
307 RecordTextEmbeddedAssetUuids(assetBase);
308 }
309 else if ((sbyte)OpenSimAssetType.Material == assetType)
310 {
311 RecordMaterialAssetUuids(assetBase);
312 }
313 else if ((sbyte)AssetType.Object == assetType)
314 {
315 RecordSceneObjectAssetUuids(assetBase);
316 }
317 }
318 }
319 catch (Exception)
320 {
321 m_log.ErrorFormat("[UUID GATHERER]: Failed to gather uuids for asset id {0}", assetUuid);
322 throw;
323 }
324 }
263 325
264 // Assume AssetIDs embedded are textures. 326 private void AddForInspection(UUID assetUuid, sbyte assetType)
265 assetUuids[uuid] = AssetType.Texture; 327 {
328 // Here, we want to collect uuids which require further asset fetches but mark the others as gathered
329 try
330 {
331 if ((sbyte)AssetType.Bodypart == assetType
332 || (sbyte)AssetType.Clothing == assetType
333 || (sbyte)AssetType.Gesture == assetType
334 || (sbyte)AssetType.Notecard == assetType
335 || (sbyte)AssetType.LSLText == assetType
336 || (sbyte)OpenSimAssetType.Material == assetType
337 || (sbyte)AssetType.Object == assetType)
338 {
339 AddForInspection(assetUuid);
340 }
341 else
342 {
343 GatheredUuids[assetUuid] = assetType;
266 } 344 }
267 } 345 }
346 catch (Exception)
347 {
348 m_log.ErrorFormat(
349 "[UUID GATHERER]: Failed to gather uuids for asset id {0}, type {1}",
350 assetUuid, assetType);
351 throw;
352 }
268 } 353 }
269 354
270 /// <summary> 355 /// <summary>
271 /// Record the uuids referenced by the given wearable asset 356 /// Collect all the asset uuids found in one face of a Texture Entry.
272 /// </summary> 357 /// </summary>
273 /// <param name="wearableAssetUuid"></param> 358 private void RecordTextureEntryAssetUuids(Primitive.TextureEntryFace texture)
274 /// <param name="assetUuids">Dictionary in which to record the references</param>
275 private void GetWearableAssetUuids(UUID wearableAssetUuid, IDictionary<UUID, AssetType> assetUuids)
276 { 359 {
277 AssetBase assetBase = GetAsset(wearableAssetUuid); 360 GatheredUuids[texture.TextureID] = (sbyte)AssetType.Texture;
278 361
279 if (null != assetBase) 362 if (texture.MaterialID != UUID.Zero)
363 AddForInspection(texture.MaterialID);
364 }
365
366 /// <summary>
367 /// Gather all of the texture asset UUIDs used to reference "Materials" such as normal and specular maps
368 /// stored in legacy format in part.DynAttrs
369 /// </summary>
370 /// <param name="part"></param>
371 private void RecordMaterialsUuids(SceneObjectPart part)
372 {
373 // scan thru the dynAttrs map of this part for any textures used as materials
374 OSD osdMaterials = null;
375
376 lock (part.DynAttrs)
280 { 377 {
281 //m_log.Debug(new System.Text.ASCIIEncoding().GetString(bodypartAsset.Data)); 378 if (part.DynAttrs.ContainsStore("OpenSim", "Materials"))
282 AssetWearable wearableAsset = new AssetBodypart(wearableAssetUuid, assetBase.Data);
283 wearableAsset.Decode();
284
285 //m_log.DebugFormat(
286 // "[ARCHIVER]: Wearable asset {0} references {1} assets", wearableAssetUuid, wearableAsset.Textures.Count);
287
288 foreach (UUID uuid in wearableAsset.Textures.Values)
289 { 379 {
290 assetUuids[uuid] = AssetType.Texture; 380 OSDMap materialsStore = part.DynAttrs.GetStore("OpenSim", "Materials");
381
382 if (materialsStore == null)
383 return;
384
385 materialsStore.TryGetValue("Materials", out osdMaterials);
386 }
387
388 if (osdMaterials != null)
389 {
390 //m_log.Info("[UUID Gatherer]: found Materials: " + OSDParser.SerializeJsonString(osd));
391
392 if (osdMaterials is OSDArray)
393 {
394 OSDArray matsArr = osdMaterials as OSDArray;
395 foreach (OSDMap matMap in matsArr)
396 {
397 try
398 {
399 if (matMap.ContainsKey("Material"))
400 {
401 OSDMap mat = matMap["Material"] as OSDMap;
402 if (mat.ContainsKey("NormMap"))
403 {
404 UUID normalMapId = mat["NormMap"].AsUUID();
405 if (normalMapId != UUID.Zero)
406 {
407 GatheredUuids[normalMapId] = (sbyte)AssetType.Texture;
408 //m_log.Info("[UUID Gatherer]: found normal map ID: " + normalMapId.ToString());
409 }
410 }
411 if (mat.ContainsKey("SpecMap"))
412 {
413 UUID specularMapId = mat["SpecMap"].AsUUID();
414 if (specularMapId != UUID.Zero)
415 {
416 GatheredUuids[specularMapId] = (sbyte)AssetType.Texture;
417 //m_log.Info("[UUID Gatherer]: found specular map ID: " + specularMapId.ToString());
418 }
419 }
420 }
421
422 }
423 catch (Exception e)
424 {
425 m_log.Warn("[UUID Gatherer]: exception getting materials: " + e.Message);
426 }
427 }
428 }
291 } 429 }
292 } 430 }
293 } 431 }
294 432
295 /// <summary> 433 /// <summary>
434 /// Get an asset synchronously, potentially using an asynchronous callback. If the
435 /// asynchronous callback is used, we will wait for it to complete.
436 /// </summary>
437 /// <param name="uuid"></param>
438 /// <returns></returns>
439 protected virtual AssetBase GetAsset(UUID uuid)
440 {
441 return m_assetService.Get(uuid.ToString());
442 }
443
444 /// <summary>
445 /// Record the asset uuids embedded within the given text (e.g. a script).
446 /// </summary>
447 /// <param name="textAsset"></param>
448 private void RecordTextEmbeddedAssetUuids(AssetBase textAsset)
449 {
450 // m_log.DebugFormat("[ASSET GATHERER]: Getting assets for uuid references in asset {0}", embeddingAssetId);
451
452 string text = Utils.BytesToString(textAsset.Data);
453// m_log.DebugFormat("[UUID GATHERER]: Text {0}", text);
454 MatchCollection uuidMatches = Util.PermissiveUUIDPattern.Matches(text);
455// m_log.DebugFormat("[UUID GATHERER]: Found {0} matches in text", uuidMatches.Count);
456
457 foreach (Match uuidMatch in uuidMatches)
458 {
459 UUID uuid = new UUID(uuidMatch.Value);
460// m_log.DebugFormat("[UUID GATHERER]: Recording {0} in text", uuid);
461
462 AddForInspection(uuid);
463 }
464 }
465
466 /// <summary>
467 /// Record the uuids referenced by the given wearable asset
468 /// </summary>
469 /// <param name="assetBase"></param>
470 private void RecordWearableAssetUuids(AssetBase assetBase)
471 {
472 //m_log.Debug(new System.Text.ASCIIEncoding().GetString(bodypartAsset.Data));
473 AssetWearable wearableAsset = new AssetBodypart(assetBase.FullID, assetBase.Data);
474 wearableAsset.Decode();
475
476 //m_log.DebugFormat(
477 // "[ARCHIVER]: Wearable asset {0} references {1} assets", wearableAssetUuid, wearableAsset.Textures.Count);
478
479 foreach (UUID uuid in wearableAsset.Textures.Values)
480 GatheredUuids[uuid] = (sbyte)AssetType.Texture;
481 }
482
483 /// <summary>
296 /// Get all the asset uuids associated with a given object. This includes both those directly associated with 484 /// Get all the asset uuids associated with a given object. This includes both those directly associated with
297 /// it (e.g. face textures) and recursively, those of items within it's inventory (e.g. objects contained 485 /// it (e.g. face textures) and recursively, those of items within it's inventory (e.g. objects contained
298 /// within this object). 486 /// within this object).
299 /// </summary> 487 /// </summary>
300 /// <param name="sceneObject"></param> 488 /// <param name="sceneObjectAsset"></param>
301 /// <param name="assetUuids"></param> 489 private void RecordSceneObjectAssetUuids(AssetBase sceneObjectAsset)
302 private void GetSceneObjectAssetUuids(UUID sceneObjectUuid, IDictionary<UUID, AssetType> assetUuids)
303 { 490 {
304 AssetBase objectAsset = GetAsset(sceneObjectUuid); 491 string xml = Utils.BytesToString(sceneObjectAsset.Data);
305 492
306 if (null != objectAsset) 493 CoalescedSceneObjects coa;
494 if (CoalescedSceneObjectsSerializer.TryFromXml(xml, out coa))
307 { 495 {
308 string xml = Utils.BytesToString(objectAsset.Data); 496 foreach (SceneObjectGroup sog in coa.Objects)
309 497 AddForInspection(sog);
310 CoalescedSceneObjects coa; 498 }
311 if (CoalescedSceneObjectsSerializer.TryFromXml(xml, out coa)) 499 else
312 { 500 {
313 foreach (SceneObjectGroup sog in coa.Objects) 501 SceneObjectGroup sog = SceneObjectSerializer.FromOriginalXmlFormat(xml);
314 GatherAssetUuids(sog, assetUuids); 502
315 } 503 if (null != sog)
316 else 504 AddForInspection(sog);
505 }
506 }
507
508 /// <summary>
509 /// Get the asset uuid associated with a gesture
510 /// </summary>
511 /// <param name="gestureAsset"></param>
512 private void RecordGestureAssetUuids(AssetBase gestureAsset)
513 {
514 using (MemoryStream ms = new MemoryStream(gestureAsset.Data))
515 using (StreamReader sr = new StreamReader(ms))
516 {
517 sr.ReadLine(); // Unknown (Version?)
518 sr.ReadLine(); // Unknown
519 sr.ReadLine(); // Unknown
520 sr.ReadLine(); // Name
521 sr.ReadLine(); // Comment ?
522 int count = Convert.ToInt32(sr.ReadLine()); // Item count
523
524 for (int i = 0 ; i < count ; i++)
317 { 525 {
318 SceneObjectGroup sog = SceneObjectSerializer.FromOriginalXmlFormat(xml); 526 string type = sr.ReadLine();
319 527 if (type == null)
320 if (null != sog) 528 break;
321 GatherAssetUuids(sog, assetUuids); 529 string name = sr.ReadLine();
530 if (name == null)
531 break;
532 string id = sr.ReadLine();
533 if (id == null)
534 break;
535 string unknown = sr.ReadLine();
536 if (unknown == null)
537 break;
538
539 // If it can be parsed as a UUID, it is an asset ID
540 UUID uuid;
541 if (UUID.TryParse(id, out uuid))
542 GatheredUuids[uuid] = (sbyte)AssetType.Animation; // the asset is either an Animation or a Sound, but this distinction isn't important
322 } 543 }
323 } 544 }
324 } 545 }
325 546
326 /// <summary> 547 /// <summary>
327 /// Get the asset uuid associated with a gesture 548 /// Get the asset uuid's referenced in a material.
328 /// </summary> 549 /// </summary>
329 /// <param name="gestureUuid"></param> 550 private void RecordMaterialAssetUuids(AssetBase materialAsset)
330 /// <param name="assetUuids"></param>
331 private void GetGestureAssetUuids(UUID gestureUuid, IDictionary<UUID, AssetType> assetUuids)
332 { 551 {
333 AssetBase assetBase = GetAsset(gestureUuid); 552 OSDMap mat = (OSDMap)OSDParser.DeserializeLLSDXml(materialAsset.Data);
334 if (null == assetBase)
335 return;
336
337 MemoryStream ms = new MemoryStream(assetBase.Data);
338 StreamReader sr = new StreamReader(ms);
339 553
340 sr.ReadLine(); // Unknown (Version?) 554 UUID normMap = mat["NormMap"].AsUUID();
341 sr.ReadLine(); // Unknown 555 if (normMap != UUID.Zero)
342 sr.ReadLine(); // Unknown 556 GatheredUuids[normMap] = (sbyte)AssetType.Texture;
343 sr.ReadLine(); // Name
344 sr.ReadLine(); // Comment ?
345 int count = Convert.ToInt32(sr.ReadLine()); // Item count
346 557
347 for (int i = 0 ; i < count ; i++) 558 UUID specMap = mat["SpecMap"].AsUUID();
348 { 559 if (specMap != UUID.Zero)
349 string type = sr.ReadLine(); 560 GatheredUuids[specMap] = (sbyte)AssetType.Texture;
350 if (type == null)
351 break;
352 string name = sr.ReadLine();
353 if (name == null)
354 break;
355 string id = sr.ReadLine();
356 if (id == null)
357 break;
358 string unknown = sr.ReadLine();
359 if (unknown == null)
360 break;
361
362 // If it can be parsed as a UUID, it is an asset ID
363 UUID uuid;
364 if (UUID.TryParse(id, out uuid))
365 assetUuids[uuid] = AssetType.Animation;
366 }
367 } 561 }
368 } 562 }
369 563
@@ -374,7 +568,10 @@ namespace OpenSim.Region.Framework.Scenes
374 protected string m_assetServerURL; 568 protected string m_assetServerURL;
375 569
376 public HGUuidGatherer(IAssetService assetService, string assetServerURL) 570 public HGUuidGatherer(IAssetService assetService, string assetServerURL)
377 : base(assetService) 571 : this(assetService, assetServerURL, new Dictionary<UUID, sbyte>()) {}
572
573 public HGUuidGatherer(IAssetService assetService, string assetServerURL, IDictionary<UUID, sbyte> collector)
574 : base(assetService, collector)
378 { 575 {
379 m_assetServerURL = assetServerURL; 576 m_assetServerURL = assetServerURL;
380 if (!m_assetServerURL.EndsWith("/") && !m_assetServerURL.EndsWith("=")) 577 if (!m_assetServerURL.EndsWith("/") && !m_assetServerURL.EndsWith("="))
@@ -391,7 +588,6 @@ namespace OpenSim.Region.Framework.Scenes
391 588
392 public AssetBase FetchAsset(UUID assetID) 589 public AssetBase FetchAsset(UUID assetID)
393 { 590 {
394
395 // Test if it's already here 591 // Test if it's already here
396 AssetBase asset = m_assetService.Get(assetID.ToString()); 592 AssetBase asset = m_assetService.Get(assetID.ToString());
397 if (asset == null) 593 if (asset == null)