diff options
author | David Walter Seikel | 2016-11-03 21:44:39 +1000 |
---|---|---|
committer | David Walter Seikel | 2016-11-03 21:44:39 +1000 |
commit | 134f86e8d5c414409631b25b8c6f0ee45fbd8631 (patch) | |
tree | 216b89d3fb89acfb81be1e440c25c41ab09fa96d /OpenSim/Region/Framework/Scenes | |
parent | More changing to production grid. Double oops. (diff) | |
download | opensim-SC-134f86e8d5c414409631b25b8c6f0ee45fbd8631.zip opensim-SC-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.gz opensim-SC-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.bz2 opensim-SC-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.xz |
Initial update to OpenSim 0.8.2.1 source code.
Diffstat (limited to '')
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 | ||
28 | using System.Collections.Generic; | ||
29 | using OpenSim.Data; | ||
28 | using OpenMetaverse; | 30 | using OpenMetaverse; |
29 | 31 | ||
30 | namespace OpenSim.Region.Framework.Scenes.Scripting | 32 | namespace 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 | ||
28 | using System; | 28 | using System; |
29 | using OpenMetaverse; | 29 | using System.Collections.Generic; |
30 | using log4net; | 30 | using System.Collections.Specialized; |
31 | using System.Reflection; | 31 | using System.Linq; |
32 | using OpenSim.Framework; | 32 | using System.Net; |
33 | 33 | ||
34 | namespace OpenSim.Region.Framework.Scenes.Scripting | 34 | namespace 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 @@ | |||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Reflection; | 30 | using System.Reflection; |
31 | using System.Text; | ||
31 | using log4net; | 32 | using log4net; |
32 | using OpenMetaverse; | 33 | using OpenMetaverse; |
34 | using OpenMetaverse.StructuredData; | ||
35 | |||
33 | using OpenSim.Framework; | 36 | using OpenSim.Framework; |
34 | 37 | ||
35 | using Animation = OpenSim.Framework.Animation; | 38 | using 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; | |||
35 | using OpenSim.Framework; | 35 | using OpenSim.Framework; |
36 | using OpenSim.Region.Framework.Interfaces; | 36 | using OpenSim.Region.Framework.Interfaces; |
37 | using OpenSim.Region.Framework.Scenes; | 37 | using OpenSim.Region.Framework.Scenes; |
38 | using OpenSim.Region.Physics.Manager; | 38 | using OpenSim.Region.PhysicsModules.SharedBase; |
39 | 39 | ||
40 | namespace OpenSim.Region.Framework.Scenes.Animation | 40 | namespace 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; | |||
33 | namespace OpenSim.Region.Framework.Scenes | 33 | namespace 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 | |||
28 | using System; | ||
29 | using System.Timers; | ||
30 | using System.Collections; | ||
31 | using System.Collections.Generic; | ||
32 | using System.IO; | ||
33 | using System.Diagnostics; | ||
34 | using System.Reflection; | ||
35 | using System.Threading; | ||
36 | using OpenMetaverse; | ||
37 | using OpenSim.Framework; | ||
38 | using OpenSim.Region.Framework.Interfaces; | ||
39 | using OpenSim.Region.PhysicsModules.SharedBase; | ||
40 | using OpenSim.Region.Framework.Scenes.Serialization; | ||
41 | using System.Runtime.Serialization.Formatters.Binary; | ||
42 | using System.Runtime.Serialization; | ||
43 | using Timer = System.Timers.Timer; | ||
44 | using log4net; | ||
45 | |||
46 | namespace 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; | |||
31 | using Nini.Config; | 31 | using Nini.Config; |
32 | using OpenSim.Framework; | 32 | using OpenSim.Framework; |
33 | using OpenMetaverse; | 33 | using OpenMetaverse; |
34 | using OpenSim.Region.Physics.Manager; | 34 | using 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; | |||
35 | using OpenMetaverse; | 35 | using OpenMetaverse; |
36 | using OpenMetaverse.StructuredData; | 36 | using OpenMetaverse.StructuredData; |
37 | using OpenSim.Framework; | 37 | using OpenSim.Framework; |
38 | using OpenSim.Framework.Communications; | ||
39 | using OpenSim.Framework.Console; | 38 | using OpenSim.Framework.Console; |
40 | using OpenSim.Framework.Servers; | 39 | using OpenSim.Framework.Servers; |
41 | using OpenSim.Framework.Servers.HttpServer; | 40 | using OpenSim.Framework.Servers.HttpServer; |
@@ -46,47 +45,33 @@ using OpenSim.Region.Framework.Scenes; | |||
46 | 45 | ||
47 | namespace OpenSim.Region.Framework.Scenes | 46 | namespace 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; | |||
30 | using System.Collections; | 30 | using System.Collections; |
31 | using System.Reflection; | 31 | using System.Reflection; |
32 | using System.Text; | 32 | using System.Text; |
33 | using System.Threading; | ||
33 | using System.Timers; | 34 | using System.Timers; |
35 | using System.Xml; | ||
34 | using OpenMetaverse; | 36 | using OpenMetaverse; |
35 | using OpenMetaverse.Packets; | 37 | using OpenMetaverse.Packets; |
36 | using log4net; | 38 | using log4net; |
37 | using OpenSim.Framework; | 39 | using OpenSim.Framework; |
40 | using OpenSim.Framework.Serialization.External; | ||
38 | using OpenSim.Region.Framework; | 41 | using OpenSim.Region.Framework; |
39 | using OpenSim.Framework.Client; | 42 | using OpenSim.Framework.Client; |
40 | using OpenSim.Region.Framework.Interfaces; | 43 | using OpenSim.Region.Framework.Interfaces; |
41 | using OpenSim.Region.Framework.Scenes.Serialization; | 44 | using OpenSim.Region.Framework.Scenes.Serialization; |
45 | using OpenSim.Services.Interfaces; | ||
46 | using PermissionMask = OpenSim.Framework.PermissionMask; | ||
42 | 47 | ||
43 | namespace OpenSim.Region.Framework.Scenes | 48 | namespace 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; | |||
31 | using OpenMetaverse; | 31 | using OpenMetaverse; |
32 | using OpenMetaverse.Packets; | 32 | using OpenMetaverse.Packets; |
33 | using OpenSim.Framework; | 33 | using OpenSim.Framework; |
34 | using OpenSim.Framework.Communications; | ||
35 | using OpenSim.Services.Interfaces; | 34 | using OpenSim.Services.Interfaces; |
36 | 35 | ||
37 | namespace OpenSim.Region.Framework.Scenes | 36 | namespace 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; | |||
39 | using OpenMetaverse; | 39 | using OpenMetaverse; |
40 | using OpenMetaverse.Packets; | 40 | using OpenMetaverse.Packets; |
41 | using OpenMetaverse.Imaging; | 41 | using OpenMetaverse.Imaging; |
42 | using OpenMetaverse.StructuredData; | ||
42 | using OpenSim.Framework; | 43 | using OpenSim.Framework; |
43 | using OpenSim.Framework.Monitoring; | 44 | using OpenSim.Framework.Monitoring; |
44 | using OpenSim.Services.Interfaces; | 45 | using OpenSim.Services.Interfaces; |
45 | using OpenSim.Framework.Communications; | ||
46 | using OpenSim.Framework.Console; | 46 | using OpenSim.Framework.Console; |
47 | using OpenSim.Region.Framework.Interfaces; | 47 | using OpenSim.Region.Framework.Interfaces; |
48 | using OpenSim.Region.Framework.Scenes.Scripting; | 48 | using OpenSim.Region.Framework.Scenes.Scripting; |
49 | using OpenSim.Region.Framework.Scenes.Serialization; | 49 | using OpenSim.Region.Framework.Scenes.Serialization; |
50 | using OpenSim.Region.Physics.Manager; | 50 | using OpenSim.Region.PhysicsModules.SharedBase; |
51 | using Timer=System.Timers.Timer; | 51 | using Timer = System.Timers.Timer; |
52 | using TPFlags = OpenSim.Framework.Constants.TeleportFlags; | 52 | using TPFlags = OpenSim.Framework.Constants.TeleportFlags; |
53 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; | 53 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; |
54 | using PermissionMask = OpenSim.Framework.PermissionMask; | ||
54 | 55 | ||
55 | namespace OpenSim.Region.Framework.Scenes | 56 | namespace 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; | |||
35 | using log4net; | 35 | using log4net; |
36 | using OpenSim.Framework; | 36 | using OpenSim.Framework; |
37 | using OpenSim.Framework.Client; | 37 | using OpenSim.Framework.Client; |
38 | using OpenSim.Framework.Communications; | ||
39 | using OpenSim.Framework.Capabilities; | 38 | using OpenSim.Framework.Capabilities; |
40 | using OpenSim.Region.Framework.Interfaces; | 39 | using OpenSim.Region.Framework.Interfaces; |
41 | using OpenSim.Services.Interfaces; | 40 | using 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; | |||
34 | using log4net; | 34 | using log4net; |
35 | using OpenSim.Framework; | 35 | using OpenSim.Framework; |
36 | using OpenSim.Region.Framework.Scenes.Types; | 36 | using OpenSim.Region.Framework.Scenes.Types; |
37 | using OpenSim.Region.Physics.Manager; | 37 | using OpenSim.Region.PhysicsModules.SharedBase; |
38 | using OpenSim.Region.Framework.Interfaces; | 38 | using OpenSim.Region.Framework.Interfaces; |
39 | 39 | ||
40 | namespace OpenSim.Region.Framework.Scenes | 40 | namespace 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; | |||
34 | using OpenSim.Region.Framework.Interfaces; | 34 | using OpenSim.Region.Framework.Interfaces; |
35 | using System.Collections.Generic; | 35 | using System.Collections.Generic; |
36 | using System.Xml; | 36 | using System.Xml; |
37 | using PermissionMask = OpenSim.Framework.PermissionMask; | ||
37 | 38 | ||
38 | namespace OpenSim.Region.Framework.Scenes | 39 | namespace 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; | |||
38 | using OpenMetaverse.Packets; | 38 | using OpenMetaverse.Packets; |
39 | using OpenSim.Framework; | 39 | using OpenSim.Framework; |
40 | using OpenSim.Region.Framework.Interfaces; | 40 | using OpenSim.Region.Framework.Interfaces; |
41 | using OpenSim.Region.Physics.Manager; | 41 | using OpenSim.Region.PhysicsModules.SharedBase; |
42 | using OpenSim.Region.Framework.Scenes.Serialization; | 42 | using OpenSim.Region.Framework.Scenes.Serialization; |
43 | using PermissionMask = OpenSim.Framework.PermissionMask; | ||
44 | using OpenSim.Services.Interfaces; | ||
43 | 45 | ||
44 | namespace OpenSim.Region.Framework.Scenes | 46 | namespace 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; | |||
37 | using log4net; | 37 | using log4net; |
38 | using OpenMetaverse; | 38 | using OpenMetaverse; |
39 | using OpenMetaverse.Packets; | 39 | using OpenMetaverse.Packets; |
40 | using OpenMetaverse.StructuredData; | ||
40 | using OpenSim.Framework; | 41 | using OpenSim.Framework; |
41 | using OpenSim.Region.Framework.Interfaces; | 42 | using OpenSim.Region.Framework.Interfaces; |
42 | using OpenSim.Region.Framework.Scenes.Scripting; | 43 | using OpenSim.Region.Framework.Scenes.Scripting; |
43 | using OpenSim.Region.Framework.Scenes.Serialization; | 44 | using OpenSim.Region.Framework.Scenes.Serialization; |
44 | using OpenSim.Region.Physics.Manager; | 45 | using OpenSim.Region.PhysicsModules.SharedBase; |
46 | using PermissionMask = OpenSim.Framework.PermissionMask; | ||
45 | 47 | ||
46 | namespace OpenSim.Region.Framework.Scenes | 48 | namespace 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; | |||
38 | using OpenSim.Region.Framework.Interfaces; | 38 | using OpenSim.Region.Framework.Interfaces; |
39 | using OpenSim.Region.Framework.Scenes.Scripting; | 39 | using OpenSim.Region.Framework.Scenes.Scripting; |
40 | using OpenSim.Region.Framework.Scenes.Serialization; | 40 | using OpenSim.Region.Framework.Scenes.Serialization; |
41 | using PermissionMask = OpenSim.Framework.PermissionMask; | ||
41 | 42 | ||
42 | namespace OpenSim.Region.Framework.Scenes | 43 | namespace 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; | |||
29 | using System.Xml; | 29 | using System.Xml; |
30 | using System.Collections.Generic; | 30 | using System.Collections.Generic; |
31 | using System.Reflection; | 31 | using System.Reflection; |
32 | using System.Threading; | ||
32 | using System.Timers; | 33 | using System.Timers; |
34 | using Timer = System.Timers.Timer; | ||
33 | using OpenMetaverse; | 35 | using OpenMetaverse; |
34 | using log4net; | 36 | using log4net; |
35 | using Nini.Config; | 37 | using Nini.Config; |
36 | using OpenSim.Framework; | 38 | using OpenSim.Framework; |
37 | using OpenSim.Framework.Client; | 39 | using OpenSim.Framework.Client; |
40 | using OpenSim.Framework.Monitoring; | ||
38 | using OpenSim.Region.Framework.Interfaces; | 41 | using OpenSim.Region.Framework.Interfaces; |
39 | using OpenSim.Region.Framework.Scenes.Animation; | 42 | using OpenSim.Region.Framework.Scenes.Animation; |
40 | using OpenSim.Region.Framework.Scenes.Types; | 43 | using OpenSim.Region.Framework.Scenes.Types; |
41 | using OpenSim.Region.Physics.Manager; | 44 | using OpenSim.Region.PhysicsModules.SharedBase; |
42 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; | 45 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; |
43 | using OpenSim.Services.Interfaces; | 46 | using OpenSim.Services.Interfaces; |
44 | using TeleportFlags = OpenSim.Framework.Constants.TeleportFlags; | 47 | using 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 | |||
28 | using System; | ||
29 | |||
30 | namespace 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 | |||
30 | namespace 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 */ | ||
29 | using System; | ||
30 | using System.IO; | ||
31 | using System.Reflection; | ||
32 | using log4net; | ||
33 | |||
34 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using OpenMetaverse; | ||
31 | using OpenSim.Framework; | ||
32 | |||
33 | namespace 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; | |||
38 | using OpenSim.Framework.Serialization.External; | 38 | using OpenSim.Framework.Serialization.External; |
39 | using OpenSim.Region.Framework.Interfaces; | 39 | using OpenSim.Region.Framework.Interfaces; |
40 | using OpenSim.Region.Framework.Scenes; | 40 | using OpenSim.Region.Framework.Scenes; |
41 | using OpenSim.Services.Interfaces; | ||
41 | 42 | ||
42 | namespace OpenSim.Region.Framework.Scenes.Serialization | 43 | namespace 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; | |||
34 | using log4net; | 34 | using log4net; |
35 | using OpenSim.Framework; | 35 | using OpenSim.Framework; |
36 | using OpenSim.Region.Framework.Scenes; | 36 | using OpenSim.Region.Framework.Scenes; |
37 | using OpenSim.Region.Physics.Manager; | 37 | using OpenSim.Region.PhysicsModules.SharedBase; |
38 | 38 | ||
39 | namespace OpenSim.Region.Framework.Scenes.Serialization | 39 | namespace 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 | ||
28 | using OpenSim.Framework; | ||
29 | using OpenSim.Region.Framework.Interfaces; | ||
30 | using System; | 28 | using System; |
29 | using System.IO; | ||
31 | using System.Text; | 30 | using System.Text; |
31 | using System.Reflection; | ||
32 | using System.Xml; | 32 | using System.Xml; |
33 | using System.IO; | ||
34 | using System.Xml.Serialization; | 33 | using System.Xml.Serialization; |
35 | 34 | ||
35 | using OpenSim.Data; | ||
36 | using OpenSim.Framework; | ||
37 | using OpenSim.Region.Framework.Interfaces; | ||
38 | |||
39 | using OpenMetaverse; | ||
40 | |||
41 | using log4net; | ||
42 | |||
36 | namespace OpenSim.Region.Framework.Scenes | 43 | namespace 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 | |||
32 | using System; | ||
33 | using System.Reflection; | ||
34 | |||
35 | using log4net; | ||
36 | |||
37 | using OpenSim.Framework; | ||
38 | using OpenSim.Region.Framework; | ||
39 | using OpenSim.Region.Framework.Scenes; | ||
40 | |||
41 | using OpenMetaverse; | ||
42 | using OpenMetaverse.Packets; | ||
43 | |||
44 | namespace 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; | |||
34 | using NUnit.Framework; | 34 | using NUnit.Framework; |
35 | using OpenMetaverse; | 35 | using OpenMetaverse; |
36 | using OpenSim.Framework; | 36 | using OpenSim.Framework; |
37 | using OpenSim.Framework.Communications; | ||
38 | using OpenSim.Region.Framework.Scenes; | 37 | using OpenSim.Region.Framework.Scenes; |
39 | using OpenSim.Tests.Common; | 38 | using 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; | |||
32 | using NUnit.Framework; | 32 | using NUnit.Framework; |
33 | using OpenMetaverse; | 33 | using OpenMetaverse; |
34 | using OpenSim.Framework; | 34 | using OpenSim.Framework; |
35 | using OpenSim.Framework.Communications; | ||
36 | using OpenSim.Region.Framework.Scenes; | 35 | using OpenSim.Region.Framework.Scenes; |
37 | using OpenSim.Tests.Common; | 36 | using OpenSim.Tests.Common; |
38 | using OpenSim.Tests.Common.Mock; | ||
39 | 37 | ||
40 | namespace OpenSim.Region.Framework.Scenes.Tests | 38 | namespace 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; | |||
32 | using NUnit.Framework; | 32 | using NUnit.Framework; |
33 | using OpenMetaverse; | 33 | using OpenMetaverse; |
34 | using OpenSim.Framework; | 34 | using OpenSim.Framework; |
35 | using OpenSim.Framework.Communications; | ||
36 | using OpenSim.Region.Framework.Scenes; | 35 | using OpenSim.Region.Framework.Scenes; |
37 | using OpenSim.Services.Interfaces; | 36 | using OpenSim.Services.Interfaces; |
38 | using OpenSim.Tests.Common; | 37 | using OpenSim.Tests.Common; |
39 | using OpenSim.Tests.Common.Mock; | ||
40 | 38 | ||
41 | namespace OpenSim.Region.Framework.Scenes.Tests | 39 | namespace 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; | |||
33 | using NUnit.Framework; | 33 | using NUnit.Framework; |
34 | using OpenMetaverse; | 34 | using OpenMetaverse; |
35 | using OpenSim.Framework; | 35 | using OpenSim.Framework; |
36 | using OpenSim.Framework.Communications; | ||
37 | using OpenSim.Region.Framework.Scenes; | 36 | using OpenSim.Region.Framework.Scenes; |
38 | using OpenSim.Services.Interfaces; | 37 | using OpenSim.Services.Interfaces; |
39 | using OpenSim.Tests.Common; | 38 | using OpenSim.Tests.Common; |
40 | using OpenSim.Tests.Common.Mock; | ||
41 | 39 | ||
42 | namespace OpenSim.Region.Framework.Scenes.Tests | 40 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Reflection; | ||
31 | using Nini.Config; | ||
32 | using NUnit.Framework; | ||
33 | using OpenMetaverse; | ||
34 | using OpenSim.Framework; | ||
35 | using OpenSim.Region.CoreModules.Framework.EntityTransfer; | ||
36 | using OpenSim.Region.CoreModules.Framework.InventoryAccess; | ||
37 | using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; | ||
38 | using OpenSim.Region.CoreModules.World.Permissions; | ||
39 | using OpenSim.Region.Framework.Scenes; | ||
40 | using OpenSim.Services.Interfaces; | ||
41 | using OpenSim.Tests.Common; | ||
42 | |||
43 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using Nini.Config; | ||
31 | using NUnit.Framework; | ||
32 | using OpenMetaverse; | ||
33 | using OpenSim.Framework; | ||
34 | using OpenSim.Region.CoreModules.Framework; | ||
35 | using OpenSim.Region.CoreModules.Framework.EntityTransfer; | ||
36 | using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; | ||
37 | using OpenSim.Region.CoreModules.World.Land; | ||
38 | using OpenSim.Region.OptionalModules; | ||
39 | using OpenSim.Tests.Common; | ||
40 | |||
41 | namespace 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; | |||
32 | using NUnit.Framework; | 32 | using NUnit.Framework; |
33 | using OpenMetaverse; | 33 | using OpenMetaverse; |
34 | using OpenSim.Framework; | 34 | using OpenSim.Framework; |
35 | using OpenSim.Framework.Communications; | 35 | using OpenSim.Region.CoreModules.Framework.EntityTransfer; |
36 | using OpenSim.Region.CoreModules.Framework.InventoryAccess; | 36 | using OpenSim.Region.CoreModules.Framework.InventoryAccess; |
37 | using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; | ||
37 | using OpenSim.Region.CoreModules.World.Permissions; | 38 | using OpenSim.Region.CoreModules.World.Permissions; |
38 | using OpenSim.Region.Framework.Scenes; | 39 | using OpenSim.Region.Framework.Scenes; |
39 | using OpenSim.Services.Interfaces; | 40 | using OpenSim.Services.Interfaces; |
40 | using OpenSim.Tests.Common; | 41 | using OpenSim.Tests.Common; |
41 | using OpenSim.Tests.Common.Mock; | ||
42 | 42 | ||
43 | namespace OpenSim.Region.Framework.Scenes.Tests | 43 | namespace 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; | |||
31 | using NUnit.Framework; | 31 | using NUnit.Framework; |
32 | using OpenMetaverse; | 32 | using OpenMetaverse; |
33 | using OpenSim.Framework; | 33 | using OpenSim.Framework; |
34 | using OpenSim.Framework.Communications; | ||
35 | using OpenSim.Region.Framework.Scenes; | 34 | using OpenSim.Region.Framework.Scenes; |
36 | using OpenSim.Tests.Common; | 35 | using OpenSim.Tests.Common; |
37 | using OpenSim.Tests.Common.Mock; | ||
38 | using log4net; | 36 | using log4net; |
39 | 37 | ||
40 | namespace OpenSim.Region.Framework.Scenes.Tests | 38 | namespace 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; | |||
30 | using NUnit.Framework; | 30 | using NUnit.Framework; |
31 | using OpenMetaverse; | 31 | using OpenMetaverse; |
32 | using OpenSim.Framework; | 32 | using OpenSim.Framework; |
33 | using OpenSim.Framework.Communications; | ||
34 | using OpenSim.Region.Framework.Scenes; | 33 | using OpenSim.Region.Framework.Scenes; |
35 | using OpenSim.Tests.Common; | 34 | using OpenSim.Tests.Common; |
36 | using OpenSim.Tests.Common.Mock; | ||
37 | 35 | ||
38 | namespace OpenSim.Region.Framework.Scenes.Tests | 36 | namespace 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; | |||
31 | using NUnit.Framework; | 31 | using NUnit.Framework; |
32 | using OpenMetaverse; | 32 | using OpenMetaverse; |
33 | using OpenSim.Framework; | 33 | using OpenSim.Framework; |
34 | using OpenSim.Framework.Communications; | ||
35 | using OpenSim.Region.Framework.Interfaces; | 34 | using OpenSim.Region.Framework.Interfaces; |
36 | using OpenSim.Region.Framework.Scenes; | 35 | using OpenSim.Region.Framework.Scenes; |
37 | using OpenSim.Tests.Common; | 36 | using OpenSim.Tests.Common; |
38 | using OpenSim.Tests.Common.Mock; | ||
39 | 37 | ||
40 | namespace OpenSim.Region.Framework.Scenes.Tests | 38 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Reflection; | ||
31 | using System.Threading; | ||
32 | using System.Xml; | ||
33 | using System.Linq; | ||
34 | using Nini.Config; | ||
35 | using NUnit.Framework; | ||
36 | using OpenMetaverse; | ||
37 | using OpenSim.Framework; | ||
38 | using OpenSim.Framework.Serialization.External; | ||
39 | using OpenSim.Region.Framework.Scenes; | ||
40 | using OpenSim.Region.Framework.Scenes.Serialization; | ||
41 | using OpenSim.Services.Interfaces; | ||
42 | using OpenSim.Tests.Common; | ||
43 | |||
44 | namespace 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; | |||
31 | using NUnit.Framework; | 31 | using NUnit.Framework; |
32 | using OpenMetaverse; | 32 | using OpenMetaverse; |
33 | using OpenSim.Framework; | 33 | using OpenSim.Framework; |
34 | using OpenSim.Framework.Communications; | ||
35 | using OpenSim.Region.Framework.Scenes; | 34 | using OpenSim.Region.Framework.Scenes; |
36 | using OpenSim.Tests.Common; | 35 | using OpenSim.Tests.Common; |
37 | using OpenSim.Tests.Common.Mock; | ||
38 | 36 | ||
39 | namespace OpenSim.Region.Framework.Scenes.Tests | 37 | namespace 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; | |||
31 | using NUnit.Framework; | 31 | using NUnit.Framework; |
32 | using OpenMetaverse; | 32 | using OpenMetaverse; |
33 | using OpenSim.Framework; | 33 | using OpenSim.Framework; |
34 | using OpenSim.Framework.Communications; | ||
35 | using OpenSim.Region.Framework.Scenes; | 34 | using OpenSim.Region.Framework.Scenes; |
36 | using OpenSim.Tests.Common; | 35 | using OpenSim.Tests.Common; |
37 | using OpenSim.Tests.Common.Mock; | ||
38 | 36 | ||
39 | namespace OpenSim.Region.Framework.Scenes.Tests | 37 | namespace 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; | |||
30 | using NUnit.Framework; | 30 | using NUnit.Framework; |
31 | using OpenMetaverse; | 31 | using OpenMetaverse; |
32 | using OpenSim.Framework; | 32 | using OpenSim.Framework; |
33 | using OpenSim.Framework.Communications; | ||
34 | using OpenSim.Region.Framework.Scenes; | 33 | using OpenSim.Region.Framework.Scenes; |
35 | using OpenSim.Tests.Common; | 34 | using OpenSim.Tests.Common; |
36 | using OpenSim.Tests.Common.Mock; | ||
37 | 35 | ||
38 | namespace OpenSim.Region.Framework.Scenes.Tests | 36 | namespace 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; | |||
32 | using NUnit.Framework; | 32 | using NUnit.Framework; |
33 | using OpenMetaverse; | 33 | using OpenMetaverse; |
34 | using OpenSim.Framework; | 34 | using OpenSim.Framework; |
35 | using OpenSim.Framework.Communications; | ||
36 | using OpenSim.Region.CoreModules.Avatar.InstantMessage; | 35 | using OpenSim.Region.CoreModules.Avatar.InstantMessage; |
37 | using OpenSim.Region.CoreModules.World.Permissions; | 36 | using OpenSim.Region.CoreModules.World.Permissions; |
38 | using OpenSim.Region.Framework.Interfaces; | 37 | using OpenSim.Region.Framework.Interfaces; |
39 | using OpenSim.Region.Framework.Scenes; | 38 | using OpenSim.Region.Framework.Scenes; |
40 | using OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups; | 39 | using OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups; |
41 | using OpenSim.Tests.Common; | 40 | using OpenSim.Tests.Common; |
42 | using OpenSim.Tests.Common.Mock; | ||
43 | 41 | ||
44 | namespace OpenSim.Region.Framework.Scenes.Tests | 42 | namespace 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; | |||
36 | using NUnit.Framework; | 36 | using NUnit.Framework; |
37 | using OpenMetaverse; | 37 | using OpenMetaverse; |
38 | using OpenSim.Framework; | 38 | using OpenSim.Framework; |
39 | using OpenSim.Framework.Communications; | ||
40 | using OpenSim.Region.Framework.Scenes; | 39 | using OpenSim.Region.Framework.Scenes; |
41 | using OpenSim.Region.Framework.Interfaces; | 40 | using OpenSim.Region.Framework.Interfaces; |
42 | using OpenSim.Region.ClientStack.Linden; | 41 | using OpenSim.Region.ClientStack.Linden; |
@@ -44,7 +43,6 @@ using OpenSim.Region.CoreModules.Framework.EntityTransfer; | |||
44 | using OpenSim.Region.CoreModules.World.Serialiser; | 43 | using OpenSim.Region.CoreModules.World.Serialiser; |
45 | using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; | 44 | using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; |
46 | using OpenSim.Tests.Common; | 45 | using OpenSim.Tests.Common; |
47 | using OpenSim.Tests.Common.Mock; | ||
48 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; | 46 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; |
49 | 47 | ||
50 | namespace OpenSim.Region.Framework.Scenes.Tests | 48 | namespace 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; | |||
35 | using NUnit.Framework; | 35 | using NUnit.Framework; |
36 | using OpenMetaverse; | 36 | using OpenMetaverse; |
37 | using OpenSim.Framework; | 37 | using OpenSim.Framework; |
38 | using OpenSim.Framework.Communications; | ||
39 | using OpenSim.Region.Framework.Scenes; | 38 | using OpenSim.Region.Framework.Scenes; |
40 | using OpenSim.Region.Framework.Interfaces; | 39 | using OpenSim.Region.Framework.Interfaces; |
41 | using OpenSim.Region.CoreModules.Framework.EntityTransfer; | 40 | using OpenSim.Region.CoreModules.Framework.EntityTransfer; |
42 | using OpenSim.Region.CoreModules.World.Serialiser; | 41 | using OpenSim.Region.CoreModules.World.Serialiser; |
43 | using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; | 42 | using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; |
44 | using OpenSim.Region.Physics.Manager; | 43 | using OpenSim.Region.PhysicsModules.SharedBase; |
45 | using OpenSim.Tests.Common; | 44 | using OpenSim.Tests.Common; |
46 | using OpenSim.Tests.Common.Mock; | ||
47 | 45 | ||
48 | namespace OpenSim.Region.Framework.Scenes.Tests | 46 | namespace 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; | |||
33 | using NUnit.Framework; | 33 | using NUnit.Framework; |
34 | using OpenMetaverse; | 34 | using OpenMetaverse; |
35 | using OpenSim.Framework; | 35 | using OpenSim.Framework; |
36 | using OpenSim.Framework.Communications; | ||
37 | using OpenSim.Region.Framework.Interfaces; | 36 | using OpenSim.Region.Framework.Interfaces; |
38 | using OpenSim.Region.Framework.Scenes; | 37 | using OpenSim.Region.Framework.Scenes; |
39 | using OpenSim.Tests.Common; | 38 | using OpenSim.Tests.Common; |
40 | using OpenSim.Tests.Common.Mock; | ||
41 | 39 | ||
42 | namespace OpenSim.Region.Framework.Scenes.Tests | 40 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Reflection; | ||
31 | using System.Text; | ||
32 | using System.Threading; | ||
33 | using System.Timers; | ||
34 | using Timer = System.Timers.Timer; | ||
35 | using Nini.Config; | ||
36 | using NUnit.Framework; | ||
37 | using OpenMetaverse; | ||
38 | using OpenSim.Framework; | ||
39 | using OpenSim.Framework.Servers; | ||
40 | using OpenSim.Framework.Servers.HttpServer; | ||
41 | using OpenSim.Region.ClientStack.Linden; | ||
42 | using OpenSim.Region.CoreModules.Framework; | ||
43 | using OpenSim.Region.CoreModules.Framework.EntityTransfer; | ||
44 | using OpenSim.Region.CoreModules.World.Serialiser; | ||
45 | using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; | ||
46 | using OpenSim.Region.Framework.Scenes; | ||
47 | using OpenSim.Region.Framework.Interfaces; | ||
48 | using OpenSim.Tests.Common; | ||
49 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; | ||
50 | |||
51 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Reflection; | ||
31 | using Nini.Config; | ||
32 | using NUnit.Framework; | ||
33 | using OpenMetaverse; | ||
34 | using OpenSim.Framework; | ||
35 | using OpenSim.Framework.Servers; | ||
36 | using OpenSim.Region.Framework.Interfaces; | ||
37 | using OpenSim.Region.CoreModules.Framework; | ||
38 | using OpenSim.Region.CoreModules.Framework.EntityTransfer; | ||
39 | using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; | ||
40 | using OpenSim.Region.CoreModules.World.Permissions; | ||
41 | using OpenSim.Tests.Common; | ||
42 | |||
43 | namespace 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; | |||
32 | using NUnit.Framework; | 32 | using NUnit.Framework; |
33 | using OpenMetaverse; | 33 | using OpenMetaverse; |
34 | using OpenSim.Framework; | 34 | using OpenSim.Framework; |
35 | using OpenSim.Framework.Communications; | ||
36 | using OpenSim.Framework.Servers; | 35 | using OpenSim.Framework.Servers; |
37 | using OpenSim.Region.Framework.Interfaces; | 36 | using OpenSim.Region.Framework.Interfaces; |
38 | using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; | 37 | using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; |
39 | using OpenSim.Tests.Common; | 38 | using OpenSim.Tests.Common; |
40 | using OpenSim.Tests.Common.Mock; | ||
41 | using System.Threading; | 39 | using System.Threading; |
42 | 40 | ||
43 | namespace OpenSim.Region.Framework.Scenes.Tests | 41 | namespace 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 | ||
28 | using System; | 28 | using System; |
29 | using System.Reflection; | 29 | using System.Collections.Generic; |
30 | using System.IO; | ||
31 | using System.Net; | ||
32 | using System.Text; | ||
33 | using System.Threading; | ||
30 | using Nini.Config; | 34 | using Nini.Config; |
31 | using NUnit.Framework; | 35 | using NUnit.Framework; |
32 | using OpenMetaverse; | 36 | using OpenMetaverse; |
33 | using OpenSim.Framework; | 37 | using OpenSim.Framework; |
34 | using OpenSim.Framework.Communications; | ||
35 | using OpenSim.Framework.Servers; | 38 | using OpenSim.Framework.Servers; |
36 | using OpenSim.Region.Framework.Interfaces; | 39 | using OpenSim.Region.Framework.Interfaces; |
37 | using OpenSim.Region.CoreModules.Framework; | 40 | using OpenSim.Region.CoreModules.Framework; |
@@ -39,9 +42,6 @@ using OpenSim.Region.CoreModules.Framework.EntityTransfer; | |||
39 | using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; | 42 | using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; |
40 | using OpenSim.Region.CoreModules.World.Permissions; | 43 | using OpenSim.Region.CoreModules.World.Permissions; |
41 | using OpenSim.Tests.Common; | 44 | using OpenSim.Tests.Common; |
42 | using OpenSim.Tests.Common.Mock; | ||
43 | using System.IO; | ||
44 | using System.Text; | ||
45 | 45 | ||
46 | namespace OpenSim.Region.Framework.Scenes.Tests | 46 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Reflection; | ||
31 | using NUnit.Framework; | ||
32 | using OpenMetaverse; | ||
33 | using OpenSim.Framework; | ||
34 | using OpenSim.Region.Framework.Scenes; | ||
35 | using OpenSim.Tests.Common; | ||
36 | |||
37 | namespace 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 | |||
25 | using System; | ||
26 | using Nini.Config; | ||
27 | using NUnit.Framework; | ||
28 | using OpenMetaverse; | ||
29 | using OpenSim.Framework; | ||
30 | using OpenSim.Region.CoreModules.World.Estate; | ||
31 | using OpenSim.Region.Framework.Scenes; | ||
32 | using OpenSim.Region.Framework.Interfaces; | ||
33 | using OpenSim.Services.Interfaces; | ||
34 | using OpenSim.Tests.Common; | ||
35 | |||
36 | namespace 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; | |||
36 | using NUnit.Framework; | 36 | using NUnit.Framework; |
37 | using OpenMetaverse; | 37 | using OpenMetaverse; |
38 | using OpenSim.Framework; | 38 | using OpenSim.Framework; |
39 | using OpenSim.Framework.Communications; | ||
40 | using OpenSim.Region.Framework.Scenes; | 39 | using OpenSim.Region.Framework.Scenes; |
41 | using OpenSim.Region.Framework.Interfaces; | 40 | using OpenSim.Region.Framework.Interfaces; |
42 | using OpenSim.Region.CoreModules.World.Serialiser; | 41 | using OpenSim.Region.CoreModules.World.Serialiser; |
43 | using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; | 42 | using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; |
44 | using OpenSim.Tests.Common; | 43 | using OpenSim.Tests.Common; |
45 | using OpenSim.Tests.Common.Mock; | ||
46 | 44 | ||
47 | namespace OpenSim.Region.Framework.Scenes.Tests | 45 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Net; | ||
31 | using Mono.Addins; | ||
32 | using Nini.Config; | ||
33 | using NUnit.Framework; | ||
34 | using OpenMetaverse; | ||
35 | using OpenSim; | ||
36 | using OpenSim.ApplicationPlugins.RegionModulesController; | ||
37 | using OpenSim.Framework; | ||
38 | using OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid; | ||
39 | using OpenSim.Region.Framework.Interfaces; | ||
40 | using OpenSim.Tests.Common; | ||
41 | |||
42 | namespace 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; | |||
37 | using OpenMetaverse; | 37 | using OpenMetaverse; |
38 | using OpenMetaverse.Assets; | 38 | using OpenMetaverse.Assets; |
39 | using OpenSim.Framework; | 39 | using OpenSim.Framework; |
40 | using OpenSim.Framework.Communications; | ||
41 | using OpenSim.Region.Framework.Scenes; | 40 | using OpenSim.Region.Framework.Scenes; |
42 | using OpenSim.Region.Framework.Interfaces; | 41 | using OpenSim.Region.Framework.Interfaces; |
43 | using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver; | 42 | using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver; |
@@ -45,7 +44,6 @@ using OpenSim.Region.CoreModules.World.Serialiser; | |||
45 | using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; | 44 | using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; |
46 | using OpenSim.Services.Interfaces; | 45 | using OpenSim.Services.Interfaces; |
47 | using OpenSim.Tests.Common; | 46 | using OpenSim.Tests.Common; |
48 | using OpenSim.Tests.Common.Mock; | ||
49 | 47 | ||
50 | namespace OpenSim.Region.Framework.Tests | 48 | namespace 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; | |||
37 | using OpenMetaverse; | 37 | using OpenMetaverse; |
38 | using OpenMetaverse.Assets; | 38 | using OpenMetaverse.Assets; |
39 | using OpenSim.Framework; | 39 | using OpenSim.Framework; |
40 | using OpenSim.Framework.Communications; | ||
41 | using OpenSim.Region.Framework.Scenes; | 40 | using OpenSim.Region.Framework.Scenes; |
42 | using OpenSim.Region.Framework.Interfaces; | 41 | using OpenSim.Region.Framework.Interfaces; |
43 | using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver; | 42 | using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver; |
@@ -45,7 +44,6 @@ using OpenSim.Region.CoreModules.World.Serialiser; | |||
45 | using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; | 44 | using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; |
46 | using OpenSim.Services.Interfaces; | 45 | using OpenSim.Services.Interfaces; |
47 | using OpenSim.Tests.Common; | 46 | using OpenSim.Tests.Common; |
48 | using OpenSim.Tests.Common.Mock; | ||
49 | 47 | ||
50 | namespace OpenSim.Region.Framework.Tests | 48 | namespace 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; | |||
33 | using OpenSim.Region.Framework.Scenes; | 33 | using OpenSim.Region.Framework.Scenes; |
34 | using OpenSim.Services.Interfaces; | 34 | using OpenSim.Services.Interfaces; |
35 | using OpenSim.Tests.Common; | 35 | using OpenSim.Tests.Common; |
36 | using OpenSim.Tests.Common.Mock; | ||
37 | 36 | ||
38 | namespace OpenSim.Region.Framework.Scenes.Tests | 37 | namespace 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; | |||
34 | using log4net; | 34 | using log4net; |
35 | using OpenMetaverse; | 35 | using OpenMetaverse; |
36 | using OpenMetaverse.Assets; | 36 | using OpenMetaverse.Assets; |
37 | using OpenMetaverse.StructuredData; | ||
37 | using OpenSim.Framework; | 38 | using OpenSim.Framework; |
38 | using OpenSim.Region.Framework.Scenes.Serialization; | 39 | using OpenSim.Region.Framework.Scenes.Serialization; |
39 | using OpenSim.Services.Interfaces; | 40 | using OpenSim.Services.Interfaces; |
41 | using OpenSimAssetType = OpenSim.Framework.SLUtil.OpenSimAssetType; | ||
40 | 42 | ||
41 | namespace OpenSim.Region.Framework.Scenes | 43 | namespace 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) |