aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Framework/Scenes
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Framework/Scenes')
-rw-r--r--OpenSim/Region/Framework/Scenes/EventManager.cs24
-rw-r--r--OpenSim/Region/Framework/Scenes/KeyframeMotion.cs422
-rw-r--r--OpenSim/Region/Framework/Scenes/Prioritizer.cs4
-rw-r--r--OpenSim/Region/Framework/Scenes/SOPMaterial.cs95
-rw-r--r--OpenSim/Region/Framework/Scenes/SOPVehicle.cs742
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.Inventory.cs315
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs70
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs719
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneBase.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs37
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneGraph.cs479
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneManager.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs17
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs1349
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPart.cs1362
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs770
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresence.cs515
-rw-r--r--OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs122
-rw-r--r--OpenSim/Region/Framework/Scenes/SimStatsReporter.cs92
-rw-r--r--OpenSim/Region/Framework/Scenes/UndoState.cs367
-rw-r--r--OpenSim/Region/Framework/Scenes/UuidGatherer.cs4
21 files changed, 5875 insertions, 1634 deletions
diff --git a/OpenSim/Region/Framework/Scenes/EventManager.cs b/OpenSim/Region/Framework/Scenes/EventManager.cs
index ace8313..e88a623 100644
--- a/OpenSim/Region/Framework/Scenes/EventManager.cs
+++ b/OpenSim/Region/Framework/Scenes/EventManager.cs
@@ -55,8 +55,12 @@ namespace OpenSim.Region.Framework.Scenes
55 55
56 public delegate void OnTerrainTickDelegate(); 56 public delegate void OnTerrainTickDelegate();
57 57
58 public delegate void OnTerrainUpdateDelegate();
59
58 public event OnTerrainTickDelegate OnTerrainTick; 60 public event OnTerrainTickDelegate OnTerrainTick;
59 61
62 public event OnTerrainUpdateDelegate OnTerrainUpdate;
63
60 public delegate void OnBackupDelegate(ISimulationDataService datastore, bool forceBackup); 64 public delegate void OnBackupDelegate(ISimulationDataService datastore, bool forceBackup);
61 65
62 public event OnBackupDelegate OnBackup; 66 public event OnBackupDelegate OnBackup;
@@ -892,6 +896,26 @@ namespace OpenSim.Region.Framework.Scenes
892 } 896 }
893 } 897 }
894 } 898 }
899 public void TriggerTerrainUpdate()
900 {
901 OnTerrainUpdateDelegate handlerTerrainUpdate = OnTerrainUpdate;
902 if (handlerTerrainUpdate != null)
903 {
904 foreach (OnTerrainUpdateDelegate d in handlerTerrainUpdate.GetInvocationList())
905 {
906 try
907 {
908 d();
909 }
910 catch (Exception e)
911 {
912 m_log.ErrorFormat(
913 "[EVENT MANAGER]: Delegate for TriggerTerrainUpdate failed - continuing. {0} {1}",
914 e.Message, e.StackTrace);
915 }
916 }
917 }
918 }
895 919
896 public void TriggerTerrainTick() 920 public void TriggerTerrainTick()
897 { 921 {
diff --git a/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs
new file mode 100644
index 0000000..b7b0d27
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs
@@ -0,0 +1,422 @@
1// Proprietary code of Avination Virtual Limited
2// (c) 2012 Melanie Thielker
3//
4
5using System;
6using System.Timers;
7using System.Collections;
8using System.Collections.Generic;
9using System.IO;
10using System.Diagnostics;
11using System.Reflection;
12using System.Threading;
13using OpenMetaverse;
14using OpenSim.Framework;
15using OpenSim.Region.Framework.Interfaces;
16using OpenSim.Region.Physics.Manager;
17using OpenSim.Region.Framework.Scenes.Serialization;
18using System.Runtime.Serialization.Formatters.Binary;
19using System.Runtime.Serialization;
20using Timer = System.Timers.Timer;
21using log4net;
22
23namespace OpenSim.Region.Framework.Scenes
24{
25 [Serializable]
26 public class KeyframeMotion
27 {
28 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
29
30 public enum PlayMode : int
31 {
32 Forward = 0,
33 Reverse = 1,
34 Loop = 2,
35 PingPong = 3
36 };
37
38 [Flags]
39 public enum DataFormat : int
40 {
41 Translation = 1,
42 Rotation = 2
43 }
44
45 [Serializable]
46 public struct Keyframe
47 {
48 public Vector3? Position;
49 public Quaternion? Rotation;
50 public Quaternion StartRotation;
51 public int TimeMS;
52 public int TimeTotal;
53 public Vector3 AngularVelocity;
54 };
55
56 private Vector3 m_basePosition;
57 private Quaternion m_baseRotation;
58 private Vector3 m_serializedPosition;
59
60 private Keyframe m_currentFrame;
61 private List<Keyframe> m_frames = new List<Keyframe>();
62
63 private Keyframe[] m_keyframes;
64
65 [NonSerialized()]
66 protected Timer m_timer = new Timer();
67
68 [NonSerialized()]
69 private SceneObjectGroup m_group;
70
71 private PlayMode m_mode = PlayMode.Forward;
72 private DataFormat m_data = DataFormat.Translation | DataFormat.Rotation;
73
74 private bool m_running = false;
75 [NonSerialized()]
76 private bool m_selected = false;
77
78 private int m_iterations = 0;
79
80 private const double timerInterval = 50.0;
81
82 public DataFormat Data
83 {
84 get { return m_data; }
85 }
86
87 public bool Selected
88 {
89 set
90 {
91 if (value)
92 {
93 // Once we're let go, recompute positions
94 if (m_selected)
95 UpdateSceneObject(m_group);
96 }
97 else
98 {
99 // Save selection position in case we get moved
100 if (!m_selected)
101 m_serializedPosition = m_group.AbsolutePosition;
102 }
103 m_selected = value; }
104 }
105
106 public static KeyframeMotion FromData(SceneObjectGroup grp, Byte[] data)
107 {
108 MemoryStream ms = new MemoryStream(data);
109
110 BinaryFormatter fmt = new BinaryFormatter();
111
112 KeyframeMotion newMotion = (KeyframeMotion)fmt.Deserialize(ms);
113
114 // This will be started when position is updated
115 newMotion.m_timer = new Timer();
116 newMotion.m_timer.Interval = (int)timerInterval;
117 newMotion.m_timer.AutoReset = true;
118 newMotion.m_timer.Elapsed += newMotion.OnTimer;
119
120 return newMotion;
121 }
122
123 public void UpdateSceneObject(SceneObjectGroup grp)
124 {
125 m_group = grp;
126 Vector3 offset = grp.AbsolutePosition - m_serializedPosition;
127
128 m_basePosition += offset;
129 m_currentFrame.Position += offset;
130 for (int i = 0 ; i < m_frames.Count ; i++)
131 {
132 Keyframe k = m_frames[i];
133 k.Position += offset;
134 m_frames[i] = k;
135 }
136
137 if (m_running)
138 Start();
139 }
140
141 public KeyframeMotion(SceneObjectGroup grp, PlayMode mode, DataFormat data)
142 {
143 m_mode = mode;
144 m_data = data;
145
146 m_group = grp;
147 m_basePosition = grp.AbsolutePosition;
148 m_baseRotation = grp.GroupRotation;
149
150 m_timer.Interval = (int)timerInterval;
151 m_timer.AutoReset = true;
152 m_timer.Elapsed += OnTimer;
153 }
154
155 public void SetKeyframes(Keyframe[] frames)
156 {
157 m_keyframes = frames;
158 }
159
160 public void Start()
161 {
162 if (m_keyframes.Length > 0)
163 m_timer.Start();
164 m_running = true;
165 }
166
167 public void Stop()
168 {
169 // Failed object creation
170 if (m_timer == null)
171 return;
172 m_timer.Stop();
173
174 m_basePosition = m_group.AbsolutePosition;
175 m_baseRotation = m_group.GroupRotation;
176
177 m_group.RootPart.Velocity = Vector3.Zero;
178 m_group.RootPart.UpdateAngularVelocity(Vector3.Zero);
179 m_group.SendGroupRootTerseUpdate();
180
181 m_frames.Clear();
182 m_running = false;
183 }
184
185 public void Pause()
186 {
187 m_group.RootPart.Velocity = Vector3.Zero;
188 m_group.RootPart.UpdateAngularVelocity(Vector3.Zero);
189 m_group.SendGroupRootTerseUpdate();
190
191 m_timer.Stop();
192 m_running = false;
193 }
194
195 private void GetNextList()
196 {
197 m_frames.Clear();
198 Vector3 pos = m_basePosition;
199 Quaternion rot = m_baseRotation;
200
201 if (m_mode == PlayMode.Loop || m_mode == PlayMode.PingPong || m_iterations == 0)
202 {
203 int direction = 1;
204 if (m_mode == PlayMode.Reverse || ((m_mode == PlayMode.PingPong) && ((m_iterations & 1) != 0)))
205 direction = -1;
206
207 int start = 0;
208 int end = m_keyframes.Length;
209// if (m_mode == PlayMode.PingPong && m_keyframes.Length > 1)
210// end = m_keyframes.Length - 1;
211
212 if (direction < 0)
213 {
214 start = m_keyframes.Length - 1;
215 end = -1;
216// if (m_mode == PlayMode.PingPong && m_keyframes.Length > 1)
217// end = 0;
218 }
219
220 for (int i = start; i != end ; i += direction)
221 {
222 Keyframe k = m_keyframes[i];
223
224 if (k.Position.HasValue)
225 k.Position = (k.Position * direction) + pos;
226 else
227 k.Position = pos;
228
229 k.StartRotation = rot;
230 if (k.Rotation.HasValue)
231 {
232 if (direction == -1)
233 k.Rotation = Quaternion.Conjugate((Quaternion)k.Rotation);
234 k.Rotation = rot * k.Rotation;
235 }
236 else
237 {
238 k.Rotation = rot;
239 }
240
241 float angle = 0;
242
243 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;
244 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;
245 float aa_bb = aa * bb;
246
247 if (aa_bb == 0)
248 {
249 angle = 0;
250 }
251 else
252 {
253 float ab = k.StartRotation.X * ((Quaternion)k.Rotation).X +
254 k.StartRotation.Y * ((Quaternion)k.Rotation).Y +
255 k.StartRotation.Z * ((Quaternion)k.Rotation).Z +
256 k.StartRotation.W * ((Quaternion)k.Rotation).W;
257 float q = (ab * ab) / aa_bb;
258
259 if (q > 1.0f)
260 {
261 angle = 0;
262 }
263 else
264 {
265 angle = (float)Math.Acos(2 * q - 1);
266 }
267 }
268
269 k.AngularVelocity = (new Vector3(0, 0, 1) * (Quaternion)k.Rotation) * (angle / (k.TimeMS / 1000));
270 k.TimeTotal = k.TimeMS;
271
272 m_frames.Add(k);
273
274 pos = (Vector3)k.Position;
275 rot = (Quaternion)k.Rotation;
276 }
277
278 m_basePosition = pos;
279 m_baseRotation = rot;
280
281 m_iterations++;
282 }
283 }
284
285 protected void OnTimer(object sender, ElapsedEventArgs e)
286 {
287 if (m_frames.Count == 0)
288 {
289 GetNextList();
290
291 if (m_frames.Count == 0)
292 {
293 Stop();
294 return;
295 }
296
297 m_currentFrame = m_frames[0];
298 }
299
300 if (m_selected)
301 {
302 if (m_group.RootPart.Velocity != Vector3.Zero)
303 {
304 m_group.RootPart.Velocity = Vector3.Zero;
305 m_group.SendGroupRootTerseUpdate();
306 }
307 return;
308 }
309
310 // Do the frame processing
311 double steps = (double)m_currentFrame.TimeMS / timerInterval;
312 float complete = ((float)m_currentFrame.TimeTotal - (float)m_currentFrame.TimeMS) / (float)m_currentFrame.TimeTotal;
313
314 if (steps <= 1.0)
315 {
316 m_currentFrame.TimeMS = 0;
317
318 m_group.AbsolutePosition = (Vector3)m_currentFrame.Position;
319 m_group.UpdateGroupRotationR((Quaternion)m_currentFrame.Rotation);
320 }
321 else
322 {
323 Vector3 v = (Vector3)m_currentFrame.Position - m_group.AbsolutePosition;
324 Vector3 motionThisFrame = v / (float)steps;
325 v = v * 1000 / m_currentFrame.TimeMS;
326
327 bool update = false;
328
329 if (Vector3.Mag(motionThisFrame) >= 0.05f)
330 {
331 m_group.AbsolutePosition += motionThisFrame;
332 m_group.RootPart.Velocity = v;
333 update = true;
334 }
335
336 if ((Quaternion)m_currentFrame.Rotation != m_group.GroupRotation)
337 {
338 Quaternion current = m_group.GroupRotation;
339
340 Quaternion step = Quaternion.Slerp(m_currentFrame.StartRotation, (Quaternion)m_currentFrame.Rotation, complete);
341
342 float angle = 0;
343
344 float aa = current.X * current.X + current.Y * current.Y + current.Z * current.Z + current.W * current.W;
345 float bb = step.X * step.X + step.Y * step.Y + step.Z * step.Z + step.W * step.W;
346 float aa_bb = aa * bb;
347
348 if (aa_bb == 0)
349 {
350 angle = 0;
351 }
352 else
353 {
354 float ab = current.X * step.X +
355 current.Y * step.Y +
356 current.Z * step.Z +
357 current.W * step.W;
358 float q = (ab * ab) / aa_bb;
359
360 if (q > 1.0f)
361 {
362 angle = 0;
363 }
364 else
365 {
366 angle = (float)Math.Acos(2 * q - 1);
367 }
368 }
369
370 if (angle > 0.01f)
371 {
372 m_group.UpdateGroupRotationR(step);
373 //m_group.RootPart.UpdateAngularVelocity(m_currentFrame.AngularVelocity / 2);
374 update = true;
375 }
376 }
377
378 if (update)
379 m_group.SendGroupRootTerseUpdate();
380 }
381
382 m_currentFrame.TimeMS -= (int)timerInterval;
383
384 if (m_currentFrame.TimeMS <= 0)
385 {
386 m_group.RootPart.Velocity = Vector3.Zero;
387 m_group.RootPart.UpdateAngularVelocity(Vector3.Zero);
388 m_group.SendGroupRootTerseUpdate();
389
390 m_frames.RemoveAt(0);
391 if (m_frames.Count > 0)
392 m_currentFrame = m_frames[0];
393 }
394 }
395
396 public Byte[] Serialize()
397 {
398 MemoryStream ms = new MemoryStream();
399 m_timer.Stop();
400
401 BinaryFormatter fmt = new BinaryFormatter();
402 SceneObjectGroup tmp = m_group;
403 m_group = null;
404 m_serializedPosition = tmp.AbsolutePosition;
405 fmt.Serialize(ms, this);
406 m_group = tmp;
407 return ms.ToArray();
408 }
409
410 public void CrossingFailure()
411 {
412 // The serialization has stopped the timer, so let's wait a moment
413 // then retry the crossing. We'll get back here if it fails.
414 Util.FireAndForget(delegate (object x)
415 {
416 Thread.Sleep(60000);
417 if (m_running)
418 m_timer.Start();
419 });
420 }
421 }
422}
diff --git a/OpenSim/Region/Framework/Scenes/Prioritizer.cs b/OpenSim/Region/Framework/Scenes/Prioritizer.cs
index 1b10e3c..0a34a4c 100644
--- a/OpenSim/Region/Framework/Scenes/Prioritizer.cs
+++ b/OpenSim/Region/Framework/Scenes/Prioritizer.cs
@@ -157,7 +157,7 @@ namespace OpenSim.Region.Framework.Scenes
157 157
158 private uint GetPriorityByBestAvatarResponsiveness(IClientAPI client, ISceneEntity entity) 158 private uint GetPriorityByBestAvatarResponsiveness(IClientAPI client, ISceneEntity entity)
159 { 159 {
160 uint pqueue = ComputeDistancePriority(client,entity,true); 160 uint pqueue = ComputeDistancePriority(client,entity,false);
161 161
162 ScenePresence presence = m_scene.GetScenePresence(client.AgentId); 162 ScenePresence presence = m_scene.GetScenePresence(client.AgentId);
163 if (presence != null) 163 if (presence != null)
@@ -226,7 +226,7 @@ namespace OpenSim.Region.Framework.Scenes
226 226
227 for (int i = 0; i < queues - 1; i++) 227 for (int i = 0; i < queues - 1; i++)
228 { 228 {
229 if (distance < 10 * Math.Pow(2.0,i)) 229 if (distance < 30 * Math.Pow(2.0,i))
230 break; 230 break;
231 pqueue++; 231 pqueue++;
232 } 232 }
diff --git a/OpenSim/Region/Framework/Scenes/SOPMaterial.cs b/OpenSim/Region/Framework/Scenes/SOPMaterial.cs
new file mode 100644
index 0000000..10ac37c
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/SOPMaterial.cs
@@ -0,0 +1,95 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using OpenMetaverse;
31using OpenSim.Framework;
32
33namespace OpenSim.Region.Framework.Scenes
34{
35 public static class SOPMaterialData
36 {
37 public enum SopMaterial : int // redundante and not in use for now
38 {
39 Stone = 0,
40 Metal = 1,
41 Glass = 2,
42 Wood = 3,
43 Flesh = 4,
44 Plastic = 5,
45 Rubber = 6,
46 light = 7 // compatibility with old viewers
47 }
48
49 private struct MaterialData
50 {
51 public float friction;
52 public float bounce;
53 public MaterialData(float f, float b)
54 {
55 friction = f;
56 bounce = b;
57 }
58 }
59
60 private static MaterialData[] m_materialdata = {
61 new MaterialData(0.8f,0.4f), // Stone
62 new MaterialData(0.3f,0.4f), // Metal
63 new MaterialData(0.2f,0.7f), // Glass
64 new MaterialData(0.6f,0.5f), // Wood
65 new MaterialData(0.9f,0.3f), // Flesh
66 new MaterialData(0.4f,0.7f), // Plastic
67 new MaterialData(0.9f,0.95f), // Rubber
68 new MaterialData(0.0f,0.0f) // light ??
69 };
70
71 public static Material MaxMaterial
72 {
73 get { return (Material)(m_materialdata.Length - 1); }
74 }
75
76 public static float friction(Material material)
77 {
78 int indx = (int)material;
79 if (indx < m_materialdata.Length)
80 return (m_materialdata[indx].friction);
81 else
82 return 0;
83 }
84
85 public static float bounce(Material material)
86 {
87 int indx = (int)material;
88 if (indx < m_materialdata.Length)
89 return (m_materialdata[indx].bounce);
90 else
91 return 0;
92 }
93
94 }
95} \ No newline at end of file
diff --git a/OpenSim/Region/Framework/Scenes/SOPVehicle.cs b/OpenSim/Region/Framework/Scenes/SOPVehicle.cs
new file mode 100644
index 0000000..d3c2d27
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/SOPVehicle.cs
@@ -0,0 +1,742 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using OpenMetaverse;
31using OpenSim.Framework;
32using OpenSim.Region.Physics.Manager;
33using System.Xml;
34using OpenSim.Framework.Serialization;
35using OpenSim.Framework.Serialization.External;
36using OpenSim.Region.Framework.Scenes.Serialization;
37using OpenSim.Region.Framework.Scenes.Serialization;
38
39namespace OpenSim.Region.Framework.Scenes
40{
41 public class SOPVehicle
42 {
43 public VehicleData vd;
44
45 public Vehicle Type
46 {
47 get { return vd.m_type; }
48 }
49
50 public SOPVehicle()
51 {
52 vd = new VehicleData();
53 ProcessTypeChange(Vehicle.TYPE_NONE); // is needed?
54 }
55
56 public void ProcessFloatVehicleParam(Vehicle pParam, float pValue)
57 {
58 float len;
59 float timestep = 0.01f;
60 switch (pParam)
61 {
62 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY:
63 if (pValue < 0f) pValue = 0f;
64 if (pValue > 1f) pValue = 1f;
65 vd.m_angularDeflectionEfficiency = pValue;
66 break;
67 case Vehicle.ANGULAR_DEFLECTION_TIMESCALE:
68 if (pValue < timestep) pValue = timestep;
69 vd.m_angularDeflectionTimescale = pValue;
70 break;
71 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE:
72 if (pValue < timestep) pValue = timestep;
73 else if (pValue > 120) pValue = 120;
74 vd.m_angularMotorDecayTimescale = pValue;
75 break;
76 case Vehicle.ANGULAR_MOTOR_TIMESCALE:
77 if (pValue < timestep) pValue = timestep;
78 vd.m_angularMotorTimescale = pValue;
79 break;
80 case Vehicle.BANKING_EFFICIENCY:
81 if (pValue < -1f) pValue = -1f;
82 if (pValue > 1f) pValue = 1f;
83 vd.m_bankingEfficiency = pValue;
84 break;
85 case Vehicle.BANKING_MIX:
86 if (pValue < 0f) pValue = 0f;
87 if (pValue > 1f) pValue = 1f;
88 vd.m_bankingMix = pValue;
89 break;
90 case Vehicle.BANKING_TIMESCALE:
91 if (pValue < timestep) pValue = timestep;
92 vd.m_bankingTimescale = pValue;
93 break;
94 case Vehicle.BUOYANCY:
95 if (pValue < -1f) pValue = -1f;
96 if (pValue > 1f) pValue = 1f;
97 vd.m_VehicleBuoyancy = pValue;
98 break;
99 case Vehicle.HOVER_EFFICIENCY:
100 if (pValue < 0f) pValue = 0f;
101 if (pValue > 1f) pValue = 1f;
102 vd.m_VhoverEfficiency = pValue;
103 break;
104 case Vehicle.HOVER_HEIGHT:
105 vd.m_VhoverHeight = pValue;
106 break;
107 case Vehicle.HOVER_TIMESCALE:
108 if (pValue < timestep) pValue = timestep;
109 vd.m_VhoverTimescale = pValue;
110 break;
111 case Vehicle.LINEAR_DEFLECTION_EFFICIENCY:
112 if (pValue < 0f) pValue = 0f;
113 if (pValue > 1f) pValue = 1f;
114 vd.m_linearDeflectionEfficiency = pValue;
115 break;
116 case Vehicle.LINEAR_DEFLECTION_TIMESCALE:
117 if (pValue < timestep) pValue = timestep;
118 vd.m_linearDeflectionTimescale = pValue;
119 break;
120 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE:
121 if (pValue < timestep) pValue = timestep;
122 else if (pValue > 120) pValue = 120;
123 vd.m_linearMotorDecayTimescale = pValue;
124 break;
125 case Vehicle.LINEAR_MOTOR_TIMESCALE:
126 if (pValue < timestep) pValue = timestep;
127 vd.m_linearMotorTimescale = pValue;
128 break;
129 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY:
130 if (pValue < 0f) pValue = 0f;
131 if (pValue > 1f) pValue = 1f;
132 vd.m_verticalAttractionEfficiency = pValue;
133 break;
134 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE:
135 if (pValue < timestep) pValue = timestep;
136 vd.m_verticalAttractionTimescale = pValue;
137 break;
138
139 // These are vector properties but the engine lets you use a single float value to
140 // set all of the components to the same value
141 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
142 if (pValue < timestep) pValue = timestep;
143 vd.m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue);
144 break;
145 case Vehicle.ANGULAR_MOTOR_DIRECTION:
146 vd.m_angularMotorDirection = new Vector3(pValue, pValue, pValue);
147 len = vd.m_angularMotorDirection.Length();
148 if (len > 12.566f)
149 vd.m_angularMotorDirection *= (12.566f / len);
150 break;
151 case Vehicle.LINEAR_FRICTION_TIMESCALE:
152 if (pValue < timestep) pValue = timestep;
153 vd.m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue);
154 break;
155 case Vehicle.LINEAR_MOTOR_DIRECTION:
156 vd.m_linearMotorDirection = new Vector3(pValue, pValue, pValue);
157 len = vd.m_linearMotorDirection.Length();
158 if (len > 30.0f)
159 vd.m_linearMotorDirection *= (30.0f / len);
160 break;
161 case Vehicle.LINEAR_MOTOR_OFFSET:
162 vd.m_linearMotorOffset = new Vector3(pValue, pValue, pValue);
163 len = vd.m_linearMotorOffset.Length();
164 if (len > 100.0f)
165 vd.m_linearMotorOffset *= (100.0f / len);
166 break;
167 }
168 }//end ProcessFloatVehicleParam
169
170 public void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue)
171 {
172 float len;
173 float timestep = 0.01f;
174 switch (pParam)
175 {
176 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
177 if (pValue.X < timestep) pValue.X = timestep;
178 if (pValue.Y < timestep) pValue.Y = timestep;
179 if (pValue.Z < timestep) pValue.Z = timestep;
180
181 vd.m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
182 break;
183 case Vehicle.ANGULAR_MOTOR_DIRECTION:
184 vd.m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
185 // Limit requested angular speed to 2 rps= 4 pi rads/sec
186 len = vd.m_angularMotorDirection.Length();
187 if (len > 12.566f)
188 vd.m_angularMotorDirection *= (12.566f / len);
189 break;
190 case Vehicle.LINEAR_FRICTION_TIMESCALE:
191 if (pValue.X < timestep) pValue.X = timestep;
192 if (pValue.Y < timestep) pValue.Y = timestep;
193 if (pValue.Z < timestep) pValue.Z = timestep;
194 vd.m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
195 break;
196 case Vehicle.LINEAR_MOTOR_DIRECTION:
197 vd.m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
198 len = vd.m_linearMotorDirection.Length();
199 if (len > 30.0f)
200 vd.m_linearMotorDirection *= (30.0f / len);
201 break;
202 case Vehicle.LINEAR_MOTOR_OFFSET:
203 vd.m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z);
204 len = vd.m_linearMotorOffset.Length();
205 if (len > 100.0f)
206 vd.m_linearMotorOffset *= (100.0f / len);
207 break;
208 }
209 }//end ProcessVectorVehicleParam
210
211 public void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue)
212 {
213 switch (pParam)
214 {
215 case Vehicle.REFERENCE_FRAME:
216 vd.m_referenceFrame = Quaternion.Inverse(pValue);
217 break;
218 }
219 }//end ProcessRotationVehicleParam
220
221 public void ProcessVehicleFlags(int pParam, bool remove)
222 {
223 if (remove)
224 {
225 vd.m_flags &= ~((VehicleFlag)pParam);
226 }
227 else
228 {
229 vd.m_flags |= (VehicleFlag)pParam;
230 }
231 }//end ProcessVehicleFlags
232
233 public void ProcessTypeChange(Vehicle pType)
234 {
235 vd.m_linearMotorDirection = Vector3.Zero;
236 vd.m_angularMotorDirection = Vector3.Zero;
237 vd.m_linearMotorOffset = Vector3.Zero;
238 vd.m_referenceFrame = Quaternion.Identity;
239
240 // Set Defaults For Type
241 vd.m_type = pType;
242 switch (pType)
243 {
244 case Vehicle.TYPE_NONE:
245 vd.m_linearFrictionTimescale = new Vector3(1000, 1000, 1000);
246 vd.m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
247 vd.m_linearMotorTimescale = 1000;
248 vd.m_linearMotorDecayTimescale = 120;
249 vd.m_angularMotorTimescale = 1000;
250 vd.m_angularMotorDecayTimescale = 1000;
251 vd.m_VhoverHeight = 0;
252 vd.m_VhoverEfficiency = 1;
253 vd.m_VhoverTimescale = 1000;
254 vd.m_VehicleBuoyancy = 0;
255 vd.m_linearDeflectionEfficiency = 0;
256 vd.m_linearDeflectionTimescale = 1000;
257 vd.m_angularDeflectionEfficiency = 0;
258 vd.m_angularDeflectionTimescale = 1000;
259 vd.m_bankingEfficiency = 0;
260 vd.m_bankingMix = 1;
261 vd.m_bankingTimescale = 1000;
262 vd.m_verticalAttractionEfficiency = 0;
263 vd.m_verticalAttractionTimescale = 1000;
264
265 vd.m_flags = (VehicleFlag)0;
266 break;
267
268 case Vehicle.TYPE_SLED:
269 vd.m_linearFrictionTimescale = new Vector3(30, 1, 1000);
270 vd.m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
271 vd.m_linearMotorTimescale = 1000;
272 vd.m_linearMotorDecayTimescale = 120;
273 vd.m_angularMotorTimescale = 1000;
274 vd.m_angularMotorDecayTimescale = 120;
275 vd.m_VhoverHeight = 0;
276 vd.m_VhoverEfficiency = 1;
277 vd.m_VhoverTimescale = 10;
278 vd.m_VehicleBuoyancy = 0;
279 vd.m_linearDeflectionEfficiency = 1;
280 vd.m_linearDeflectionTimescale = 1;
281 vd.m_angularDeflectionEfficiency = 0;
282 vd.m_angularDeflectionTimescale = 1000;
283 vd.m_bankingEfficiency = 0;
284 vd.m_bankingMix = 1;
285 vd.m_bankingTimescale = 10;
286 vd.m_flags &=
287 ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
288 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY);
289 vd.m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP);
290 break;
291 case Vehicle.TYPE_CAR:
292 vd.m_linearFrictionTimescale = new Vector3(100, 2, 1000);
293 vd.m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
294 vd.m_linearMotorTimescale = 1;
295 vd.m_linearMotorDecayTimescale = 60;
296 vd.m_angularMotorTimescale = 1;
297 vd.m_angularMotorDecayTimescale = 0.8f;
298 vd.m_VhoverHeight = 0;
299 vd.m_VhoverEfficiency = 0;
300 vd.m_VhoverTimescale = 1000;
301 vd.m_VehicleBuoyancy = 0;
302 vd.m_linearDeflectionEfficiency = 1;
303 vd.m_linearDeflectionTimescale = 2;
304 vd.m_angularDeflectionEfficiency = 0;
305 vd.m_angularDeflectionTimescale = 10;
306 vd.m_verticalAttractionEfficiency = 1f;
307 vd.m_verticalAttractionTimescale = 10f;
308 vd.m_bankingEfficiency = -0.2f;
309 vd.m_bankingMix = 1;
310 vd.m_bankingTimescale = 1;
311 vd.m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT);
312 vd.m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY |
313 VehicleFlag.LIMIT_MOTOR_UP | VehicleFlag.HOVER_UP_ONLY);
314 break;
315 case Vehicle.TYPE_BOAT:
316 vd.m_linearFrictionTimescale = new Vector3(10, 3, 2);
317 vd.m_angularFrictionTimescale = new Vector3(10, 10, 10);
318 vd.m_linearMotorTimescale = 5;
319 vd.m_linearMotorDecayTimescale = 60;
320 vd.m_angularMotorTimescale = 4;
321 vd.m_angularMotorDecayTimescale = 4;
322 vd.m_VhoverHeight = 0;
323 vd.m_VhoverEfficiency = 0.5f;
324 vd.m_VhoverTimescale = 2;
325 vd.m_VehicleBuoyancy = 1;
326 vd.m_linearDeflectionEfficiency = 0.5f;
327 vd.m_linearDeflectionTimescale = 3;
328 vd.m_angularDeflectionEfficiency = 0.5f;
329 vd.m_angularDeflectionTimescale = 5;
330 vd.m_verticalAttractionEfficiency = 0.5f;
331 vd.m_verticalAttractionTimescale = 5f;
332 vd.m_bankingEfficiency = -0.3f;
333 vd.m_bankingMix = 0.8f;
334 vd.m_bankingTimescale = 1;
335 vd.m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY |
336 VehicleFlag.HOVER_GLOBAL_HEIGHT |
337 VehicleFlag.HOVER_UP_ONLY |
338 VehicleFlag.LIMIT_ROLL_ONLY);
339 vd.m_flags |= (VehicleFlag.NO_DEFLECTION_UP |
340 VehicleFlag.LIMIT_MOTOR_UP |
341 VehicleFlag.HOVER_WATER_ONLY);
342 break;
343 case Vehicle.TYPE_AIRPLANE:
344 vd.m_linearFrictionTimescale = new Vector3(200, 10, 5);
345 vd.m_angularFrictionTimescale = new Vector3(20, 20, 20);
346 vd.m_linearMotorTimescale = 2;
347 vd.m_linearMotorDecayTimescale = 60;
348 vd.m_angularMotorTimescale = 4;
349 vd.m_angularMotorDecayTimescale = 8;
350 vd.m_VhoverHeight = 0;
351 vd.m_VhoverEfficiency = 0.5f;
352 vd.m_VhoverTimescale = 1000;
353 vd.m_VehicleBuoyancy = 0;
354 vd.m_linearDeflectionEfficiency = 0.5f;
355 vd.m_linearDeflectionTimescale = 0.5f;
356 vd.m_angularDeflectionEfficiency = 1;
357 vd.m_angularDeflectionTimescale = 2;
358 vd.m_verticalAttractionEfficiency = 0.9f;
359 vd.m_verticalAttractionTimescale = 2f;
360 vd.m_bankingEfficiency = 1;
361 vd.m_bankingMix = 0.7f;
362 vd.m_bankingTimescale = 2;
363 vd.m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY |
364 VehicleFlag.HOVER_TERRAIN_ONLY |
365 VehicleFlag.HOVER_GLOBAL_HEIGHT |
366 VehicleFlag.HOVER_UP_ONLY |
367 VehicleFlag.NO_DEFLECTION_UP |
368 VehicleFlag.LIMIT_MOTOR_UP);
369 vd.m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY);
370 break;
371 case Vehicle.TYPE_BALLOON:
372 vd.m_linearFrictionTimescale = new Vector3(5, 5, 5);
373 vd.m_angularFrictionTimescale = new Vector3(10, 10, 10);
374 vd.m_linearMotorTimescale = 5;
375 vd.m_linearMotorDecayTimescale = 60;
376 vd.m_angularMotorTimescale = 6;
377 vd.m_angularMotorDecayTimescale = 10;
378 vd.m_VhoverHeight = 5;
379 vd.m_VhoverEfficiency = 0.8f;
380 vd.m_VhoverTimescale = 10;
381 vd.m_VehicleBuoyancy = 1;
382 vd.m_linearDeflectionEfficiency = 0;
383 vd.m_linearDeflectionTimescale = 5;
384 vd.m_angularDeflectionEfficiency = 0;
385 vd.m_angularDeflectionTimescale = 5;
386 vd.m_verticalAttractionEfficiency = 0f;
387 vd.m_verticalAttractionTimescale = 1000f;
388 vd.m_bankingEfficiency = 0;
389 vd.m_bankingMix = 0.7f;
390 vd.m_bankingTimescale = 5;
391 vd.m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY |
392 VehicleFlag.HOVER_TERRAIN_ONLY |
393 VehicleFlag.HOVER_UP_ONLY |
394 VehicleFlag.NO_DEFLECTION_UP |
395 VehicleFlag.LIMIT_MOTOR_UP);
396 vd.m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY |
397 VehicleFlag.HOVER_GLOBAL_HEIGHT);
398 break;
399 }
400 }
401 public void SetVehicle(PhysicsActor ph)
402 {
403 if (ph == null)
404 return;
405 ph.SetVehicle(vd);
406 }
407
408 private XmlTextWriter writer;
409
410 private void XWint(string name, int i)
411 {
412 writer.WriteElementString(name, i.ToString());
413 }
414
415 private void XWfloat(string name, float f)
416 {
417 writer.WriteElementString(name, f.ToString(Utils.EnUsCulture));
418 }
419
420 private void XWVector(string name, Vector3 vec)
421 {
422 writer.WriteStartElement(name);
423 writer.WriteElementString("X", vec.X.ToString(Utils.EnUsCulture));
424 writer.WriteElementString("Y", vec.Y.ToString(Utils.EnUsCulture));
425 writer.WriteElementString("Z", vec.Z.ToString(Utils.EnUsCulture));
426 writer.WriteEndElement();
427 }
428
429 private void XWQuat(string name, Quaternion quat)
430 {
431 writer.WriteStartElement(name);
432 writer.WriteElementString("X", quat.X.ToString(Utils.EnUsCulture));
433 writer.WriteElementString("Y", quat.Y.ToString(Utils.EnUsCulture));
434 writer.WriteElementString("Z", quat.Z.ToString(Utils.EnUsCulture));
435 writer.WriteElementString("W", quat.W.ToString(Utils.EnUsCulture));
436 writer.WriteEndElement();
437 }
438
439 public void ToXml2(XmlTextWriter twriter)
440 {
441 writer = twriter;
442 writer.WriteStartElement("Vehicle");
443
444 XWint("TYPE", (int)vd.m_type);
445 XWint("FLAGS", (int)vd.m_flags);
446
447 // Linear properties
448 XWVector("LMDIR", vd.m_linearMotorDirection);
449 XWVector("LMFTIME", vd.m_linearFrictionTimescale);
450 XWfloat("LMDTIME", vd.m_linearMotorDecayTimescale);
451 XWfloat("LMTIME", vd.m_linearMotorTimescale);
452 XWVector("LMOFF", vd.m_linearMotorOffset);
453
454 //Angular properties
455 XWVector("AMDIR", vd.m_angularMotorDirection);
456 XWfloat("AMTIME", vd.m_angularMotorTimescale);
457 XWfloat("AMDTIME", vd.m_angularMotorDecayTimescale);
458 XWVector("AMFTIME", vd.m_angularFrictionTimescale);
459
460 //Deflection properties
461 XWfloat("ADEFF", vd.m_angularDeflectionEfficiency);
462 XWfloat("ADTIME", vd.m_angularDeflectionTimescale);
463 XWfloat("LDEFF", vd.m_linearDeflectionEfficiency);
464 XWfloat("LDTIME", vd.m_linearDeflectionTimescale);
465
466 //Banking properties
467 XWfloat("BEFF", vd.m_bankingEfficiency);
468 XWfloat("BMIX", vd.m_bankingMix);
469 XWfloat("BTIME", vd.m_bankingTimescale);
470
471 //Hover and Buoyancy properties
472 XWfloat("HHEI", vd.m_VhoverHeight);
473 XWfloat("HEFF", vd.m_VhoverEfficiency);
474 XWfloat("HTIME", vd.m_VhoverTimescale);
475 XWfloat("VBUO", vd.m_VehicleBuoyancy);
476
477 //Attractor properties
478 XWfloat("VAEFF", vd.m_verticalAttractionEfficiency);
479 XWfloat("VATIME", vd.m_verticalAttractionTimescale);
480
481 XWQuat("REF_FRAME", vd.m_referenceFrame);
482
483 writer.WriteEndElement();
484 writer = null;
485 }
486
487
488
489 XmlTextReader reader;
490
491 private int XRint()
492 {
493 return reader.ReadElementContentAsInt();
494 }
495
496 private float XRfloat()
497 {
498 return reader.ReadElementContentAsFloat();
499 }
500
501 public Vector3 XRvector()
502 {
503 Vector3 vec;
504 reader.ReadStartElement();
505 vec.X = reader.ReadElementContentAsFloat();
506 vec.Y = reader.ReadElementContentAsFloat();
507 vec.Z = reader.ReadElementContentAsFloat();
508 reader.ReadEndElement();
509 return vec;
510 }
511
512 public Quaternion XRquat()
513 {
514 Quaternion q;
515 reader.ReadStartElement();
516 q.X = reader.ReadElementContentAsFloat();
517 q.Y = reader.ReadElementContentAsFloat();
518 q.Z = reader.ReadElementContentAsFloat();
519 q.W = reader.ReadElementContentAsFloat();
520 reader.ReadEndElement();
521 return q;
522 }
523
524 public static bool EReadProcessors(
525 Dictionary<string, Action> processors,
526 XmlTextReader xtr)
527 {
528 bool errors = false;
529
530 string nodeName = string.Empty;
531 while (xtr.NodeType != XmlNodeType.EndElement)
532 {
533 nodeName = xtr.Name;
534
535 // m_log.DebugFormat("[ExternalRepresentationUtils]: Processing: {0}", nodeName);
536
537 Action p = null;
538 if (processors.TryGetValue(xtr.Name, out p))
539 {
540 // m_log.DebugFormat("[ExternalRepresentationUtils]: Found {0} processor, nodeName);
541
542 try
543 {
544 p();
545 }
546 catch (Exception e)
547 {
548 errors = true;
549 if (xtr.NodeType == XmlNodeType.EndElement)
550 xtr.Read();
551 }
552 }
553 else
554 {
555 // m_log.DebugFormat("[LandDataSerializer]: caught unknown element {0}", nodeName);
556 xtr.ReadOuterXml(); // ignore
557 }
558 }
559
560 return errors;
561 }
562
563
564
565 public void FromXml2(XmlTextReader _reader, out bool errors)
566 {
567 errors = false;
568 reader = _reader;
569
570 Dictionary<string, Action> m_VehicleXmlProcessors
571 = new Dictionary<string, Action>();
572
573 m_VehicleXmlProcessors.Add("TYPE", ProcessXR_type);
574 m_VehicleXmlProcessors.Add("FLAGS", ProcessXR_flags);
575
576 // Linear properties
577 m_VehicleXmlProcessors.Add("LMDIR", ProcessXR_linearMotorDirection);
578 m_VehicleXmlProcessors.Add("LMFTIME", ProcessXR_linearFrictionTimescale);
579 m_VehicleXmlProcessors.Add("LMDTIME", ProcessXR_linearMotorDecayTimescale);
580 m_VehicleXmlProcessors.Add("LMTIME", ProcessXR_linearMotorTimescale);
581 m_VehicleXmlProcessors.Add("LMOFF", ProcessXR_linearMotorOffset);
582
583 //Angular properties
584 m_VehicleXmlProcessors.Add("AMDIR", ProcessXR_angularMotorDirection);
585 m_VehicleXmlProcessors.Add("AMTIME", ProcessXR_angularMotorTimescale);
586 m_VehicleXmlProcessors.Add("AMDTIME", ProcessXR_angularMotorDecayTimescale);
587 m_VehicleXmlProcessors.Add("AMFTIME", ProcessXR_angularFrictionTimescale);
588
589 //Deflection properties
590 m_VehicleXmlProcessors.Add("ADEFF", ProcessXR_angularDeflectionEfficiency);
591 m_VehicleXmlProcessors.Add("ADTIME", ProcessXR_angularDeflectionTimescale);
592 m_VehicleXmlProcessors.Add("LDEFF", ProcessXR_linearDeflectionEfficiency);
593 m_VehicleXmlProcessors.Add("LDTIME", ProcessXR_linearDeflectionTimescale);
594
595 //Banking properties
596 m_VehicleXmlProcessors.Add("BEFF", ProcessXR_bankingEfficiency);
597 m_VehicleXmlProcessors.Add("BMIX", ProcessXR_bankingMix);
598 m_VehicleXmlProcessors.Add("BTIME", ProcessXR_bankingTimescale);
599
600 //Hover and Buoyancy properties
601 m_VehicleXmlProcessors.Add("HHEI", ProcessXR_VhoverHeight);
602 m_VehicleXmlProcessors.Add("HEFF", ProcessXR_VhoverEfficiency);
603 m_VehicleXmlProcessors.Add("HTIME", ProcessXR_VhoverTimescale);
604
605 m_VehicleXmlProcessors.Add("VBUO", ProcessXR_VehicleBuoyancy);
606
607 //Attractor properties
608 m_VehicleXmlProcessors.Add("VAEFF", ProcessXR_verticalAttractionEfficiency);
609 m_VehicleXmlProcessors.Add("VATIME", ProcessXR_verticalAttractionTimescale);
610
611 m_VehicleXmlProcessors.Add("REF_FRAME", ProcessXR_referenceFrame);
612
613 vd = new VehicleData();
614
615 reader.ReadStartElement("Vehicle", String.Empty);
616
617 errors = EReadProcessors(
618 m_VehicleXmlProcessors,
619 reader);
620
621 reader.ReadEndElement();
622 reader = null;
623 }
624
625 private void ProcessXR_type()
626 {
627 vd.m_type = (Vehicle)XRint();
628 }
629 private void ProcessXR_flags()
630 {
631 vd.m_flags = (VehicleFlag)XRint();
632 }
633 // Linear properties
634 private void ProcessXR_linearMotorDirection()
635 {
636 vd.m_linearMotorDirection = XRvector();
637 }
638
639 private void ProcessXR_linearFrictionTimescale()
640 {
641 vd.m_linearFrictionTimescale = XRvector();
642 }
643
644 private void ProcessXR_linearMotorDecayTimescale()
645 {
646 vd.m_linearMotorDecayTimescale = XRfloat();
647 }
648 private void ProcessXR_linearMotorTimescale()
649 {
650 vd.m_linearMotorTimescale = XRfloat();
651 }
652 private void ProcessXR_linearMotorOffset()
653 {
654 vd.m_linearMotorOffset = XRvector();
655 }
656
657
658 //Angular properties
659 private void ProcessXR_angularMotorDirection()
660 {
661 vd.m_angularMotorDirection = XRvector();
662 }
663 private void ProcessXR_angularMotorTimescale()
664 {
665 vd.m_angularMotorTimescale = XRfloat();
666 }
667 private void ProcessXR_angularMotorDecayTimescale()
668 {
669 vd.m_angularMotorDecayTimescale = XRfloat();
670 }
671 private void ProcessXR_angularFrictionTimescale()
672 {
673 vd.m_angularFrictionTimescale = XRvector();
674 }
675
676 //Deflection properties
677 private void ProcessXR_angularDeflectionEfficiency()
678 {
679 vd.m_angularDeflectionEfficiency = XRfloat();
680 }
681 private void ProcessXR_angularDeflectionTimescale()
682 {
683 vd.m_angularDeflectionTimescale = XRfloat();
684 }
685 private void ProcessXR_linearDeflectionEfficiency()
686 {
687 vd.m_linearDeflectionEfficiency = XRfloat();
688 }
689 private void ProcessXR_linearDeflectionTimescale()
690 {
691 vd.m_linearDeflectionTimescale = XRfloat();
692 }
693
694 //Banking properties
695 private void ProcessXR_bankingEfficiency()
696 {
697 vd.m_bankingEfficiency = XRfloat();
698 }
699 private void ProcessXR_bankingMix()
700 {
701 vd.m_bankingMix = XRfloat();
702 }
703 private void ProcessXR_bankingTimescale()
704 {
705 vd.m_bankingTimescale = XRfloat();
706 }
707
708 //Hover and Buoyancy properties
709 private void ProcessXR_VhoverHeight()
710 {
711 vd.m_VhoverHeight = XRfloat();
712 }
713 private void ProcessXR_VhoverEfficiency()
714 {
715 vd.m_VhoverEfficiency = XRfloat();
716 }
717 private void ProcessXR_VhoverTimescale()
718 {
719 vd.m_VhoverTimescale = XRfloat();
720 }
721
722 private void ProcessXR_VehicleBuoyancy()
723 {
724 vd.m_VehicleBuoyancy = XRfloat();
725 }
726
727 //Attractor properties
728 private void ProcessXR_verticalAttractionEfficiency()
729 {
730 vd.m_verticalAttractionEfficiency = XRfloat();
731 }
732 private void ProcessXR_verticalAttractionTimescale()
733 {
734 vd.m_verticalAttractionTimescale = XRfloat();
735 }
736
737 private void ProcessXR_referenceFrame()
738 {
739 vd.m_referenceFrame = XRquat();
740 }
741 }
742} \ No newline at end of file
diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
index 816d3b6..0089c7d 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
@@ -156,7 +156,7 @@ namespace OpenSim.Region.Framework.Scenes
156 return false; 156 return false;
157 } 157 }
158 } 158 }
159 159
160 if (InventoryService.AddItem(item)) 160 if (InventoryService.AddItem(item))
161 { 161 {
162 int userlevel = 0; 162 int userlevel = 0;
@@ -307,8 +307,7 @@ namespace OpenSim.Region.Framework.Scenes
307 307
308 // Update item with new asset 308 // Update item with new asset
309 item.AssetID = asset.FullID; 309 item.AssetID = asset.FullID;
310 if (group.UpdateInventoryItem(item)) 310 group.UpdateInventoryItem(item);
311 remoteClient.SendAgentAlertMessage("Script saved", false);
312 311
313 part.SendPropertiesToClient(remoteClient); 312 part.SendPropertiesToClient(remoteClient);
314 313
@@ -319,12 +318,7 @@ namespace OpenSim.Region.Framework.Scenes
319 { 318 {
320 // Needs to determine which engine was running it and use that 319 // Needs to determine which engine was running it and use that
321 // 320 //
322 part.Inventory.CreateScriptInstance(item.ItemID, 0, false, DefaultScriptEngine, 0); 321 errors = part.Inventory.CreateScriptInstanceEr(item.ItemID, 0, false, DefaultScriptEngine, 0);
323 errors = part.Inventory.GetScriptErrors(item.ItemID);
324 }
325 else
326 {
327 remoteClient.SendAgentAlertMessage("Script saved", false);
328 } 322 }
329 323
330 // Tell anyone managing scripts that a script has been reloaded/changed 324 // Tell anyone managing scripts that a script has been reloaded/changed
@@ -392,6 +386,7 @@ namespace OpenSim.Region.Framework.Scenes
392 386
393 if (UUID.Zero == transactionID) 387 if (UUID.Zero == transactionID)
394 { 388 {
389 item.Flags = (item.Flags & ~(uint)255) | (itemUpd.Flags & (uint)255);
395 item.Name = itemUpd.Name; 390 item.Name = itemUpd.Name;
396 item.Description = itemUpd.Description; 391 item.Description = itemUpd.Description;
397 392
@@ -779,6 +774,8 @@ namespace OpenSim.Region.Framework.Scenes
779 return; 774 return;
780 } 775 }
781 776
777 if (newName == null) newName = item.Name;
778
782 AssetBase asset = AssetService.Get(item.AssetID.ToString()); 779 AssetBase asset = AssetService.Get(item.AssetID.ToString());
783 780
784 if (asset != null) 781 if (asset != null)
@@ -835,6 +832,24 @@ namespace OpenSim.Region.Framework.Scenes
835 } 832 }
836 833
837 /// <summary> 834 /// <summary>
835 /// Move an item within the agent's inventory, and leave a copy (used in making a new outfit)
836 /// </summary>
837 public void MoveInventoryItemsLeaveCopy(IClientAPI remoteClient, List<InventoryItemBase> items, UUID destfolder)
838 {
839 List<InventoryItemBase> moveitems = new List<InventoryItemBase>();
840 foreach (InventoryItemBase b in items)
841 {
842 CopyInventoryItem(remoteClient, 0, remoteClient.AgentId, b.ID, b.Folder, null);
843 InventoryItemBase n = InventoryService.GetItem(b);
844 n.Folder = destfolder;
845 moveitems.Add(n);
846 remoteClient.SendInventoryItemCreateUpdate(n, 0);
847 }
848
849 MoveInventoryItem(remoteClient, moveitems);
850 }
851
852 /// <summary>
838 /// Move an item within the agent's inventory. 853 /// Move an item within the agent's inventory.
839 /// </summary> 854 /// </summary>
840 /// <param name="remoteClient"></param> 855 /// <param name="remoteClient"></param>
@@ -1177,6 +1192,10 @@ namespace OpenSim.Region.Framework.Scenes
1177 { 1192 {
1178 SceneObjectPart part = GetSceneObjectPart(primLocalId); 1193 SceneObjectPart part = GetSceneObjectPart(primLocalId);
1179 1194
1195 // Can't move a null item
1196 if (itemId == UUID.Zero)
1197 return;
1198
1180 if (null == part) 1199 if (null == part)
1181 { 1200 {
1182 m_log.WarnFormat( 1201 m_log.WarnFormat(
@@ -1281,21 +1300,28 @@ namespace OpenSim.Region.Framework.Scenes
1281 return; 1300 return;
1282 } 1301 }
1283 1302
1284 if (part.OwnerID != destPart.OwnerID) 1303 // Can't transfer this
1304 //
1305 if (part.OwnerID != destPart.OwnerID && (srcTaskItem.CurrentPermissions & (uint)PermissionMask.Transfer) == 0)
1306 return;
1307
1308 bool overrideNoMod = false;
1309 if ((part.GetEffectiveObjectFlags() & (uint)PrimFlags.AllowInventoryDrop) != 0)
1310 overrideNoMod = true;
1311
1312 if (part.OwnerID != destPart.OwnerID && (destPart.GetEffectiveObjectFlags() & (uint)PrimFlags.AllowInventoryDrop) == 0)
1285 { 1313 {
1286 // Source must have transfer permissions 1314 // object cannot copy items to an object owned by a different owner
1287 if ((srcTaskItem.CurrentPermissions & (uint)PermissionMask.Transfer) == 0) 1315 // unless llAllowInventoryDrop has been called
1288 return;
1289 1316
1290 // Object cannot copy items to an object owned by a different owner 1317 return;
1291 // unless llAllowInventoryDrop has been called on the destination
1292 if ((destPart.GetEffectiveObjectFlags() & (uint)PrimFlags.AllowInventoryDrop) == 0)
1293 return;
1294 } 1318 }
1295 1319
1296 // must have both move and modify permission to put an item in an object 1320 // must have both move and modify permission to put an item in an object
1297 if ((part.OwnerMask & ((uint)PermissionMask.Move | (uint)PermissionMask.Modify)) == 0) 1321 if (((part.OwnerMask & (uint)PermissionMask.Modify) == 0) && (!overrideNoMod))
1322 {
1298 return; 1323 return;
1324 }
1299 1325
1300 TaskInventoryItem destTaskItem = new TaskInventoryItem(); 1326 TaskInventoryItem destTaskItem = new TaskInventoryItem();
1301 1327
@@ -1351,6 +1377,14 @@ namespace OpenSim.Region.Framework.Scenes
1351 1377
1352 public UUID MoveTaskInventoryItems(UUID destID, string category, SceneObjectPart host, List<UUID> items) 1378 public UUID MoveTaskInventoryItems(UUID destID, string category, SceneObjectPart host, List<UUID> items)
1353 { 1379 {
1380 SceneObjectPart destPart = GetSceneObjectPart(destID);
1381 if (destPart != null) // Move into a prim
1382 {
1383 foreach(UUID itemID in items)
1384 MoveTaskInventoryItem(destID, host, itemID);
1385 return destID; // Prim folder ID == prim ID
1386 }
1387
1354 InventoryFolderBase rootFolder = InventoryService.GetRootFolder(destID); 1388 InventoryFolderBase rootFolder = InventoryService.GetRootFolder(destID);
1355 1389
1356 UUID newFolderID = UUID.Random(); 1390 UUID newFolderID = UUID.Random();
@@ -1536,12 +1570,12 @@ namespace OpenSim.Region.Framework.Scenes
1536 agentTransactions.HandleTaskItemUpdateFromTransaction( 1570 agentTransactions.HandleTaskItemUpdateFromTransaction(
1537 remoteClient, part, transactionID, currentItem); 1571 remoteClient, part, transactionID, currentItem);
1538 1572
1539 if ((InventoryType)itemInfo.InvType == InventoryType.Notecard) 1573// if ((InventoryType)itemInfo.InvType == InventoryType.Notecard)
1540 remoteClient.SendAgentAlertMessage("Notecard saved", false); 1574// remoteClient.SendAgentAlertMessage("Notecard saved", false);
1541 else if ((InventoryType)itemInfo.InvType == InventoryType.LSL) 1575// else if ((InventoryType)itemInfo.InvType == InventoryType.LSL)
1542 remoteClient.SendAgentAlertMessage("Script saved", false); 1576// remoteClient.SendAgentAlertMessage("Script saved", false);
1543 else 1577// else
1544 remoteClient.SendAgentAlertMessage("Item saved", false); 1578// remoteClient.SendAgentAlertMessage("Item saved", false);
1545 } 1579 }
1546 } 1580 }
1547 1581
@@ -1725,7 +1759,7 @@ namespace OpenSim.Region.Framework.Scenes
1725 } 1759 }
1726 1760
1727 AssetBase asset = CreateAsset(itemBase.Name, itemBase.Description, (sbyte)itemBase.AssetType, 1761 AssetBase asset = CreateAsset(itemBase.Name, itemBase.Description, (sbyte)itemBase.AssetType,
1728 Encoding.ASCII.GetBytes("default\n{\n state_entry()\n {\n llSay(0, \"Script running\");\n }\n}"), 1762 Encoding.ASCII.GetBytes("default\n{\n state_entry()\n {\n llSay(0, \"Script running\");\n }\n\n touch_start(integer num)\n {\n }\n}"),
1729 agentID); 1763 agentID);
1730 AssetService.Store(asset); 1764 AssetService.Store(asset);
1731 1765
@@ -1881,23 +1915,32 @@ namespace OpenSim.Region.Framework.Scenes
1881 // build a list of eligible objects 1915 // build a list of eligible objects
1882 List<uint> deleteIDs = new List<uint>(); 1916 List<uint> deleteIDs = new List<uint>();
1883 List<SceneObjectGroup> deleteGroups = new List<SceneObjectGroup>(); 1917 List<SceneObjectGroup> deleteGroups = new List<SceneObjectGroup>();
1884 1918 List<SceneObjectGroup> takeGroups = new List<SceneObjectGroup>();
1885 // Start with true for both, then remove the flags if objects
1886 // that we can't derez are part of the selection
1887 bool permissionToTake = true;
1888 bool permissionToTakeCopy = true;
1889 bool permissionToDelete = true;
1890 1919
1891 foreach (uint localID in localIDs) 1920 foreach (uint localID in localIDs)
1892 { 1921 {
1922 // Start with true for both, then remove the flags if objects
1923 // that we can't derez are part of the selection
1924 bool permissionToTake = true;
1925 bool permissionToTakeCopy = true;
1926 bool permissionToDelete = true;
1927
1893 // Invalid id 1928 // Invalid id
1894 SceneObjectPart part = GetSceneObjectPart(localID); 1929 SceneObjectPart part = GetSceneObjectPart(localID);
1895 if (part == null) 1930 if (part == null)
1931 {
1932 //Client still thinks the object exists, kill it
1933 deleteIDs.Add(localID);
1896 continue; 1934 continue;
1935 }
1897 1936
1898 // Already deleted by someone else 1937 // Already deleted by someone else
1899 if (part.ParentGroup.IsDeleted) 1938 if (part.ParentGroup.IsDeleted)
1939 {
1940 //Client still thinks the object exists, kill it
1941 deleteIDs.Add(localID);
1900 continue; 1942 continue;
1943 }
1901 1944
1902 // Can't delete child prims 1945 // Can't delete child prims
1903 if (part != part.ParentGroup.RootPart) 1946 if (part != part.ParentGroup.RootPart)
@@ -1905,9 +1948,6 @@ namespace OpenSim.Region.Framework.Scenes
1905 1948
1906 SceneObjectGroup grp = part.ParentGroup; 1949 SceneObjectGroup grp = part.ParentGroup;
1907 1950
1908 deleteIDs.Add(localID);
1909 deleteGroups.Add(grp);
1910
1911 if (remoteClient == null) 1951 if (remoteClient == null)
1912 { 1952 {
1913 // Autoreturn has a null client. Nothing else does. So 1953 // Autoreturn has a null client. Nothing else does. So
@@ -1924,81 +1964,193 @@ namespace OpenSim.Region.Framework.Scenes
1924 } 1964 }
1925 else 1965 else
1926 { 1966 {
1927 if (!Permissions.CanTakeCopyObject(grp.UUID, remoteClient.AgentId)) 1967 if (action == DeRezAction.TakeCopy)
1968 {
1969 if (!Permissions.CanTakeCopyObject(grp.UUID, remoteClient.AgentId))
1970 permissionToTakeCopy = false;
1971 }
1972 else
1973 {
1928 permissionToTakeCopy = false; 1974 permissionToTakeCopy = false;
1929 1975 }
1930 if (!Permissions.CanTakeObject(grp.UUID, remoteClient.AgentId)) 1976 if (!Permissions.CanTakeObject(grp.UUID, remoteClient.AgentId))
1931 permissionToTake = false; 1977 permissionToTake = false;
1932 1978
1933 if (!Permissions.CanDeleteObject(grp.UUID, remoteClient.AgentId)) 1979 if (!Permissions.CanDeleteObject(grp.UUID, remoteClient.AgentId))
1934 permissionToDelete = false; 1980 permissionToDelete = false;
1935 } 1981 }
1936 }
1937 1982
1938 // Handle god perms 1983 // Handle god perms
1939 if ((remoteClient != null) && Permissions.IsGod(remoteClient.AgentId)) 1984 if ((remoteClient != null) && Permissions.IsGod(remoteClient.AgentId))
1940 { 1985 {
1941 permissionToTake = true; 1986 permissionToTake = true;
1942 permissionToTakeCopy = true; 1987 permissionToTakeCopy = true;
1943 permissionToDelete = true; 1988 permissionToDelete = true;
1944 } 1989 }
1945 1990
1946 // If we're re-saving, we don't even want to delete 1991 // If we're re-saving, we don't even want to delete
1947 if (action == DeRezAction.SaveToExistingUserInventoryItem) 1992 if (action == DeRezAction.SaveToExistingUserInventoryItem)
1948 permissionToDelete = false; 1993 permissionToDelete = false;
1949 1994
1950 // if we want to take a copy, we also don't want to delete 1995 // if we want to take a copy, we also don't want to delete
1951 // Note: after this point, the permissionToTakeCopy flag 1996 // Note: after this point, the permissionToTakeCopy flag
1952 // becomes irrelevant. It already includes the permissionToTake 1997 // becomes irrelevant. It already includes the permissionToTake
1953 // permission and after excluding no copy items here, we can 1998 // permission and after excluding no copy items here, we can
1954 // just use that. 1999 // just use that.
1955 if (action == DeRezAction.TakeCopy) 2000 if (action == DeRezAction.TakeCopy)
1956 { 2001 {
1957 // If we don't have permission, stop right here 2002 // If we don't have permission, stop right here
1958 if (!permissionToTakeCopy) 2003 if (!permissionToTakeCopy)
1959 return; 2004 return;
1960 2005
1961 permissionToTake = true; 2006 permissionToTake = true;
1962 // Don't delete 2007 // Don't delete
1963 permissionToDelete = false; 2008 permissionToDelete = false;
1964 } 2009 }
1965 2010
1966 if (action == DeRezAction.Return) 2011 if (action == DeRezAction.Return)
1967 {
1968 if (remoteClient != null)
1969 { 2012 {
1970 if (Permissions.CanReturnObjects( 2013 if (remoteClient != null)
1971 null,
1972 remoteClient.AgentId,
1973 deleteGroups))
1974 { 2014 {
1975 permissionToTake = true; 2015 if (Permissions.CanReturnObjects(
1976 permissionToDelete = true; 2016 null,
1977 2017 remoteClient.AgentId,
1978 foreach (SceneObjectGroup g in deleteGroups) 2018 deleteGroups))
1979 { 2019 {
1980 AddReturn(g.OwnerID == g.GroupID ? g.LastOwnerID : g.OwnerID, g.Name, g.AbsolutePosition, "parcel owner return"); 2020 permissionToTake = true;
2021 permissionToDelete = true;
2022
2023 AddReturn(grp.OwnerID == grp.GroupID ? grp.LastOwnerID : grp.OwnerID, grp.Name, grp.AbsolutePosition, "parcel owner return");
1981 } 2024 }
1982 } 2025 }
2026 else // Auto return passes through here with null agent
2027 {
2028 permissionToTake = true;
2029 permissionToDelete = true;
2030 }
1983 } 2031 }
1984 else // Auto return passes through here with null agent 2032
2033 if (permissionToTake && (!permissionToDelete))
2034 takeGroups.Add(grp);
2035
2036 if (permissionToDelete)
1985 { 2037 {
1986 permissionToTake = true; 2038 if (permissionToTake)
1987 permissionToDelete = true; 2039 deleteGroups.Add(grp);
2040 deleteIDs.Add(grp.LocalId);
1988 } 2041 }
1989 } 2042 }
1990 2043
1991 if (permissionToTake && (action != DeRezAction.Delete || this.m_useTrashOnDelete)) 2044 SendKillObject(deleteIDs);
2045
2046 if (deleteGroups.Count > 0)
1992 { 2047 {
2048 foreach (SceneObjectGroup g in deleteGroups)
2049 deleteIDs.Remove(g.LocalId);
2050
1993 m_asyncSceneObjectDeleter.DeleteToInventory( 2051 m_asyncSceneObjectDeleter.DeleteToInventory(
1994 action, destinationID, deleteGroups, remoteClient, 2052 action, destinationID, deleteGroups, remoteClient,
1995 permissionToDelete); 2053 true);
2054 }
2055 if (takeGroups.Count > 0)
2056 {
2057 m_asyncSceneObjectDeleter.DeleteToInventory(
2058 action, destinationID, takeGroups, remoteClient,
2059 false);
1996 } 2060 }
1997 else if (permissionToDelete) 2061 if (deleteIDs.Count > 0)
1998 { 2062 {
1999 foreach (SceneObjectGroup g in deleteGroups) 2063 foreach (SceneObjectGroup g in deleteGroups)
2000 DeleteSceneObject(g, false); 2064 DeleteSceneObject(g, true);
2065 }
2066 }
2067
2068 public UUID attachObjectAssetStore(IClientAPI remoteClient, SceneObjectGroup grp, UUID AgentId, out UUID itemID)
2069 {
2070 itemID = UUID.Zero;
2071 if (grp != null)
2072 {
2073 Vector3 inventoryStoredPosition = new Vector3
2074 (((grp.AbsolutePosition.X > (int)Constants.RegionSize)
2075 ? 250
2076 : grp.AbsolutePosition.X)
2077 ,
2078 (grp.AbsolutePosition.X > (int)Constants.RegionSize)
2079 ? 250
2080 : grp.AbsolutePosition.X,
2081 grp.AbsolutePosition.Z);
2082
2083 Vector3 originalPosition = grp.AbsolutePosition;
2084
2085 grp.AbsolutePosition = inventoryStoredPosition;
2086
2087 string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp);
2088
2089 grp.AbsolutePosition = originalPosition;
2090
2091 AssetBase asset = CreateAsset(
2092 grp.GetPartName(grp.LocalId),
2093 grp.GetPartDescription(grp.LocalId),
2094 (sbyte)AssetType.Object,
2095 Utils.StringToBytes(sceneObjectXml),
2096 remoteClient.AgentId);
2097 AssetService.Store(asset);
2098
2099 InventoryItemBase item = new InventoryItemBase();
2100 item.CreatorId = grp.RootPart.CreatorID.ToString();
2101 item.CreatorData = grp.RootPart.CreatorData;
2102 item.Owner = remoteClient.AgentId;
2103 item.ID = UUID.Random();
2104 item.AssetID = asset.FullID;
2105 item.Description = asset.Description;
2106 item.Name = asset.Name;
2107 item.AssetType = asset.Type;
2108 item.InvType = (int)InventoryType.Object;
2109
2110 InventoryFolderBase folder = InventoryService.GetFolderForType(remoteClient.AgentId, AssetType.Object);
2111 if (folder != null)
2112 item.Folder = folder.ID;
2113 else // oopsies
2114 item.Folder = UUID.Zero;
2115
2116 // Set up base perms properly
2117 uint permsBase = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify);
2118 permsBase &= grp.RootPart.BaseMask;
2119 permsBase |= (uint)PermissionMask.Move;
2120
2121 // Make sure we don't lock it
2122 grp.RootPart.NextOwnerMask |= (uint)PermissionMask.Move;
2123
2124 if ((remoteClient.AgentId != grp.RootPart.OwnerID) && Permissions.PropagatePermissions())
2125 {
2126 item.BasePermissions = permsBase & grp.RootPart.NextOwnerMask;
2127 item.CurrentPermissions = permsBase & grp.RootPart.NextOwnerMask;
2128 item.NextPermissions = permsBase & grp.RootPart.NextOwnerMask;
2129 item.EveryOnePermissions = permsBase & grp.RootPart.EveryoneMask & grp.RootPart.NextOwnerMask;
2130 item.GroupPermissions = permsBase & grp.RootPart.GroupMask & grp.RootPart.NextOwnerMask;
2131 }
2132 else
2133 {
2134 item.BasePermissions = permsBase;
2135 item.CurrentPermissions = permsBase & grp.RootPart.OwnerMask;
2136 item.NextPermissions = permsBase & grp.RootPart.NextOwnerMask;
2137 item.EveryOnePermissions = permsBase & grp.RootPart.EveryoneMask;
2138 item.GroupPermissions = permsBase & grp.RootPart.GroupMask;
2139 }
2140 item.CreationDate = Util.UnixTimeSinceEpoch();
2141
2142 // sets itemID so client can show item as 'attached' in inventory
2143 grp.FromItemID = item.ID;
2144
2145 if (AddInventoryItem(item))
2146 remoteClient.SendInventoryItemCreateUpdate(item, 0);
2147 else
2148 m_dialogModule.SendAlertToUser(remoteClient, "Operation failed");
2149
2150 itemID = item.ID;
2151 return item.AssetID;
2001 } 2152 }
2153 return UUID.Zero;
2002 } 2154 }
2003 2155
2004 /// <summary> 2156 /// <summary>
@@ -2127,6 +2279,9 @@ namespace OpenSim.Region.Framework.Scenes
2127 2279
2128 public void SetScriptRunning(IClientAPI controllingClient, UUID objectID, UUID itemID, bool running) 2280 public void SetScriptRunning(IClientAPI controllingClient, UUID objectID, UUID itemID, bool running)
2129 { 2281 {
2282 if (!Permissions.CanEditScript(itemID, objectID, controllingClient.AgentId))
2283 return;
2284
2130 SceneObjectPart part = GetSceneObjectPart(objectID); 2285 SceneObjectPart part = GetSceneObjectPart(objectID);
2131 if (part == null) 2286 if (part == null)
2132 return; 2287 return;
diff --git a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs
index 2701d6e..cf68ff4 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs
@@ -149,27 +149,47 @@ namespace OpenSim.Region.Framework.Scenes
149 /// <param name="remoteClient"></param> 149 /// <param name="remoteClient"></param>
150 public void SelectPrim(uint primLocalID, IClientAPI remoteClient) 150 public void SelectPrim(uint primLocalID, IClientAPI remoteClient)
151 { 151 {
152 /*
153 SceneObjectPart part = GetSceneObjectPart(primLocalID);
154
155 if (null == part)
156 return;
157
158 if (part.IsRoot)
159 {
160 SceneObjectGroup sog = part.ParentGroup;
161 sog.SendPropertiesToClient(remoteClient);
162
163 // A prim is only tainted if it's allowed to be edited by the person clicking it.
164 if (Permissions.CanEditObject(sog.UUID, remoteClient.AgentId)
165 || Permissions.CanMoveObject(sog.UUID, remoteClient.AgentId))
166 {
167 sog.IsSelected = true;
168 EventManager.TriggerParcelPrimCountTainted();
169 }
170 }
171 else
172 {
173 part.SendPropertiesToClient(remoteClient);
174 }
175 */
152 SceneObjectPart part = GetSceneObjectPart(primLocalID); 176 SceneObjectPart part = GetSceneObjectPart(primLocalID);
153 177
154 if (null == part) 178 if (null == part)
155 return; 179 return;
156 180
157 if (part.IsRoot) 181 SceneObjectGroup sog = part.ParentGroup;
158 { 182 if (sog == null)
159 SceneObjectGroup sog = part.ParentGroup; 183 return;
160 sog.SendPropertiesToClient(remoteClient);
161 sog.IsSelected = true;
162 184
163 // A prim is only tainted if it's allowed to be edited by the person clicking it. 185 part.SendPropertiesToClient(remoteClient);
164 if (Permissions.CanEditObject(sog.UUID, remoteClient.AgentId) 186
165 || Permissions.CanMoveObject(sog.UUID, remoteClient.AgentId)) 187 // A prim is only tainted if it's allowed to be edited by the person clicking it.
166 { 188 if (Permissions.CanEditObject(sog.UUID, remoteClient.AgentId)
167 EventManager.TriggerParcelPrimCountTainted(); 189 || Permissions.CanMoveObject(sog.UUID, remoteClient.AgentId))
168 }
169 }
170 else
171 { 190 {
172 part.SendPropertiesToClient(remoteClient); 191 part.IsSelected = true;
192 EventManager.TriggerParcelPrimCountTainted();
173 } 193 }
174 } 194 }
175 195
@@ -222,7 +242,7 @@ namespace OpenSim.Region.Framework.Scenes
222 SceneObjectPart part = GetSceneObjectPart(primLocalID); 242 SceneObjectPart part = GetSceneObjectPart(primLocalID);
223 if (part == null) 243 if (part == null)
224 return; 244 return;
225 245 /*
226 // A deselect packet contains all the local prims being deselected. However, since selection is still 246 // A deselect packet contains all the local prims being deselected. However, since selection is still
227 // group based we only want the root prim to trigger a full update - otherwise on objects with many prims 247 // group based we only want the root prim to trigger a full update - otherwise on objects with many prims
228 // we end up sending many duplicate ObjectUpdates 248 // we end up sending many duplicate ObjectUpdates
@@ -235,7 +255,9 @@ namespace OpenSim.Region.Framework.Scenes
235 // handled by group, but by prim. Legacy cruft. 255 // handled by group, but by prim. Legacy cruft.
236 // TODO: Make selection flagging per prim! 256 // TODO: Make selection flagging per prim!
237 // 257 //
238 part.ParentGroup.IsSelected = false; 258 if (Permissions.CanEditObject(part.ParentGroup.UUID, remoteClient.AgentId)
259 || Permissions.CanMoveObject(part.ParentGroup.UUID, remoteClient.AgentId))
260 part.ParentGroup.IsSelected = false;
239 261
240 if (part.ParentGroup.IsAttachment) 262 if (part.ParentGroup.IsAttachment)
241 isAttachment = true; 263 isAttachment = true;
@@ -255,6 +277,22 @@ namespace OpenSim.Region.Framework.Scenes
255 part.UUID, remoteClient.AgentId)) 277 part.UUID, remoteClient.AgentId))
256 EventManager.TriggerParcelPrimCountTainted(); 278 EventManager.TriggerParcelPrimCountTainted();
257 } 279 }
280 */
281
282 bool oldgprSelect = part.ParentGroup.IsSelected;
283
284 // This is wrong, wrong, wrong. Selection should not be
285 // handled by group, but by prim. Legacy cruft.
286 // TODO: Make selection flagging per prim!
287 //
288 if (Permissions.CanEditObject(part.ParentGroup.UUID, remoteClient.AgentId)
289 || Permissions.CanMoveObject(part.ParentGroup.UUID, remoteClient.AgentId))
290 {
291 part.IsSelected = false;
292 if (!part.ParentGroup.IsAttachment && oldgprSelect != part.ParentGroup.IsSelected)
293 EventManager.TriggerParcelPrimCountTainted();
294 }
295
258 } 296 }
259 297
260 public virtual void ProcessMoneyTransferRequest(UUID source, UUID destination, int amount, 298 public virtual void ProcessMoneyTransferRequest(UUID source, UUID destination, int amount,
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index 4d0aa6f..ff2c46f 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -119,6 +119,7 @@ namespace OpenSim.Region.Framework.Scenes
119 // TODO: need to figure out how allow client agents but deny 119 // TODO: need to figure out how allow client agents but deny
120 // root agents when ACL denies access to root agent 120 // root agents when ACL denies access to root agent
121 public bool m_strictAccessControl = true; 121 public bool m_strictAccessControl = true;
122 public bool m_seeIntoBannedRegion = false;
122 public int MaxUndoCount = 5; 123 public int MaxUndoCount = 5;
123 // Using this for RegionReady module to prevent LoginsDisabled from changing under our feet; 124 // Using this for RegionReady module to prevent LoginsDisabled from changing under our feet;
124 public bool LoginLock = false; 125 public bool LoginLock = false;
@@ -134,12 +135,14 @@ namespace OpenSim.Region.Framework.Scenes
134 135
135 protected int m_splitRegionID; 136 protected int m_splitRegionID;
136 protected Timer m_restartWaitTimer = new Timer(); 137 protected Timer m_restartWaitTimer = new Timer();
138 protected Timer m_timerWatchdog = new Timer();
137 protected List<RegionInfo> m_regionRestartNotifyList = new List<RegionInfo>(); 139 protected List<RegionInfo> m_regionRestartNotifyList = new List<RegionInfo>();
138 protected List<RegionInfo> m_neighbours = new List<RegionInfo>(); 140 protected List<RegionInfo> m_neighbours = new List<RegionInfo>();
139 protected string m_simulatorVersion = "OpenSimulator Server"; 141 protected string m_simulatorVersion = "OpenSimulator Server";
140 protected ModuleLoader m_moduleLoader; 142 protected ModuleLoader m_moduleLoader;
141 protected AgentCircuitManager m_authenticateHandler; 143 protected AgentCircuitManager m_authenticateHandler;
142 protected SceneCommunicationService m_sceneGridService; 144 protected SceneCommunicationService m_sceneGridService;
145 protected ISnmpModule m_snmpService = null;
143 146
144 protected ISimulationDataService m_SimulationDataService; 147 protected ISimulationDataService m_SimulationDataService;
145 protected IEstateDataService m_EstateDataService; 148 protected IEstateDataService m_EstateDataService;
@@ -202,7 +205,7 @@ namespace OpenSim.Region.Framework.Scenes
202 private int m_update_events = 1; 205 private int m_update_events = 1;
203 private int m_update_backup = 200; 206 private int m_update_backup = 200;
204 private int m_update_terrain = 50; 207 private int m_update_terrain = 50;
205// private int m_update_land = 1; 208 private int m_update_land = 10;
206 private int m_update_coarse_locations = 50; 209 private int m_update_coarse_locations = 50;
207 210
208 private int agentMS; 211 private int agentMS;
@@ -221,6 +224,7 @@ namespace OpenSim.Region.Framework.Scenes
221 /// </summary> 224 /// </summary>
222 private int m_lastFrameTick; 225 private int m_lastFrameTick;
223 226
227 public bool CombineRegions = false;
224 /// <summary> 228 /// <summary>
225 /// Tick at which the last maintenance run occurred. 229 /// Tick at which the last maintenance run occurred.
226 /// </summary> 230 /// </summary>
@@ -251,6 +255,11 @@ namespace OpenSim.Region.Framework.Scenes
251 /// </summary> 255 /// </summary>
252 private int m_LastLogin; 256 private int m_LastLogin;
253 257
258 private int m_lastIncoming;
259 private int m_lastOutgoing;
260 private int m_hbRestarts = 0;
261
262
254 /// <summary> 263 /// <summary>
255 /// Thread that runs the scene loop. 264 /// Thread that runs the scene loop.
256 /// </summary> 265 /// </summary>
@@ -266,7 +275,7 @@ namespace OpenSim.Region.Framework.Scenes
266 private volatile bool m_shuttingDown; 275 private volatile bool m_shuttingDown;
267 276
268// private int m_lastUpdate; 277// private int m_lastUpdate;
269// private bool m_firstHeartbeat = true; 278 private bool m_firstHeartbeat = true;
270 279
271 private UpdatePrioritizationSchemes m_priorityScheme = UpdatePrioritizationSchemes.Time; 280 private UpdatePrioritizationSchemes m_priorityScheme = UpdatePrioritizationSchemes.Time;
272 private bool m_reprioritizationEnabled = true; 281 private bool m_reprioritizationEnabled = true;
@@ -311,6 +320,19 @@ namespace OpenSim.Region.Framework.Scenes
311 get { return m_sceneGridService; } 320 get { return m_sceneGridService; }
312 } 321 }
313 322
323 public ISnmpModule SnmpService
324 {
325 get
326 {
327 if (m_snmpService == null)
328 {
329 m_snmpService = RequestModuleInterface<ISnmpModule>();
330 }
331
332 return m_snmpService;
333 }
334 }
335
314 public ISimulationDataService SimulationDataService 336 public ISimulationDataService SimulationDataService
315 { 337 {
316 get 338 get
@@ -594,6 +616,8 @@ namespace OpenSim.Region.Framework.Scenes
594 m_EstateDataService = estateDataService; 616 m_EstateDataService = estateDataService;
595 m_regionHandle = m_regInfo.RegionHandle; 617 m_regionHandle = m_regInfo.RegionHandle;
596 m_regionName = m_regInfo.RegionName; 618 m_regionName = m_regInfo.RegionName;
619 m_lastIncoming = 0;
620 m_lastOutgoing = 0;
597 621
598 m_asyncSceneObjectDeleter = new AsyncSceneObjectGroupDeleter(this); 622 m_asyncSceneObjectDeleter = new AsyncSceneObjectGroupDeleter(this);
599 m_asyncSceneObjectDeleter.Enabled = true; 623 m_asyncSceneObjectDeleter.Enabled = true;
@@ -674,99 +698,108 @@ namespace OpenSim.Region.Framework.Scenes
674 698
675 // Region config overrides global config 699 // Region config overrides global config
676 // 700 //
677 if (m_config.Configs["Startup"] != null) 701 try
678 { 702 {
679 IConfig startupConfig = m_config.Configs["Startup"]; 703 if (m_config.Configs["Startup"] != null)
680
681 m_defaultDrawDistance = startupConfig.GetFloat("DefaultDrawDistance",m_defaultDrawDistance);
682 m_useBackup = startupConfig.GetBoolean("UseSceneBackup", m_useBackup);
683 if (!m_useBackup)
684 m_log.InfoFormat("[SCENE]: Backup has been disabled for {0}", RegionInfo.RegionName);
685
686 //Animation states
687 m_useFlySlow = startupConfig.GetBoolean("enableflyslow", false);
688
689 PhysicalPrims = startupConfig.GetBoolean("physical_prim", PhysicalPrims);
690 CollidablePrims = startupConfig.GetBoolean("collidable_prim", CollidablePrims);
691
692 m_maxNonphys = startupConfig.GetFloat("NonphysicalPrimMax", m_maxNonphys);
693 if (RegionInfo.NonphysPrimMax > 0)
694 { 704 {
695 m_maxNonphys = RegionInfo.NonphysPrimMax; 705 IConfig startupConfig = m_config.Configs["Startup"];
696 }
697
698 m_maxPhys = startupConfig.GetFloat("PhysicalPrimMax", m_maxPhys);
699 706
700 if (RegionInfo.PhysPrimMax > 0) 707 m_defaultDrawDistance = startupConfig.GetFloat("DefaultDrawDistance",m_defaultDrawDistance);
701 { 708 m_useBackup = startupConfig.GetBoolean("UseSceneBackup", m_useBackup);
702 m_maxPhys = RegionInfo.PhysPrimMax; 709 if (!m_useBackup)
703 } 710 m_log.InfoFormat("[SCENE]: Backup has been disabled for {0}", RegionInfo.RegionName);
711
712 //Animation states
713 m_useFlySlow = startupConfig.GetBoolean("enableflyslow", false);
704 714
705 // Here, if clamping is requested in either global or 715 PhysicalPrims = startupConfig.GetBoolean("physical_prim", true);
706 // local config, it will be used 716 CollidablePrims = startupConfig.GetBoolean("collidable_prim", true);
707 //
708 m_clampPrimSize = startupConfig.GetBoolean("ClampPrimSize", m_clampPrimSize);
709 if (RegionInfo.ClampPrimSize)
710 {
711 m_clampPrimSize = true;
712 }
713 717
714 m_useTrashOnDelete = startupConfig.GetBoolean("UseTrashOnDelete",m_useTrashOnDelete); 718 m_maxNonphys = startupConfig.GetFloat("NonphysicalPrimMax", m_maxNonphys);
715 m_trustBinaries = startupConfig.GetBoolean("TrustBinaries", m_trustBinaries); 719 if (RegionInfo.NonphysPrimMax > 0)
716 m_allowScriptCrossings = startupConfig.GetBoolean("AllowScriptCrossing", m_allowScriptCrossings); 720 {
717 m_dontPersistBefore = 721 m_maxNonphys = RegionInfo.NonphysPrimMax;
718 startupConfig.GetLong("MinimumTimeBeforePersistenceConsidered", DEFAULT_MIN_TIME_FOR_PERSISTENCE); 722 }
719 m_dontPersistBefore *= 10000000;
720 m_persistAfter =
721 startupConfig.GetLong("MaximumTimeBeforePersistenceConsidered", DEFAULT_MAX_TIME_FOR_PERSISTENCE);
722 m_persistAfter *= 10000000;
723 723
724 m_defaultScriptEngine = startupConfig.GetString("DefaultScriptEngine", "XEngine"); 724 m_maxPhys = startupConfig.GetFloat("PhysicalPrimMax", m_maxPhys);
725 725
726 IConfig packetConfig = m_config.Configs["PacketPool"]; 726 if (RegionInfo.PhysPrimMax > 0)
727 if (packetConfig != null) 727 {
728 { 728 m_maxPhys = RegionInfo.PhysPrimMax;
729 PacketPool.Instance.RecyclePackets = packetConfig.GetBoolean("RecyclePackets", true); 729 }
730 PacketPool.Instance.RecycleDataBlocks = packetConfig.GetBoolean("RecycleDataBlocks", true);
731 }
732 730
733 m_strictAccessControl = startupConfig.GetBoolean("StrictAccessControl", m_strictAccessControl); 731 // Here, if clamping is requested in either global or
732 // local config, it will be used
733 //
734 m_clampPrimSize = startupConfig.GetBoolean("ClampPrimSize", m_clampPrimSize);
735 if (RegionInfo.ClampPrimSize)
736 {
737 m_clampPrimSize = true;
738 }
734 739
735 m_generateMaptiles = startupConfig.GetBoolean("GenerateMaptiles", true); 740 m_useTrashOnDelete = startupConfig.GetBoolean("UseTrashOnDelete",m_useTrashOnDelete);
736 if (m_generateMaptiles) 741 m_trustBinaries = startupConfig.GetBoolean("TrustBinaries", m_trustBinaries);
737 { 742 m_allowScriptCrossings = startupConfig.GetBoolean("AllowScriptCrossing", m_allowScriptCrossings);
738 int maptileRefresh = startupConfig.GetInt("MaptileRefresh", 0); 743 m_dontPersistBefore =
739 if (maptileRefresh != 0) 744 startupConfig.GetLong("MinimumTimeBeforePersistenceConsidered", DEFAULT_MIN_TIME_FOR_PERSISTENCE);
745 m_dontPersistBefore *= 10000000;
746 m_persistAfter =
747 startupConfig.GetLong("MaximumTimeBeforePersistenceConsidered", DEFAULT_MAX_TIME_FOR_PERSISTENCE);
748 m_persistAfter *= 10000000;
749
750 m_defaultScriptEngine = startupConfig.GetString("DefaultScriptEngine", "XEngine");
751 m_log.InfoFormat("[SCENE]: Default script engine {0}", m_defaultScriptEngine);
752
753 IConfig packetConfig = m_config.Configs["PacketPool"];
754 if (packetConfig != null)
740 { 755 {
741 m_mapGenerationTimer.Interval = maptileRefresh * 1000; 756 PacketPool.Instance.RecyclePackets = packetConfig.GetBoolean("RecyclePackets", true);
742 m_mapGenerationTimer.Elapsed += RegenerateMaptileAndReregister; 757 PacketPool.Instance.RecycleDataBlocks = packetConfig.GetBoolean("RecycleDataBlocks", true);
743 m_mapGenerationTimer.AutoReset = true;
744 m_mapGenerationTimer.Start();
745 } 758 }
746 }
747 else
748 {
749 string tile = startupConfig.GetString("MaptileStaticUUID", UUID.Zero.ToString());
750 UUID tileID;
751 759
752 if (UUID.TryParse(tile, out tileID)) 760 m_strictAccessControl = startupConfig.GetBoolean("StrictAccessControl", m_strictAccessControl);
761 m_seeIntoBannedRegion = startupConfig.GetBoolean("SeeIntoBannedRegion", m_seeIntoBannedRegion);
762 CombineRegions = startupConfig.GetBoolean("CombineContiguousRegions", false);
763
764 m_generateMaptiles = startupConfig.GetBoolean("GenerateMaptiles", true);
765 if (m_generateMaptiles)
753 { 766 {
754 RegionInfo.RegionSettings.TerrainImageID = tileID; 767 int maptileRefresh = startupConfig.GetInt("MaptileRefresh", 0);
768 if (maptileRefresh != 0)
769 {
770 m_mapGenerationTimer.Interval = maptileRefresh * 1000;
771 m_mapGenerationTimer.Elapsed += RegenerateMaptileAndReregister;
772 m_mapGenerationTimer.AutoReset = true;
773 m_mapGenerationTimer.Start();
774 }
755 } 775 }
756 } 776 else
777 {
778 string tile = startupConfig.GetString("MaptileStaticUUID", UUID.Zero.ToString());
779 UUID tileID;
757 780
758 MinFrameTime = startupConfig.GetFloat( "MinFrameTime", MinFrameTime); 781 if (UUID.TryParse(tile, out tileID))
759 m_update_backup = startupConfig.GetInt( "UpdateStorageEveryNFrames", m_update_backup); 782 {
760 m_update_coarse_locations = startupConfig.GetInt( "UpdateCoarseLocationsEveryNFrames", m_update_coarse_locations); 783 RegionInfo.RegionSettings.TerrainImageID = tileID;
761 m_update_entitymovement = startupConfig.GetInt( "UpdateEntityMovementEveryNFrames", m_update_entitymovement); 784 }
762 m_update_events = startupConfig.GetInt( "UpdateEventsEveryNFrames", m_update_events); 785 }
763 m_update_objects = startupConfig.GetInt( "UpdateObjectsEveryNFrames", m_update_objects);
764 m_update_physics = startupConfig.GetInt( "UpdatePhysicsEveryNFrames", m_update_physics);
765 m_update_presences = startupConfig.GetInt( "UpdateAgentsEveryNFrames", m_update_presences);
766 m_update_terrain = startupConfig.GetInt( "UpdateTerrainEveryNFrames", m_update_terrain);
767 m_update_temp_cleaning = startupConfig.GetInt( "UpdateTempCleaningEveryNFrames", m_update_temp_cleaning);
768 786
769 SendPeriodicAppearanceUpdates = startupConfig.GetBoolean("SendPeriodicAppearanceUpdates", SendPeriodicAppearanceUpdates); 787 MinFrameTime = startupConfig.GetFloat( "MinFrameTime", MinFrameTime);
788 m_update_backup = startupConfig.GetInt( "UpdateStorageEveryNFrames", m_update_backup);
789 m_update_coarse_locations = startupConfig.GetInt( "UpdateCoarseLocationsEveryNFrames", m_update_coarse_locations);
790 m_update_entitymovement = startupConfig.GetInt( "UpdateEntityMovementEveryNFrames", m_update_entitymovement);
791 m_update_events = startupConfig.GetInt( "UpdateEventsEveryNFrames", m_update_events);
792 m_update_objects = startupConfig.GetInt( "UpdateObjectsEveryNFrames", m_update_objects);
793 m_update_physics = startupConfig.GetInt( "UpdatePhysicsEveryNFrames", m_update_physics);
794 m_update_presences = startupConfig.GetInt( "UpdateAgentsEveryNFrames", m_update_presences);
795 m_update_terrain = startupConfig.GetInt( "UpdateTerrainEveryNFrames", m_update_terrain);
796 m_update_temp_cleaning = startupConfig.GetInt( "UpdateTempCleaningEveryNFrames", m_update_temp_cleaning);
797 SendPeriodicAppearanceUpdates = startupConfig.GetBoolean("SendPeriodicAppearanceUpdates", SendPeriodicAppearanceUpdates);
798 }
799 }
800 catch (Exception e)
801 {
802 m_log.Error("[SCENE]: Failed to load StartupConfig: " + e.ToString());
770 } 803 }
771 804
772 #endregion Region Config 805 #endregion Region Config
@@ -1193,7 +1226,22 @@ namespace OpenSim.Region.Framework.Scenes
1193 //m_heartbeatTimer.Elapsed += new ElapsedEventHandler(Heartbeat); 1226 //m_heartbeatTimer.Elapsed += new ElapsedEventHandler(Heartbeat);
1194 if (m_heartbeatThread != null) 1227 if (m_heartbeatThread != null)
1195 { 1228 {
1229 m_hbRestarts++;
1230 if(m_hbRestarts > 10)
1231 Environment.Exit(1);
1232 m_log.ErrorFormat("[SCENE]: Restarting heartbeat thread because it hasn't reported in in region {0}", RegionInfo.RegionName);
1233
1234//int pid = System.Diagnostics.Process.GetCurrentProcess().Id;
1235//System.Diagnostics.Process proc = new System.Diagnostics.Process();
1236//proc.EnableRaisingEvents=false;
1237//proc.StartInfo.FileName = "/bin/kill";
1238//proc.StartInfo.Arguments = "-QUIT " + pid.ToString();
1239//proc.Start();
1240//proc.WaitForExit();
1241//Thread.Sleep(1000);
1242//Environment.Exit(1);
1196 m_heartbeatThread.Abort(); 1243 m_heartbeatThread.Abort();
1244 Watchdog.AbortThread(m_heartbeatThread.ManagedThreadId);
1197 m_heartbeatThread = null; 1245 m_heartbeatThread = null;
1198 } 1246 }
1199// m_lastUpdate = Util.EnvironmentTickCount(); 1247// m_lastUpdate = Util.EnvironmentTickCount();
@@ -1341,10 +1389,12 @@ namespace OpenSim.Region.Framework.Scenes
1341 int tmpPhysicsMS, tmpPhysicsMS2, tmpAgentMS, tmpTempOnRezMS, evMS, backMS, terMS; 1389 int tmpPhysicsMS, tmpPhysicsMS2, tmpAgentMS, tmpTempOnRezMS, evMS, backMS, terMS;
1342 int previousFrameTick; 1390 int previousFrameTick;
1343 int maintc; 1391 int maintc;
1392 int sleepMS;
1393 int framestart;
1344 1394
1345 while (!m_shuttingDown && (endFrame == null || Frame < endFrame)) 1395 while (!m_shuttingDown && (endFrame == null || Frame < endFrame))
1346 { 1396 {
1347 maintc = Util.EnvironmentTickCount(); 1397 framestart = Util.EnvironmentTickCount();
1348 ++Frame; 1398 ++Frame;
1349 1399
1350// m_log.DebugFormat("[SCENE]: Processing frame {0} in {1}", Frame, RegionInfo.RegionName); 1400// m_log.DebugFormat("[SCENE]: Processing frame {0} in {1}", Frame, RegionInfo.RegionName);
@@ -1431,7 +1481,7 @@ namespace OpenSim.Region.Framework.Scenes
1431 // landMS = Util.EnvironmentTickCountSubtract(ldMS); 1481 // landMS = Util.EnvironmentTickCountSubtract(ldMS);
1432 //} 1482 //}
1433 1483
1434 frameMS = Util.EnvironmentTickCountSubtract(maintc); 1484 // frameMS = Util.EnvironmentTickCountSubtract(maintc);
1435 otherMS = tempOnRezMS + eventMS + backupMS + terrainMS + landMS; 1485 otherMS = tempOnRezMS + eventMS + backupMS + terrainMS + landMS;
1436 1486
1437 // if (Frame%m_update_avatars == 0) 1487 // if (Frame%m_update_avatars == 0)
@@ -1446,7 +1496,7 @@ namespace OpenSim.Region.Framework.Scenes
1446 1496
1447 // frameMS currently records work frame times, not total frame times (work + any required sleep to 1497 // frameMS currently records work frame times, not total frame times (work + any required sleep to
1448 // reach min frame time. 1498 // reach min frame time.
1449 StatsReporter.addFrameMS(frameMS); 1499 // StatsReporter.addFrameMS(frameMS);
1450 1500
1451 StatsReporter.addAgentMS(agentMS); 1501 StatsReporter.addAgentMS(agentMS);
1452 StatsReporter.addPhysicsMS(physicsMS + physicsMS2); 1502 StatsReporter.addPhysicsMS(physicsMS + physicsMS2);
@@ -1503,12 +1553,22 @@ namespace OpenSim.Region.Framework.Scenes
1503 1553
1504 previousFrameTick = m_lastFrameTick; 1554 previousFrameTick = m_lastFrameTick;
1505 m_lastFrameTick = Util.EnvironmentTickCount(); 1555 m_lastFrameTick = Util.EnvironmentTickCount();
1506 maintc = Util.EnvironmentTickCountSubtract(m_lastFrameTick, maintc); 1556 maintc = Util.EnvironmentTickCountSubtract(m_lastFrameTick, framestart);
1507 maintc = (int)(MinFrameTime * 1000) - maintc; 1557 maintc = (int)(MinFrameTime * 1000) - maintc;
1508 1558
1559 m_firstHeartbeat = false;
1560
1561
1562 sleepMS = Util.EnvironmentTickCount();
1563
1509 if (maintc > 0) 1564 if (maintc > 0)
1510 Thread.Sleep(maintc); 1565 Thread.Sleep(maintc);
1511 1566
1567 sleepMS = Util.EnvironmentTickCountSubtract(sleepMS);
1568 frameMS = Util.EnvironmentTickCountSubtract(framestart);
1569 StatsReporter.addSleepMS(sleepMS);
1570 StatsReporter.addFrameMS(frameMS);
1571
1512 // Optionally warn if a frame takes double the amount of time that it should. 1572 // Optionally warn if a frame takes double the amount of time that it should.
1513 if (DebugUpdates 1573 if (DebugUpdates
1514 && Util.EnvironmentTickCountSubtract( 1574 && Util.EnvironmentTickCountSubtract(
@@ -1535,9 +1595,9 @@ namespace OpenSim.Region.Framework.Scenes
1535 1595
1536 private void CheckAtTargets() 1596 private void CheckAtTargets()
1537 { 1597 {
1538 Dictionary<UUID, SceneObjectGroup>.ValueCollection objs; 1598 List<SceneObjectGroup> objs = new List<SceneObjectGroup>();
1539 lock (m_groupsWithTargets) 1599 lock (m_groupsWithTargets)
1540 objs = m_groupsWithTargets.Values; 1600 objs = new List<SceneObjectGroup>(m_groupsWithTargets.Values);
1541 1601
1542 foreach (SceneObjectGroup entry in objs) 1602 foreach (SceneObjectGroup entry in objs)
1543 entry.checkAtTargets(); 1603 entry.checkAtTargets();
@@ -1618,7 +1678,7 @@ namespace OpenSim.Region.Framework.Scenes
1618 msg.fromAgentName = "Server"; 1678 msg.fromAgentName = "Server";
1619 msg.dialog = (byte)19; // Object msg 1679 msg.dialog = (byte)19; // Object msg
1620 msg.fromGroup = false; 1680 msg.fromGroup = false;
1621 msg.offline = (byte)0; 1681 msg.offline = (byte)1;
1622 msg.ParentEstateID = RegionInfo.EstateSettings.ParentEstateID; 1682 msg.ParentEstateID = RegionInfo.EstateSettings.ParentEstateID;
1623 msg.Position = Vector3.Zero; 1683 msg.Position = Vector3.Zero;
1624 msg.RegionID = RegionInfo.RegionID.Guid; 1684 msg.RegionID = RegionInfo.RegionID.Guid;
@@ -1840,6 +1900,19 @@ namespace OpenSim.Region.Framework.Scenes
1840 EventManager.TriggerPrimsLoaded(this); 1900 EventManager.TriggerPrimsLoaded(this);
1841 } 1901 }
1842 1902
1903 public bool SuportsRayCastFiltered()
1904 {
1905 if (PhysicsScene == null)
1906 return false;
1907 return PhysicsScene.SuportsRaycastWorldFiltered();
1908 }
1909
1910 public object RayCastFiltered(Vector3 position, Vector3 direction, float length, int Count, RayFilterFlags filter)
1911 {
1912 if (PhysicsScene == null)
1913 return null;
1914 return PhysicsScene.RaycastWorld(position, direction, length, Count,filter);
1915 }
1843 1916
1844 /// <summary> 1917 /// <summary>
1845 /// Gets a new rez location based on the raycast and the size of the object that is being rezzed. 1918 /// Gets a new rez location based on the raycast and the size of the object that is being rezzed.
@@ -1856,14 +1929,24 @@ namespace OpenSim.Region.Framework.Scenes
1856 /// <returns></returns> 1929 /// <returns></returns>
1857 public Vector3 GetNewRezLocation(Vector3 RayStart, Vector3 RayEnd, UUID RayTargetID, Quaternion rot, byte bypassRayCast, byte RayEndIsIntersection, bool frontFacesOnly, Vector3 scale, bool FaceCenter) 1930 public Vector3 GetNewRezLocation(Vector3 RayStart, Vector3 RayEnd, UUID RayTargetID, Quaternion rot, byte bypassRayCast, byte RayEndIsIntersection, bool frontFacesOnly, Vector3 scale, bool FaceCenter)
1858 { 1931 {
1932
1933 float wheight = (float)RegionInfo.RegionSettings.WaterHeight;
1934 Vector3 wpos = Vector3.Zero;
1935 // Check for water surface intersection from above
1936 if ( (RayStart.Z > wheight) && (RayEnd.Z < wheight) )
1937 {
1938 float ratio = (RayStart.Z - wheight) / (RayStart.Z - RayEnd.Z);
1939 wpos.X = RayStart.X - (ratio * (RayStart.X - RayEnd.X));
1940 wpos.Y = RayStart.Y - (ratio * (RayStart.Y - RayEnd.Y));
1941 wpos.Z = wheight;
1942 }
1943
1859 Vector3 pos = Vector3.Zero; 1944 Vector3 pos = Vector3.Zero;
1860 if (RayEndIsIntersection == (byte)1) 1945 if (RayEndIsIntersection == (byte)1)
1861 { 1946 {
1862 pos = RayEnd; 1947 pos = RayEnd;
1863 return pos;
1864 } 1948 }
1865 1949 else if (RayTargetID != UUID.Zero)
1866 if (RayTargetID != UUID.Zero)
1867 { 1950 {
1868 SceneObjectPart target = GetSceneObjectPart(RayTargetID); 1951 SceneObjectPart target = GetSceneObjectPart(RayTargetID);
1869 1952
@@ -1885,7 +1968,7 @@ namespace OpenSim.Region.Framework.Scenes
1885 EntityIntersection ei = target.TestIntersectionOBB(NewRay, Quaternion.Identity, frontFacesOnly, FaceCenter); 1968 EntityIntersection ei = target.TestIntersectionOBB(NewRay, Quaternion.Identity, frontFacesOnly, FaceCenter);
1886 1969
1887 // Un-comment out the following line to Get Raytrace results printed to the console. 1970 // Un-comment out the following line to Get Raytrace results printed to the console.
1888 // m_log.Info("[RAYTRACERESULTS]: Hit:" + ei.HitTF.ToString() + " Point: " + ei.ipoint.ToString() + " Normal: " + ei.normal.ToString()); 1971 // m_log.Info("[RAYTRACERESULTS]: Hit:" + ei.HitTF.ToString() + " Point: " + ei.ipoint.ToString() + " Normal: " + ei.normal.ToString());
1889 float ScaleOffset = 0.5f; 1972 float ScaleOffset = 0.5f;
1890 1973
1891 // If we hit something 1974 // If we hit something
@@ -1908,13 +1991,10 @@ namespace OpenSim.Region.Framework.Scenes
1908 //pos.Z -= 0.25F; 1991 //pos.Z -= 0.25F;
1909 1992
1910 } 1993 }
1911
1912 return pos;
1913 } 1994 }
1914 else 1995 else
1915 { 1996 {
1916 // We don't have a target here, so we're going to raytrace all the objects in the scene. 1997 // We don't have a target here, so we're going to raytrace all the objects in the scene.
1917
1918 EntityIntersection ei = m_sceneGraph.GetClosestIntersectingPrim(new Ray(AXOrigin, AXdirection), true, false); 1998 EntityIntersection ei = m_sceneGraph.GetClosestIntersectingPrim(new Ray(AXOrigin, AXdirection), true, false);
1919 1999
1920 // Un-comment the following line to print the raytrace results to the console. 2000 // Un-comment the following line to print the raytrace results to the console.
@@ -1923,13 +2003,12 @@ namespace OpenSim.Region.Framework.Scenes
1923 if (ei.HitTF) 2003 if (ei.HitTF)
1924 { 2004 {
1925 pos = new Vector3(ei.ipoint.X, ei.ipoint.Y, ei.ipoint.Z); 2005 pos = new Vector3(ei.ipoint.X, ei.ipoint.Y, ei.ipoint.Z);
1926 } else 2006 }
2007 else
1927 { 2008 {
1928 // fall back to our stupid functionality 2009 // fall back to our stupid functionality
1929 pos = RayEnd; 2010 pos = RayEnd;
1930 } 2011 }
1931
1932 return pos;
1933 } 2012 }
1934 } 2013 }
1935 else 2014 else
@@ -1940,8 +2019,12 @@ namespace OpenSim.Region.Framework.Scenes
1940 //increase height so its above the ground. 2019 //increase height so its above the ground.
1941 //should be getting the normal of the ground at the rez point and using that? 2020 //should be getting the normal of the ground at the rez point and using that?
1942 pos.Z += scale.Z / 2f; 2021 pos.Z += scale.Z / 2f;
1943 return pos; 2022// return pos;
1944 } 2023 }
2024
2025 // check against posible water intercept
2026 if (wpos.Z > pos.Z) pos = wpos;
2027 return pos;
1945 } 2028 }
1946 2029
1947 2030
@@ -2031,7 +2114,10 @@ namespace OpenSim.Region.Framework.Scenes
2031 public bool AddRestoredSceneObject( 2114 public bool AddRestoredSceneObject(
2032 SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates) 2115 SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates)
2033 { 2116 {
2034 return m_sceneGraph.AddRestoredSceneObject(sceneObject, attachToBackup, alreadyPersisted, sendClientUpdates); 2117 bool result = m_sceneGraph.AddRestoredSceneObject(sceneObject, attachToBackup, alreadyPersisted, sendClientUpdates);
2118 if (result)
2119 sceneObject.IsDeleted = false;
2120 return result;
2035 } 2121 }
2036 2122
2037 /// <summary> 2123 /// <summary>
@@ -2123,6 +2209,15 @@ namespace OpenSim.Region.Framework.Scenes
2123 /// </summary> 2209 /// </summary>
2124 public void DeleteAllSceneObjects() 2210 public void DeleteAllSceneObjects()
2125 { 2211 {
2212 DeleteAllSceneObjects(false);
2213 }
2214
2215 /// <summary>
2216 /// Delete every object from the scene. This does not include attachments worn by avatars.
2217 /// </summary>
2218 public void DeleteAllSceneObjects(bool exceptNoCopy)
2219 {
2220 List<SceneObjectGroup> toReturn = new List<SceneObjectGroup>();
2126 lock (Entities) 2221 lock (Entities)
2127 { 2222 {
2128 EntityBase[] entities = Entities.GetEntities(); 2223 EntityBase[] entities = Entities.GetEntities();
@@ -2131,11 +2226,24 @@ namespace OpenSim.Region.Framework.Scenes
2131 if (e is SceneObjectGroup) 2226 if (e is SceneObjectGroup)
2132 { 2227 {
2133 SceneObjectGroup sog = (SceneObjectGroup)e; 2228 SceneObjectGroup sog = (SceneObjectGroup)e;
2134 if (!sog.IsAttachment) 2229 if (sog != null && !sog.IsAttachment)
2135 DeleteSceneObject((SceneObjectGroup)e, false); 2230 {
2231 if (!exceptNoCopy || ((sog.GetEffectivePermissions() & (uint)PermissionMask.Copy) != 0))
2232 {
2233 DeleteSceneObject((SceneObjectGroup)e, false);
2234 }
2235 else
2236 {
2237 toReturn.Add((SceneObjectGroup)e);
2238 }
2239 }
2136 } 2240 }
2137 } 2241 }
2138 } 2242 }
2243 if (toReturn.Count > 0)
2244 {
2245 returnObjects(toReturn.ToArray(), UUID.Zero);
2246 }
2139 } 2247 }
2140 2248
2141 /// <summary> 2249 /// <summary>
@@ -2170,6 +2278,8 @@ namespace OpenSim.Region.Framework.Scenes
2170 } 2278 }
2171 2279
2172 group.DeleteGroupFromScene(silent); 2280 group.DeleteGroupFromScene(silent);
2281 if (!silent)
2282 SendKillObject(new List<uint>() { group.LocalId });
2173 2283
2174// m_log.DebugFormat("[SCENE]: Exit DeleteSceneObject() for {0} {1}", group.Name, group.UUID); 2284// m_log.DebugFormat("[SCENE]: Exit DeleteSceneObject() for {0} {1}", group.Name, group.UUID);
2175 } 2285 }
@@ -2459,6 +2569,8 @@ namespace OpenSim.Region.Framework.Scenes
2459 2569
2460 if (newPosition != Vector3.Zero) 2570 if (newPosition != Vector3.Zero)
2461 newObject.RootPart.GroupPosition = newPosition; 2571 newObject.RootPart.GroupPosition = newPosition;
2572 if (newObject.RootPart.KeyframeMotion != null)
2573 newObject.RootPart.KeyframeMotion.UpdateSceneObject(newObject);
2462 2574
2463 if (!AddSceneObject(newObject)) 2575 if (!AddSceneObject(newObject))
2464 { 2576 {
@@ -2527,10 +2639,17 @@ namespace OpenSim.Region.Framework.Scenes
2527 /// <returns>True if the SceneObjectGroup was added, False if it was not</returns> 2639 /// <returns>True if the SceneObjectGroup was added, False if it was not</returns>
2528 public bool AddSceneObject(SceneObjectGroup sceneObject) 2640 public bool AddSceneObject(SceneObjectGroup sceneObject)
2529 { 2641 {
2642 if (sceneObject.OwnerID == UUID.Zero)
2643 {
2644 m_log.ErrorFormat("[SCENE]: Owner ID for {0} was zero", sceneObject.UUID);
2645 return false;
2646 }
2647
2530 // If the user is banned, we won't let any of their objects 2648 // If the user is banned, we won't let any of their objects
2531 // enter. Period. 2649 // enter. Period.
2532 // 2650 //
2533 if (m_regInfo.EstateSettings.IsBanned(sceneObject.OwnerID)) 2651 int flags = GetUserFlags(sceneObject.OwnerID);
2652 if (m_regInfo.EstateSettings.IsBanned(sceneObject.OwnerID, flags))
2534 { 2653 {
2535 m_log.InfoFormat("[INTERREGION]: Denied prim crossing for banned avatar {0}", sceneObject.OwnerID); 2654 m_log.InfoFormat("[INTERREGION]: Denied prim crossing for banned avatar {0}", sceneObject.OwnerID);
2536 2655
@@ -2576,12 +2695,23 @@ namespace OpenSim.Region.Framework.Scenes
2576 } 2695 }
2577 else 2696 else
2578 { 2697 {
2698 m_log.DebugFormat("[SCENE]: Attachment {0} arrived and scene presence was not found, setting to temp", sceneObject.UUID);
2579 RootPrim.RemFlag(PrimFlags.TemporaryOnRez); 2699 RootPrim.RemFlag(PrimFlags.TemporaryOnRez);
2580 RootPrim.AddFlag(PrimFlags.TemporaryOnRez); 2700 RootPrim.AddFlag(PrimFlags.TemporaryOnRez);
2581 } 2701 }
2702 if (sceneObject.OwnerID == UUID.Zero)
2703 {
2704 m_log.ErrorFormat("[SCENE]: Owner ID for {0} was zero after attachment processing. BUG!", sceneObject.UUID);
2705 return false;
2706 }
2582 } 2707 }
2583 else 2708 else
2584 { 2709 {
2710 if (sceneObject.OwnerID == UUID.Zero)
2711 {
2712 m_log.ErrorFormat("[SCENE]: Owner ID for non-attachment {0} was zero", sceneObject.UUID);
2713 return false;
2714 }
2585 AddRestoredSceneObject(sceneObject, true, false); 2715 AddRestoredSceneObject(sceneObject, true, false);
2586 2716
2587 if (!Permissions.CanObjectEntry(sceneObject.UUID, 2717 if (!Permissions.CanObjectEntry(sceneObject.UUID,
@@ -2610,6 +2740,24 @@ namespace OpenSim.Region.Framework.Scenes
2610 return 2; // StateSource.PrimCrossing 2740 return 2; // StateSource.PrimCrossing
2611 } 2741 }
2612 2742
2743 public int GetUserFlags(UUID user)
2744 {
2745 //Unfortunately the SP approach means that the value is cached until region is restarted
2746 /*
2747 ScenePresence sp;
2748 if (TryGetScenePresence(user, out sp))
2749 {
2750 return sp.UserFlags;
2751 }
2752 else
2753 {
2754 */
2755 UserAccount uac = UserAccountService.GetUserAccount(RegionInfo.ScopeID, user);
2756 if (uac == null)
2757 return 0;
2758 return uac.UserFlags;
2759 //}
2760 }
2613 #endregion 2761 #endregion
2614 2762
2615 #region Add/Remove Avatar Methods 2763 #region Add/Remove Avatar Methods
@@ -2623,7 +2771,7 @@ namespace OpenSim.Region.Framework.Scenes
2623 = (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0 2771 = (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0
2624 || (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaLogin) != 0; 2772 || (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaLogin) != 0;
2625 2773
2626// CheckHeartbeat(); 2774 CheckHeartbeat();
2627 2775
2628 ScenePresence sp = GetScenePresence(client.AgentId); 2776 ScenePresence sp = GetScenePresence(client.AgentId);
2629 2777
@@ -2676,7 +2824,13 @@ namespace OpenSim.Region.Framework.Scenes
2676 2824
2677 EventManager.TriggerOnNewClient(client); 2825 EventManager.TriggerOnNewClient(client);
2678 if (vialogin) 2826 if (vialogin)
2827 {
2679 EventManager.TriggerOnClientLogin(client); 2828 EventManager.TriggerOnClientLogin(client);
2829 // Send initial parcel data
2830 Vector3 pos = sp.AbsolutePosition;
2831 ILandObject land = LandChannel.GetLandObject(pos.X, pos.Y);
2832 land.SendLandUpdateToClient(client);
2833 }
2680 2834
2681 return sp; 2835 return sp;
2682 } 2836 }
@@ -2766,19 +2920,12 @@ namespace OpenSim.Region.Framework.Scenes
2766 // and the scene presence and the client, if they exist 2920 // and the scene presence and the client, if they exist
2767 try 2921 try
2768 { 2922 {
2769 // We need to wait for the client to make UDP contact first. 2923 ScenePresence sp = GetScenePresence(agentID);
2770 // It's the UDP contact that creates the scene presence 2924 PresenceService.LogoutAgent(sp.ControllingClient.SessionId);
2771 ScenePresence sp = WaitGetScenePresence(agentID); 2925
2772 if (sp != null) 2926 if (sp != null)
2773 {
2774 PresenceService.LogoutAgent(sp.ControllingClient.SessionId);
2775
2776 sp.ControllingClient.Close(); 2927 sp.ControllingClient.Close();
2777 } 2928
2778 else
2779 {
2780 m_log.WarnFormat("[SCENE]: Could not find scene presence for {0}", agentID);
2781 }
2782 // BANG! SLASH! 2929 // BANG! SLASH!
2783 m_authenticateHandler.RemoveCircuit(agentID); 2930 m_authenticateHandler.RemoveCircuit(agentID);
2784 2931
@@ -2823,6 +2970,8 @@ namespace OpenSim.Region.Framework.Scenes
2823 client.OnUpdatePrimGroupPosition += m_sceneGraph.UpdatePrimGroupPosition; 2970 client.OnUpdatePrimGroupPosition += m_sceneGraph.UpdatePrimGroupPosition;
2824 client.OnUpdatePrimSinglePosition += m_sceneGraph.UpdatePrimSinglePosition; 2971 client.OnUpdatePrimSinglePosition += m_sceneGraph.UpdatePrimSinglePosition;
2825 2972
2973 client.onClientChangeObject += m_sceneGraph.ClientChangeObject;
2974
2826 client.OnUpdatePrimGroupRotation += m_sceneGraph.UpdatePrimGroupRotation; 2975 client.OnUpdatePrimGroupRotation += m_sceneGraph.UpdatePrimGroupRotation;
2827 client.OnUpdatePrimGroupMouseRotation += m_sceneGraph.UpdatePrimGroupRotation; 2976 client.OnUpdatePrimGroupMouseRotation += m_sceneGraph.UpdatePrimGroupRotation;
2828 client.OnUpdatePrimSingleRotation += m_sceneGraph.UpdatePrimSingleRotation; 2977 client.OnUpdatePrimSingleRotation += m_sceneGraph.UpdatePrimSingleRotation;
@@ -2879,6 +3028,7 @@ namespace OpenSim.Region.Framework.Scenes
2879 client.OnFetchInventory += m_asyncInventorySender.HandleFetchInventory; 3028 client.OnFetchInventory += m_asyncInventorySender.HandleFetchInventory;
2880 client.OnUpdateInventoryItem += UpdateInventoryItemAsset; 3029 client.OnUpdateInventoryItem += UpdateInventoryItemAsset;
2881 client.OnCopyInventoryItem += CopyInventoryItem; 3030 client.OnCopyInventoryItem += CopyInventoryItem;
3031 client.OnMoveItemsAndLeaveCopy += MoveInventoryItemsLeaveCopy;
2882 client.OnMoveInventoryItem += MoveInventoryItem; 3032 client.OnMoveInventoryItem += MoveInventoryItem;
2883 client.OnRemoveInventoryItem += RemoveInventoryItem; 3033 client.OnRemoveInventoryItem += RemoveInventoryItem;
2884 client.OnRemoveInventoryFolder += RemoveInventoryFolder; 3034 client.OnRemoveInventoryFolder += RemoveInventoryFolder;
@@ -2950,6 +3100,8 @@ namespace OpenSim.Region.Framework.Scenes
2950 client.OnUpdatePrimGroupPosition -= m_sceneGraph.UpdatePrimGroupPosition; 3100 client.OnUpdatePrimGroupPosition -= m_sceneGraph.UpdatePrimGroupPosition;
2951 client.OnUpdatePrimSinglePosition -= m_sceneGraph.UpdatePrimSinglePosition; 3101 client.OnUpdatePrimSinglePosition -= m_sceneGraph.UpdatePrimSinglePosition;
2952 3102
3103 client.onClientChangeObject -= m_sceneGraph.ClientChangeObject;
3104
2953 client.OnUpdatePrimGroupRotation -= m_sceneGraph.UpdatePrimGroupRotation; 3105 client.OnUpdatePrimGroupRotation -= m_sceneGraph.UpdatePrimGroupRotation;
2954 client.OnUpdatePrimGroupMouseRotation -= m_sceneGraph.UpdatePrimGroupRotation; 3106 client.OnUpdatePrimGroupMouseRotation -= m_sceneGraph.UpdatePrimGroupRotation;
2955 client.OnUpdatePrimSingleRotation -= m_sceneGraph.UpdatePrimSingleRotation; 3107 client.OnUpdatePrimSingleRotation -= m_sceneGraph.UpdatePrimSingleRotation;
@@ -3052,15 +3204,16 @@ namespace OpenSim.Region.Framework.Scenes
3052 /// </summary> 3204 /// </summary>
3053 /// <param name="agentId">The avatar's Unique ID</param> 3205 /// <param name="agentId">The avatar's Unique ID</param>
3054 /// <param name="client">The IClientAPI for the client</param> 3206 /// <param name="client">The IClientAPI for the client</param>
3055 public virtual void TeleportClientHome(UUID agentId, IClientAPI client) 3207 public virtual bool TeleportClientHome(UUID agentId, IClientAPI client)
3056 { 3208 {
3057 if (m_teleportModule != null) 3209 if (m_teleportModule != null)
3058 m_teleportModule.TeleportHome(agentId, client); 3210 return m_teleportModule.TeleportHome(agentId, client);
3059 else 3211 else
3060 { 3212 {
3061 m_log.DebugFormat("[SCENE]: Unable to teleport user home: no AgentTransferModule is active"); 3213 m_log.DebugFormat("[SCENE]: Unable to teleport user home: no AgentTransferModule is active");
3062 client.SendTeleportFailed("Unable to perform teleports on this simulator."); 3214 client.SendTeleportFailed("Unable to perform teleports on this simulator.");
3063 } 3215 }
3216 return false;
3064 } 3217 }
3065 3218
3066 /// <summary> 3219 /// <summary>
@@ -3170,6 +3323,16 @@ namespace OpenSim.Region.Framework.Scenes
3170 /// <param name="flags"></param> 3323 /// <param name="flags"></param>
3171 public virtual void SetHomeRezPoint(IClientAPI remoteClient, ulong regionHandle, Vector3 position, Vector3 lookAt, uint flags) 3324 public virtual void SetHomeRezPoint(IClientAPI remoteClient, ulong regionHandle, Vector3 position, Vector3 lookAt, uint flags)
3172 { 3325 {
3326 //Add half the avatar's height so that the user doesn't fall through prims
3327 ScenePresence presence;
3328 if (TryGetScenePresence(remoteClient.AgentId, out presence))
3329 {
3330 if (presence.Appearance != null)
3331 {
3332 position.Z = position.Z + (presence.Appearance.AvatarHeight / 2);
3333 }
3334 }
3335
3173 if (GridUserService != null && GridUserService.SetHome(remoteClient.AgentId.ToString(), RegionInfo.RegionID, position, lookAt)) 3336 if (GridUserService != null && GridUserService.SetHome(remoteClient.AgentId.ToString(), RegionInfo.RegionID, position, lookAt))
3174 // FUBAR ALERT: this needs to be "Home position set." so the viewer saves a home-screenshot. 3337 // FUBAR ALERT: this needs to be "Home position set." so the viewer saves a home-screenshot.
3175 m_dialogModule.SendAlertToUser(remoteClient, "Home position set."); 3338 m_dialogModule.SendAlertToUser(remoteClient, "Home position set.");
@@ -3238,8 +3401,9 @@ namespace OpenSim.Region.Framework.Scenes
3238 regions.Remove(RegionInfo.RegionHandle); 3401 regions.Remove(RegionInfo.RegionHandle);
3239 m_sceneGridService.SendCloseChildAgentConnections(agentID, regions); 3402 m_sceneGridService.SendCloseChildAgentConnections(agentID, regions);
3240 } 3403 }
3241 3404 m_log.Debug("[Scene] Beginning ClientClosed");
3242 m_eventManager.TriggerClientClosed(agentID, this); 3405 m_eventManager.TriggerClientClosed(agentID, this);
3406 m_log.Debug("[Scene] Finished ClientClosed");
3243 } 3407 }
3244 catch (NullReferenceException) 3408 catch (NullReferenceException)
3245 { 3409 {
@@ -3301,9 +3465,10 @@ namespace OpenSim.Region.Framework.Scenes
3301 { 3465 {
3302 m_log.ErrorFormat("[SCENE] Scene.cs:RemoveClient exception {0}{1}", e.Message, e.StackTrace); 3466 m_log.ErrorFormat("[SCENE] Scene.cs:RemoveClient exception {0}{1}", e.Message, e.StackTrace);
3303 } 3467 }
3304 3468 m_log.Debug("[Scene] Done. Firing RemoveCircuit");
3305 m_authenticateHandler.RemoveCircuit(avatar.ControllingClient.CircuitCode); 3469 m_authenticateHandler.RemoveCircuit(avatar.ControllingClient.CircuitCode);
3306// CleanDroppedAttachments(); 3470// CleanDroppedAttachments();
3471 m_log.Debug("[Scene] The avatar has left the building");
3307 //m_log.InfoFormat("[SCENE] Memory pre GC {0}", System.GC.GetTotalMemory(false)); 3472 //m_log.InfoFormat("[SCENE] Memory pre GC {0}", System.GC.GetTotalMemory(false));
3308 //m_log.InfoFormat("[SCENE] Memory post GC {0}", System.GC.GetTotalMemory(true)); 3473 //m_log.InfoFormat("[SCENE] Memory post GC {0}", System.GC.GetTotalMemory(true));
3309 } 3474 }
@@ -3425,13 +3590,16 @@ namespace OpenSim.Region.Framework.Scenes
3425 sp = null; 3590 sp = null;
3426 } 3591 }
3427 3592
3428 ILandObject land = LandChannel.GetLandObject(agent.startpos.X, agent.startpos.Y);
3429 3593
3430 //On login test land permisions 3594 //On login test land permisions
3431 if (vialogin) 3595 if (vialogin)
3432 { 3596 {
3433 if (land != null && !TestLandRestrictions(agent, land, out reason)) 3597 IUserAccountCacheModule cache = RequestModuleInterface<IUserAccountCacheModule>();
3598 if (cache != null)
3599 cache.Remove(agent.firstname + " " + agent.lastname);
3600 if (!TestLandRestrictions(agent.AgentID, out reason, ref agent.startpos.X, ref agent.startpos.Y))
3434 { 3601 {
3602 m_log.DebugFormat("[CONNECTION BEGIN]: Denying access to {0} due to no land access", agent.AgentID.ToString());
3435 return false; 3603 return false;
3436 } 3604 }
3437 } 3605 }
@@ -3455,8 +3623,13 @@ namespace OpenSim.Region.Framework.Scenes
3455 3623
3456 try 3624 try
3457 { 3625 {
3458 if (!AuthorizeUser(agent, out reason)) 3626 // Always check estate if this is a login. Always
3459 return false; 3627 // check if banned regions are to be blacked out.
3628 if (vialogin || (!m_seeIntoBannedRegion))
3629 {
3630 if (!AuthorizeUser(agent, out reason))
3631 return false;
3632 }
3460 } 3633 }
3461 catch (Exception e) 3634 catch (Exception e)
3462 { 3635 {
@@ -3582,6 +3755,8 @@ namespace OpenSim.Region.Framework.Scenes
3582 } 3755 }
3583 3756
3584 // Honor parcel landing type and position. 3757 // Honor parcel landing type and position.
3758 /*
3759 ILandObject land = LandChannel.GetLandObject(agent.startpos.X, agent.startpos.Y);
3585 if (land != null) 3760 if (land != null)
3586 { 3761 {
3587 if (land.LandData.LandingType == (byte)1 && land.LandData.UserLocation != Vector3.Zero) 3762 if (land.LandData.LandingType == (byte)1 && land.LandData.UserLocation != Vector3.Zero)
@@ -3589,26 +3764,34 @@ namespace OpenSim.Region.Framework.Scenes
3589 agent.startpos = land.LandData.UserLocation; 3764 agent.startpos = land.LandData.UserLocation;
3590 } 3765 }
3591 } 3766 }
3767 */// This is now handled properly in ScenePresence.MakeRootAgent
3592 } 3768 }
3593 3769
3594 return true; 3770 return true;
3595 } 3771 }
3596 3772
3597 private bool TestLandRestrictions(AgentCircuitData agent, ILandObject land, out string reason) 3773 public bool TestLandRestrictions(UUID agentID, out string reason, ref float posX, ref float posY)
3598 { 3774 {
3599 3775 reason = String.Empty;
3600 bool banned = land.IsBannedFromLand(agent.AgentID); 3776 if (Permissions.IsGod(agentID))
3601 bool restricted = land.IsRestrictedFromLand(agent.AgentID); 3777 return true;
3778
3779 ILandObject land = LandChannel.GetLandObject(posX, posY);
3780 if (land == null)
3781 return false;
3782
3783 bool banned = land.IsBannedFromLand(agentID);
3784 bool restricted = land.IsRestrictedFromLand(agentID);
3602 3785
3603 if (banned || restricted) 3786 if (banned || restricted)
3604 { 3787 {
3605 ILandObject nearestParcel = GetNearestAllowedParcel(agent.AgentID, agent.startpos.X, agent.startpos.Y); 3788 ILandObject nearestParcel = GetNearestAllowedParcel(agentID, posX, posY);
3606 if (nearestParcel != null) 3789 if (nearestParcel != null)
3607 { 3790 {
3608 //Move agent to nearest allowed 3791 //Move agent to nearest allowed
3609 Vector3 newPosition = GetParcelCenterAtGround(nearestParcel); 3792 Vector3 newPosition = GetParcelCenterAtGround(nearestParcel);
3610 agent.startpos.X = newPosition.X; 3793 posX = newPosition.X;
3611 agent.startpos.Y = newPosition.Y; 3794 posY = newPosition.Y;
3612 } 3795 }
3613 else 3796 else
3614 { 3797 {
@@ -3670,7 +3853,7 @@ namespace OpenSim.Region.Framework.Scenes
3670 3853
3671 if (!m_strictAccessControl) return true; 3854 if (!m_strictAccessControl) return true;
3672 if (Permissions.IsGod(agent.AgentID)) return true; 3855 if (Permissions.IsGod(agent.AgentID)) return true;
3673 3856
3674 if (AuthorizationService != null) 3857 if (AuthorizationService != null)
3675 { 3858 {
3676 if (!AuthorizationService.IsAuthorizedForRegion( 3859 if (!AuthorizationService.IsAuthorizedForRegion(
@@ -3685,7 +3868,7 @@ namespace OpenSim.Region.Framework.Scenes
3685 3868
3686 if (m_regInfo.EstateSettings != null) 3869 if (m_regInfo.EstateSettings != null)
3687 { 3870 {
3688 if (m_regInfo.EstateSettings.IsBanned(agent.AgentID)) 3871 if (m_regInfo.EstateSettings.IsBanned(agent.AgentID,0))
3689 { 3872 {
3690 m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user is on the banlist", 3873 m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user is on the banlist",
3691 agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName); 3874 agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName);
@@ -3877,6 +4060,13 @@ namespace OpenSim.Region.Framework.Scenes
3877 4060
3878 // We have to wait until the viewer contacts this region after receiving EAC. 4061 // We have to wait until the viewer contacts this region after receiving EAC.
3879 // That calls AddNewClient, which finally creates the ScenePresence 4062 // That calls AddNewClient, which finally creates the ScenePresence
4063 int flags = GetUserFlags(cAgentData.AgentID);
4064 if (m_regInfo.EstateSettings.IsBanned(cAgentData.AgentID, flags))
4065 {
4066 m_log.DebugFormat("[SCENE]: Denying root agent entry to {0}: banned", cAgentData.AgentID);
4067 return false;
4068 }
4069
3880 ILandObject nearestParcel = GetNearestAllowedParcel(cAgentData.AgentID, Constants.RegionSize / 2, Constants.RegionSize / 2); 4070 ILandObject nearestParcel = GetNearestAllowedParcel(cAgentData.AgentID, Constants.RegionSize / 2, Constants.RegionSize / 2);
3881 if (nearestParcel == null) 4071 if (nearestParcel == null)
3882 { 4072 {
@@ -3961,12 +4151,22 @@ namespace OpenSim.Region.Framework.Scenes
3961 return false; 4151 return false;
3962 } 4152 }
3963 4153
4154 public bool IncomingCloseAgent(UUID agentID)
4155 {
4156 return IncomingCloseAgent(agentID, false);
4157 }
4158
4159 public bool IncomingCloseChildAgent(UUID agentID)
4160 {
4161 return IncomingCloseAgent(agentID, true);
4162 }
4163
3964 /// <summary> 4164 /// <summary>
3965 /// Tell a single agent to disconnect from the region. 4165 /// Tell a single agent to disconnect from the region.
3966 /// </summary> 4166 /// </summary>
3967 /// <param name="regionHandle"></param>
3968 /// <param name="agentID"></param> 4167 /// <param name="agentID"></param>
3969 public bool IncomingCloseAgent(UUID agentID) 4168 /// <param name="childOnly"></param>
4169 public bool IncomingCloseAgent(UUID agentID, bool childOnly)
3970 { 4170 {
3971 //m_log.DebugFormat("[SCENE]: Processing incoming close agent for {0}", agentID); 4171 //m_log.DebugFormat("[SCENE]: Processing incoming close agent for {0}", agentID);
3972 4172
@@ -3978,7 +4178,7 @@ namespace OpenSim.Region.Framework.Scenes
3978 { 4178 {
3979 m_sceneGraph.removeUserCount(false); 4179 m_sceneGraph.removeUserCount(false);
3980 } 4180 }
3981 else 4181 else if (!childOnly)
3982 { 4182 {
3983 m_sceneGraph.removeUserCount(true); 4183 m_sceneGraph.removeUserCount(true);
3984 } 4184 }
@@ -3994,9 +4194,12 @@ namespace OpenSim.Region.Framework.Scenes
3994 } 4194 }
3995 else 4195 else
3996 presence.ControllingClient.SendShutdownConnectionNotice(); 4196 presence.ControllingClient.SendShutdownConnectionNotice();
4197 presence.ControllingClient.Close(false);
4198 }
4199 else if (!childOnly)
4200 {
4201 presence.ControllingClient.Close(true);
3997 } 4202 }
3998
3999 presence.ControllingClient.Close();
4000 return true; 4203 return true;
4001 } 4204 }
4002 4205
@@ -4578,35 +4781,81 @@ namespace OpenSim.Region.Framework.Scenes
4578 SimulationDataService.RemoveObject(uuid, m_regInfo.RegionID); 4781 SimulationDataService.RemoveObject(uuid, m_regInfo.RegionID);
4579 } 4782 }
4580 4783
4581 public int GetHealth() 4784 public int GetHealth(out int flags, out string message)
4582 { 4785 {
4583 // Returns: 4786 // Returns:
4584 // 1 = sim is up and accepting http requests. The heartbeat has 4787 // 1 = sim is up and accepting http requests. The heartbeat has
4585 // stopped and the sim is probably locked up, but a remote 4788 // stopped and the sim is probably locked up, but a remote
4586 // admin restart may succeed 4789 // admin restart may succeed
4587 // 4790 //
4588 // 2 = Sim is up and the heartbeat is running. The sim is likely 4791 // 2 = Sim is up and the heartbeat is running. The sim is likely
4589 // usable for people within and logins _may_ work 4792 // usable for people within
4793 //
4794 // 3 = Sim is up and one packet thread is running. Sim is
4795 // unstable and will not accept new logins
4590 // 4796 //
4591 // 3 = We have seen a new user enter within the past 4 minutes 4797 // 4 = Sim is up and both packet threads are running. Sim is
4798 // likely usable
4799 //
4800 // 5 = We have seen a new user enter within the past 4 minutes
4592 // which can be seen as positive confirmation of sim health 4801 // which can be seen as positive confirmation of sim health
4593 // 4802 //
4803
4804 flags = 0;
4805 message = String.Empty;
4806
4807 CheckHeartbeat();
4808
4809 if (m_firstHeartbeat || (m_lastIncoming == 0 && m_lastOutgoing == 0))
4810 {
4811 // We're still starting
4812 // 0 means "in startup", it can't happen another way, since
4813 // to get here, we must be able to accept http connections
4814 return 0;
4815 }
4816
4594 int health=1; // Start at 1, means we're up 4817 int health=1; // Start at 1, means we're up
4595 4818
4596 if ((Util.EnvironmentTickCountSubtract(m_lastFrameTick)) < 1000) 4819 if ((Util.EnvironmentTickCountSubtract(m_lastFrameTick)) < 1000)
4597 health += 1; 4820 {
4821 health+=1;
4822 flags |= 1;
4823 }
4824
4825 if (Util.EnvironmentTickCountSubtract(m_lastIncoming) < 1000)
4826 {
4827 health+=1;
4828 flags |= 2;
4829 }
4830
4831 if (Util.EnvironmentTickCountSubtract(m_lastOutgoing) < 1000)
4832 {
4833 health+=1;
4834 flags |= 4;
4835 }
4598 else 4836 else
4837 {
4838int pid = System.Diagnostics.Process.GetCurrentProcess().Id;
4839System.Diagnostics.Process proc = new System.Diagnostics.Process();
4840proc.EnableRaisingEvents=false;
4841proc.StartInfo.FileName = "/bin/kill";
4842proc.StartInfo.Arguments = "-QUIT " + pid.ToString();
4843proc.Start();
4844proc.WaitForExit();
4845Thread.Sleep(1000);
4846Environment.Exit(1);
4847 }
4848
4849 if (flags != 7)
4599 return health; 4850 return health;
4600 4851
4601 // A login in the last 4 mins? We can't be doing too badly 4852 // A login in the last 4 mins? We can't be doing too badly
4602 // 4853 //
4603 if ((Util.EnvironmentTickCountSubtract(m_LastLogin)) < 240000) 4854 if (Util.EnvironmentTickCountSubtract(m_LastLogin) < 240000)
4604 health++; 4855 health++;
4605 else 4856 else
4606 return health; 4857 return health;
4607 4858
4608// CheckHeartbeat();
4609
4610 return health; 4859 return health;
4611 } 4860 }
4612 4861
@@ -4694,7 +4943,7 @@ namespace OpenSim.Region.Framework.Scenes
4694 bool wasUsingPhysics = ((jointProxyObject.Flags & PrimFlags.Physics) != 0); 4943 bool wasUsingPhysics = ((jointProxyObject.Flags & PrimFlags.Physics) != 0);
4695 if (wasUsingPhysics) 4944 if (wasUsingPhysics)
4696 { 4945 {
4697 jointProxyObject.UpdatePrimFlags(false, false, true, false); // FIXME: possible deadlock here; check to make sure all the scene alterations set into motion here won't deadlock 4946 jointProxyObject.UpdatePrimFlags(false, false, true, false,false); // FIXME: possible deadlock here; check to make sure all the scene alterations set into motion here won't deadlock
4698 } 4947 }
4699 } 4948 }
4700 4949
@@ -4793,14 +5042,14 @@ namespace OpenSim.Region.Framework.Scenes
4793 return (((vsn.X * xdiff) + (vsn.Y * ydiff)) / (-1 * vsn.Z)) + p0.Z; 5042 return (((vsn.X * xdiff) + (vsn.Y * ydiff)) / (-1 * vsn.Z)) + p0.Z;
4794 } 5043 }
4795 5044
4796// private void CheckHeartbeat() 5045 private void CheckHeartbeat()
4797// { 5046 {
4798// if (m_firstHeartbeat) 5047 if (m_firstHeartbeat)
4799// return; 5048 return;
4800// 5049
4801// if (Util.EnvironmentTickCountSubtract(m_lastFrameTick) > 2000) 5050 if ((Util.EnvironmentTickCountSubtract(m_lastFrameTick)) > 5000)
4802// StartTimer(); 5051 Start();
4803// } 5052 }
4804 5053
4805 public override ISceneObject DeserializeObject(string representation) 5054 public override ISceneObject DeserializeObject(string representation)
4806 { 5055 {
@@ -4812,9 +5061,14 @@ namespace OpenSim.Region.Framework.Scenes
4812 get { return m_allowScriptCrossings; } 5061 get { return m_allowScriptCrossings; }
4813 } 5062 }
4814 5063
4815 public Vector3? GetNearestAllowedPosition(ScenePresence avatar) 5064 public Vector3 GetNearestAllowedPosition(ScenePresence avatar)
5065 {
5066 return GetNearestAllowedPosition(avatar, null);
5067 }
5068
5069 public Vector3 GetNearestAllowedPosition(ScenePresence avatar, ILandObject excludeParcel)
4816 { 5070 {
4817 ILandObject nearestParcel = GetNearestAllowedParcel(avatar.UUID, avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y); 5071 ILandObject nearestParcel = GetNearestAllowedParcel(avatar.UUID, avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y, excludeParcel);
4818 5072
4819 if (nearestParcel != null) 5073 if (nearestParcel != null)
4820 { 5074 {
@@ -4823,10 +5077,7 @@ namespace OpenSim.Region.Framework.Scenes
4823 Vector3? nearestPoint = GetNearestPointInParcelAlongDirectionFromPoint(avatar.AbsolutePosition, dir, nearestParcel); 5077 Vector3? nearestPoint = GetNearestPointInParcelAlongDirectionFromPoint(avatar.AbsolutePosition, dir, nearestParcel);
4824 if (nearestPoint != null) 5078 if (nearestPoint != null)
4825 { 5079 {
4826// m_log.DebugFormat( 5080 Debug.WriteLine("Found a sane previous position based on velocity, sending them to: " + nearestPoint.ToString());
4827// "[SCENE]: Found a sane previous position based on velocity for {0}, sending them to {1} in {2}",
4828// avatar.Name, nearestPoint, nearestParcel.LandData.Name);
4829
4830 return nearestPoint.Value; 5081 return nearestPoint.Value;
4831 } 5082 }
4832 5083
@@ -4836,17 +5087,20 @@ namespace OpenSim.Region.Framework.Scenes
4836 nearestPoint = GetNearestPointInParcelAlongDirectionFromPoint(avatar.AbsolutePosition, dir, nearestParcel); 5087 nearestPoint = GetNearestPointInParcelAlongDirectionFromPoint(avatar.AbsolutePosition, dir, nearestParcel);
4837 if (nearestPoint != null) 5088 if (nearestPoint != null)
4838 { 5089 {
4839// m_log.DebugFormat( 5090 Debug.WriteLine("They had a zero velocity, sending them to: " + nearestPoint.ToString());
4840// "[SCENE]: {0} had a zero velocity, sending them to {1}", avatar.Name, nearestPoint);
4841
4842 return nearestPoint.Value; 5091 return nearestPoint.Value;
4843 } 5092 }
4844 5093
4845 //Ultimate backup if we have no idea where they are 5094 ILandObject dest = LandChannel.GetLandObject(avatar.lastKnownAllowedPosition.X, avatar.lastKnownAllowedPosition.Y);
4846// m_log.DebugFormat( 5095 if (dest != excludeParcel)
4847// "[SCENE]: No idea where {0} is, sending them to {1}", avatar.Name, avatar.lastKnownAllowedPosition); 5096 {
5097 // Ultimate backup if we have no idea where they are and
5098 // the last allowed position was in another parcel
5099 Debug.WriteLine("Have no idea where they are, sending them to: " + avatar.lastKnownAllowedPosition.ToString());
5100 return avatar.lastKnownAllowedPosition;
5101 }
4848 5102
4849 return avatar.lastKnownAllowedPosition; 5103 // else fall through to region edge
4850 } 5104 }
4851 5105
4852 //Go to the edge, this happens in teleporting to a region with no available parcels 5106 //Go to the edge, this happens in teleporting to a region with no available parcels
@@ -4880,13 +5134,18 @@ namespace OpenSim.Region.Framework.Scenes
4880 5134
4881 public ILandObject GetNearestAllowedParcel(UUID avatarId, float x, float y) 5135 public ILandObject GetNearestAllowedParcel(UUID avatarId, float x, float y)
4882 { 5136 {
5137 return GetNearestAllowedParcel(avatarId, x, y, null);
5138 }
5139
5140 public ILandObject GetNearestAllowedParcel(UUID avatarId, float x, float y, ILandObject excludeParcel)
5141 {
4883 List<ILandObject> all = AllParcels(); 5142 List<ILandObject> all = AllParcels();
4884 float minParcelDistance = float.MaxValue; 5143 float minParcelDistance = float.MaxValue;
4885 ILandObject nearestParcel = null; 5144 ILandObject nearestParcel = null;
4886 5145
4887 foreach (var parcel in all) 5146 foreach (var parcel in all)
4888 { 5147 {
4889 if (!parcel.IsEitherBannedOrRestricted(avatarId)) 5148 if (!parcel.IsEitherBannedOrRestricted(avatarId) && parcel != excludeParcel)
4890 { 5149 {
4891 float parcelDistance = GetParcelDistancefromPoint(parcel, x, y); 5150 float parcelDistance = GetParcelDistancefromPoint(parcel, x, y);
4892 if (parcelDistance < minParcelDistance) 5151 if (parcelDistance < minParcelDistance)
@@ -5128,7 +5387,55 @@ namespace OpenSim.Region.Framework.Scenes
5128 mapModule.GenerateMaptile(); 5387 mapModule.GenerateMaptile();
5129 } 5388 }
5130 5389
5131 private void RegenerateMaptileAndReregister(object sender, ElapsedEventArgs e) 5390// public void CleanDroppedAttachments()
5391// {
5392// List<SceneObjectGroup> objectsToDelete =
5393// new List<SceneObjectGroup>();
5394//
5395// lock (m_cleaningAttachments)
5396// {
5397// ForEachSOG(delegate (SceneObjectGroup grp)
5398// {
5399// if (grp.RootPart.Shape.PCode == 0 && grp.RootPart.Shape.State != 0 && (!objectsToDelete.Contains(grp)))
5400// {
5401// UUID agentID = grp.OwnerID;
5402// if (agentID == UUID.Zero)
5403// {
5404// objectsToDelete.Add(grp);
5405// return;
5406// }
5407//
5408// ScenePresence sp = GetScenePresence(agentID);
5409// if (sp == null)
5410// {
5411// objectsToDelete.Add(grp);
5412// return;
5413// }
5414// }
5415// });
5416// }
5417//
5418// foreach (SceneObjectGroup grp in objectsToDelete)
5419// {
5420// m_log.InfoFormat("[SCENE]: Deleting dropped attachment {0} of user {1}", grp.UUID, grp.OwnerID);
5421// DeleteSceneObject(grp, true);
5422// }
5423// }
5424
5425 public void ThreadAlive(int threadCode)
5426 {
5427 switch(threadCode)
5428 {
5429 case 1: // Incoming
5430 m_lastIncoming = Util.EnvironmentTickCount();
5431 break;
5432 case 2: // Incoming
5433 m_lastOutgoing = Util.EnvironmentTickCount();
5434 break;
5435 }
5436 }
5437
5438 public void RegenerateMaptileAndReregister(object sender, ElapsedEventArgs e)
5132 { 5439 {
5133 RegenerateMaptile(); 5440 RegenerateMaptile();
5134 5441
@@ -5147,6 +5454,14 @@ namespace OpenSim.Region.Framework.Scenes
5147 // child agent creation, thereby emulating the SL behavior. 5454 // child agent creation, thereby emulating the SL behavior.
5148 public bool QueryAccess(UUID agentID, Vector3 position, out string reason) 5455 public bool QueryAccess(UUID agentID, Vector3 position, out string reason)
5149 { 5456 {
5457 reason = "You are banned from the region";
5458
5459 if (Permissions.IsGod(agentID))
5460 {
5461 reason = String.Empty;
5462 return true;
5463 }
5464
5150 int num = m_sceneGraph.GetNumberOfScenePresences(); 5465 int num = m_sceneGraph.GetNumberOfScenePresences();
5151 5466
5152 if (num >= RegionInfo.RegionSettings.AgentLimit) 5467 if (num >= RegionInfo.RegionSettings.AgentLimit)
@@ -5158,6 +5473,41 @@ namespace OpenSim.Region.Framework.Scenes
5158 } 5473 }
5159 } 5474 }
5160 5475
5476 ScenePresence presence = GetScenePresence(agentID);
5477 IClientAPI client = null;
5478 AgentCircuitData aCircuit = null;
5479
5480 if (presence != null)
5481 {
5482 client = presence.ControllingClient;
5483 if (client != null)
5484 aCircuit = client.RequestClientInfo();
5485 }
5486
5487 // We may be called before there is a presence or a client.
5488 // Fake AgentCircuitData to keep IAuthorizationModule smiling
5489 if (client == null)
5490 {
5491 aCircuit = new AgentCircuitData();
5492 aCircuit.AgentID = agentID;
5493 aCircuit.firstname = String.Empty;
5494 aCircuit.lastname = String.Empty;
5495 }
5496
5497 try
5498 {
5499 if (!AuthorizeUser(aCircuit, out reason))
5500 {
5501 // m_log.DebugFormat("[SCENE]: Denying access for {0}", agentID);
5502 return false;
5503 }
5504 }
5505 catch (Exception e)
5506 {
5507 m_log.DebugFormat("[SCENE]: Exception authorizing agent: {0} "+ e.StackTrace, e.Message);
5508 return false;
5509 }
5510
5161 if (position == Vector3.Zero) // Teleport 5511 if (position == Vector3.Zero) // Teleport
5162 { 5512 {
5163 if (!RegionInfo.EstateSettings.AllowDirectTeleport) 5513 if (!RegionInfo.EstateSettings.AllowDirectTeleport)
@@ -5186,13 +5536,46 @@ namespace OpenSim.Region.Framework.Scenes
5186 } 5536 }
5187 } 5537 }
5188 } 5538 }
5539
5540 float posX = 128.0f;
5541 float posY = 128.0f;
5542
5543 if (!TestLandRestrictions(agentID, out reason, ref posX, ref posY))
5544 {
5545 // m_log.DebugFormat("[SCENE]: Denying {0} because they are banned on all parcels", agentID);
5546 return false;
5547 }
5548 }
5549 else // Walking
5550 {
5551 ILandObject land = LandChannel.GetLandObject(position.X, position.Y);
5552 if (land == null)
5553 return false;
5554
5555 bool banned = land.IsBannedFromLand(agentID);
5556 bool restricted = land.IsRestrictedFromLand(agentID);
5557
5558 if (banned || restricted)
5559 return false;
5189 } 5560 }
5190 5561
5191 reason = String.Empty; 5562 reason = String.Empty;
5192 return true; 5563 return true;
5193 } 5564 }
5194 5565
5195 /// <summary> 5566 public void StartTimerWatchdog()
5567 {
5568 m_timerWatchdog.Interval = 1000;
5569 m_timerWatchdog.Elapsed += TimerWatchdog;
5570 m_timerWatchdog.AutoReset = true;
5571 m_timerWatchdog.Start();
5572 }
5573
5574 public void TimerWatchdog(object sender, ElapsedEventArgs e)
5575 {
5576 CheckHeartbeat();
5577 }
5578
5196 /// This method deals with movement when an avatar is automatically moving (but this is distinct from the 5579 /// This method deals with movement when an avatar is automatically moving (but this is distinct from the
5197 /// autopilot that moves an avatar to a sit target!. 5580 /// autopilot that moves an avatar to a sit target!.
5198 /// </summary> 5581 /// </summary>
diff --git a/OpenSim/Region/Framework/Scenes/SceneBase.cs b/OpenSim/Region/Framework/Scenes/SceneBase.cs
index 9c6b884..9b8a3ae 100644
--- a/OpenSim/Region/Framework/Scenes/SceneBase.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneBase.cs
@@ -136,6 +136,8 @@ namespace OpenSim.Region.Framework.Scenes
136 get { return m_permissions; } 136 get { return m_permissions; }
137 } 137 }
138 138
139 protected string m_datastore;
140
139 /* Used by the loadbalancer plugin on GForge */ 141 /* Used by the loadbalancer plugin on GForge */
140 protected RegionStatus m_regStatus; 142 protected RegionStatus m_regStatus;
141 public RegionStatus RegionStatus 143 public RegionStatus RegionStatus
diff --git a/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs b/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs
index b8616e8..77e808e 100644
--- a/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs
@@ -88,7 +88,7 @@ namespace OpenSim.Region.Framework.Scenes
88 88
89 if (neighbour != null) 89 if (neighbour != null)
90 { 90 {
91 m_log.DebugFormat("[INTERGRID]: Successfully informed neighbour {0}-{1} that I'm here", x / Constants.RegionSize, y / Constants.RegionSize); 91 // m_log.DebugFormat("[INTERGRID]: Successfully informed neighbour {0}-{1} that I'm here", x / Constants.RegionSize, y / Constants.RegionSize);
92 m_scene.EventManager.TriggerOnRegionUp(neighbour); 92 m_scene.EventManager.TriggerOnRegionUp(neighbour);
93 } 93 }
94 else 94 else
@@ -102,7 +102,7 @@ namespace OpenSim.Region.Framework.Scenes
102 //m_log.Info("[INTER]: " + debugRegionName + ": SceneCommunicationService: Sending InterRegion Notification that region is up " + region.RegionName); 102 //m_log.Info("[INTER]: " + debugRegionName + ": SceneCommunicationService: Sending InterRegion Notification that region is up " + region.RegionName);
103 103
104 List<GridRegion> neighbours = m_scene.GridService.GetNeighbours(m_scene.RegionInfo.ScopeID, m_scene.RegionInfo.RegionID); 104 List<GridRegion> neighbours = m_scene.GridService.GetNeighbours(m_scene.RegionInfo.ScopeID, m_scene.RegionInfo.RegionID);
105 m_log.DebugFormat("[INTERGRID]: Informing {0} neighbours that this region is up", neighbours.Count); 105 //m_log.DebugFormat("[INTERGRID]: Informing {0} neighbours that this region is up", neighbours.Count);
106 foreach (GridRegion n in neighbours) 106 foreach (GridRegion n in neighbours)
107 { 107 {
108 InformNeighbourThatRegionUpDelegate d = InformNeighboursThatRegionIsUpAsync; 108 InformNeighbourThatRegionUpDelegate d = InformNeighboursThatRegionIsUpAsync;
@@ -182,10 +182,13 @@ namespace OpenSim.Region.Framework.Scenes
182 } 182 }
183 } 183 }
184 184
185 public delegate void SendCloseChildAgentDelegate(UUID agentID, ulong regionHandle);
186
185 /// <summary> 187 /// <summary>
186 /// Closes a child agent on a given region 188 /// This Closes child agents on neighboring regions
189 /// Calls an asynchronous method to do so.. so it doesn't lag the sim.
187 /// </summary> 190 /// </summary>
188 protected void SendCloseChildAgent(UUID agentID, ulong regionHandle) 191 protected void SendCloseChildAgentAsync(UUID agentID, ulong regionHandle)
189 { 192 {
190 // let's do our best, but there's not much we can do if the neighbour doesn't accept. 193 // let's do our best, but there's not much we can do if the neighbour doesn't accept.
191 194
@@ -194,31 +197,29 @@ namespace OpenSim.Region.Framework.Scenes
194 Utils.LongToUInts(regionHandle, out x, out y); 197 Utils.LongToUInts(regionHandle, out x, out y);
195 198
196 GridRegion destination = m_scene.GridService.GetRegionByPosition(m_regionInfo.ScopeID, (int)x, (int)y); 199 GridRegion destination = m_scene.GridService.GetRegionByPosition(m_regionInfo.ScopeID, (int)x, (int)y);
200 m_scene.SimulationService.CloseChildAgent(destination, agentID);
201 }
197 202
198 m_log.DebugFormat( 203 private void SendCloseChildAgentCompleted(IAsyncResult iar)
199 "[INTERGRID]: Sending close agent {0} to region at {1}-{2}", 204 {
200 agentID, destination.RegionCoordX, destination.RegionCoordY); 205 SendCloseChildAgentDelegate icon = (SendCloseChildAgentDelegate)iar.AsyncState;
201 206 icon.EndInvoke(iar);
202 m_scene.SimulationService.CloseAgent(destination, agentID);
203 } 207 }
204 208
205 /// <summary>
206 /// Closes a child agents in a collection of regions. Does so asynchronously
207 /// so that the caller doesn't wait.
208 /// </summary>
209 /// <param name="agentID"></param>
210 /// <param name="regionslst"></param>
211 public void SendCloseChildAgentConnections(UUID agentID, List<ulong> regionslst) 209 public void SendCloseChildAgentConnections(UUID agentID, List<ulong> regionslst)
212 { 210 {
213 foreach (ulong handle in regionslst) 211 foreach (ulong handle in regionslst)
214 { 212 {
215 SendCloseChildAgent(agentID, handle); 213 SendCloseChildAgentDelegate d = SendCloseChildAgentAsync;
214 d.BeginInvoke(agentID, handle,
215 SendCloseChildAgentCompleted,
216 d);
216 } 217 }
217 } 218 }
218 219
219 public List<GridRegion> RequestNamedRegions(string name, int maxNumber) 220 public List<GridRegion> RequestNamedRegions(string name, int maxNumber)
220 { 221 {
221 return m_scene.GridService.GetRegionsByName(UUID.Zero, name, maxNumber); 222 return m_scene.GridService.GetRegionsByName(UUID.Zero, name, maxNumber);
222 } 223 }
223 } 224 }
224} \ No newline at end of file 225}
diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
index 4815922..00f76e0 100644
--- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
@@ -41,6 +41,12 @@ namespace OpenSim.Region.Framework.Scenes
41{ 41{
42 public delegate void PhysicsCrash(); 42 public delegate void PhysicsCrash();
43 43
44 public delegate void AttachToBackupDelegate(SceneObjectGroup sog);
45
46 public delegate void DetachFromBackupDelegate(SceneObjectGroup sog);
47
48 public delegate void ChangedBackupDelegate(SceneObjectGroup sog);
49
44 /// <summary> 50 /// <summary>
45 /// This class used to be called InnerScene and may not yet truly be a SceneGraph. The non scene graph components 51 /// This class used to be called InnerScene and may not yet truly be a SceneGraph. The non scene graph components
46 /// should be migrated out over time. 52 /// should be migrated out over time.
@@ -54,11 +60,15 @@ namespace OpenSim.Region.Framework.Scenes
54 protected internal event PhysicsCrash UnRecoverableError; 60 protected internal event PhysicsCrash UnRecoverableError;
55 private PhysicsCrash handlerPhysicsCrash = null; 61 private PhysicsCrash handlerPhysicsCrash = null;
56 62
63 public event AttachToBackupDelegate OnAttachToBackup;
64 public event DetachFromBackupDelegate OnDetachFromBackup;
65 public event ChangedBackupDelegate OnChangeBackup;
66
57 #endregion 67 #endregion
58 68
59 #region Fields 69 #region Fields
60 70
61 protected object m_presenceLock = new object(); 71 protected OpenMetaverse.ReaderWriterLockSlim m_scenePresencesLock = new OpenMetaverse.ReaderWriterLockSlim();
62 protected Dictionary<UUID, ScenePresence> m_scenePresenceMap = new Dictionary<UUID, ScenePresence>(); 72 protected Dictionary<UUID, ScenePresence> m_scenePresenceMap = new Dictionary<UUID, ScenePresence>();
63 protected List<ScenePresence> m_scenePresenceArray = new List<ScenePresence>(); 73 protected List<ScenePresence> m_scenePresenceArray = new List<ScenePresence>();
64 74
@@ -127,13 +137,18 @@ namespace OpenSim.Region.Framework.Scenes
127 137
128 protected internal void Close() 138 protected internal void Close()
129 { 139 {
130 lock (m_presenceLock) 140 m_scenePresencesLock.EnterWriteLock();
141 try
131 { 142 {
132 Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(); 143 Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>();
133 List<ScenePresence> newlist = new List<ScenePresence>(); 144 List<ScenePresence> newlist = new List<ScenePresence>();
134 m_scenePresenceMap = newmap; 145 m_scenePresenceMap = newmap;
135 m_scenePresenceArray = newlist; 146 m_scenePresenceArray = newlist;
136 } 147 }
148 finally
149 {
150 m_scenePresencesLock.ExitWriteLock();
151 }
137 152
138 lock (SceneObjectGroupsByFullID) 153 lock (SceneObjectGroupsByFullID)
139 SceneObjectGroupsByFullID.Clear(); 154 SceneObjectGroupsByFullID.Clear();
@@ -254,6 +269,33 @@ namespace OpenSim.Region.Framework.Scenes
254 protected internal bool AddRestoredSceneObject( 269 protected internal bool AddRestoredSceneObject(
255 SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates) 270 SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates)
256 { 271 {
272 if (!m_parentScene.CombineRegions)
273 {
274 // KF: Check for out-of-region, move inside and make static.
275 Vector3 npos = new Vector3(sceneObject.RootPart.GroupPosition.X,
276 sceneObject.RootPart.GroupPosition.Y,
277 sceneObject.RootPart.GroupPosition.Z);
278 if (!(((sceneObject.RootPart.Shape.PCode == (byte)PCode.Prim) && (sceneObject.RootPart.Shape.State != 0))) && (npos.X < 0.0 || npos.Y < 0.0 || npos.Z < 0.0 ||
279 npos.X > Constants.RegionSize ||
280 npos.Y > Constants.RegionSize))
281 {
282 if (npos.X < 0.0) npos.X = 1.0f;
283 if (npos.Y < 0.0) npos.Y = 1.0f;
284 if (npos.Z < 0.0) npos.Z = 0.0f;
285 if (npos.X > Constants.RegionSize) npos.X = Constants.RegionSize - 1.0f;
286 if (npos.Y > Constants.RegionSize) npos.Y = Constants.RegionSize - 1.0f;
287
288 foreach (SceneObjectPart part in sceneObject.Parts)
289 {
290 part.GroupPosition = npos;
291 }
292 sceneObject.RootPart.Velocity = Vector3.Zero;
293 sceneObject.RootPart.AngularVelocity = Vector3.Zero;
294 sceneObject.RootPart.Acceleration = Vector3.Zero;
295 sceneObject.RootPart.Velocity = Vector3.Zero;
296 }
297 }
298
257 if (attachToBackup && (!alreadyPersisted)) 299 if (attachToBackup && (!alreadyPersisted))
258 { 300 {
259 sceneObject.ForceInventoryPersistence(); 301 sceneObject.ForceInventoryPersistence();
@@ -319,7 +361,7 @@ namespace OpenSim.Region.Framework.Scenes
319 sceneObject.RootPart.ApplyImpulse((vel * sceneObject.GetMass()), false); 361 sceneObject.RootPart.ApplyImpulse((vel * sceneObject.GetMass()), false);
320 sceneObject.Velocity = vel; 362 sceneObject.Velocity = vel;
321 } 363 }
322 364
323 return true; 365 return true;
324 } 366 }
325 367
@@ -344,6 +386,11 @@ namespace OpenSim.Region.Framework.Scenes
344 /// </returns> 386 /// </returns>
345 protected bool AddSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates) 387 protected bool AddSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates)
346 { 388 {
389 if (sceneObject == null)
390 {
391 m_log.ErrorFormat("[SCENEGRAPH]: Tried to add null scene object");
392 return false;
393 }
347 if (sceneObject.UUID == UUID.Zero) 394 if (sceneObject.UUID == UUID.Zero)
348 { 395 {
349 m_log.ErrorFormat( 396 m_log.ErrorFormat(
@@ -478,6 +525,30 @@ namespace OpenSim.Region.Framework.Scenes
478 m_updateList[obj.UUID] = obj; 525 m_updateList[obj.UUID] = obj;
479 } 526 }
480 527
528 public void FireAttachToBackup(SceneObjectGroup obj)
529 {
530 if (OnAttachToBackup != null)
531 {
532 OnAttachToBackup(obj);
533 }
534 }
535
536 public void FireDetachFromBackup(SceneObjectGroup obj)
537 {
538 if (OnDetachFromBackup != null)
539 {
540 OnDetachFromBackup(obj);
541 }
542 }
543
544 public void FireChangeBackup(SceneObjectGroup obj)
545 {
546 if (OnChangeBackup != null)
547 {
548 OnChangeBackup(obj);
549 }
550 }
551
481 /// <summary> 552 /// <summary>
482 /// Process all pending updates 553 /// Process all pending updates
483 /// </summary> 554 /// </summary>
@@ -595,7 +666,8 @@ namespace OpenSim.Region.Framework.Scenes
595 666
596 Entities[presence.UUID] = presence; 667 Entities[presence.UUID] = presence;
597 668
598 lock (m_presenceLock) 669 m_scenePresencesLock.EnterWriteLock();
670 try
599 { 671 {
600 Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap); 672 Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap);
601 List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray); 673 List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray);
@@ -619,6 +691,10 @@ namespace OpenSim.Region.Framework.Scenes
619 m_scenePresenceMap = newmap; 691 m_scenePresenceMap = newmap;
620 m_scenePresenceArray = newlist; 692 m_scenePresenceArray = newlist;
621 } 693 }
694 finally
695 {
696 m_scenePresencesLock.ExitWriteLock();
697 }
622 } 698 }
623 699
624 /// <summary> 700 /// <summary>
@@ -633,7 +709,8 @@ namespace OpenSim.Region.Framework.Scenes
633 agentID); 709 agentID);
634 } 710 }
635 711
636 lock (m_presenceLock) 712 m_scenePresencesLock.EnterWriteLock();
713 try
637 { 714 {
638 Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap); 715 Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap);
639 List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray); 716 List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray);
@@ -655,6 +732,10 @@ namespace OpenSim.Region.Framework.Scenes
655 m_log.WarnFormat("[SCENE GRAPH]: Tried to remove non-existent scene presence with agent ID {0} from scene ScenePresences list", agentID); 732 m_log.WarnFormat("[SCENE GRAPH]: Tried to remove non-existent scene presence with agent ID {0} from scene ScenePresences list", agentID);
656 } 733 }
657 } 734 }
735 finally
736 {
737 m_scenePresencesLock.ExitWriteLock();
738 }
658 } 739 }
659 740
660 protected internal void SwapRootChildAgent(bool direction_RC_CR_T_F) 741 protected internal void SwapRootChildAgent(bool direction_RC_CR_T_F)
@@ -1187,6 +1268,52 @@ namespace OpenSim.Region.Framework.Scenes
1187 1268
1188 #region Client Event handlers 1269 #region Client Event handlers
1189 1270
1271 protected internal void ClientChangeObject(uint localID, object odata, IClientAPI remoteClient)
1272 {
1273 SceneObjectPart part = GetSceneObjectPart(localID);
1274 ObjectChangeData data = (ObjectChangeData)odata;
1275
1276 if (part != null)
1277 {
1278 SceneObjectGroup grp = part.ParentGroup;
1279 if (grp != null)
1280 {
1281 if (m_parentScene.Permissions.CanEditObject(grp.UUID, remoteClient.AgentId))
1282 {
1283 // These two are exceptions SL makes in the interpretation
1284 // of the change flags. Must check them here because otherwise
1285 // the group flag (see below) would be lost
1286 if (data.change == ObjectChangeType.groupS)
1287 data.change = ObjectChangeType.primS;
1288 if (data.change == ObjectChangeType.groupPS)
1289 data.change = ObjectChangeType.primPS;
1290 part.StoreUndoState(data.change); // lets test only saving what we changed
1291 grp.doChangeObject(part, (ObjectChangeData)data);
1292 }
1293 else
1294 {
1295 // Is this any kind of group operation?
1296 if ((data.change & ObjectChangeType.Group) != 0)
1297 {
1298 // Is a move and/or rotation requested?
1299 if ((data.change & (ObjectChangeType.Position | ObjectChangeType.Rotation)) != 0)
1300 {
1301 // Are we allowed to move it?
1302 if (m_parentScene.Permissions.CanMoveObject(grp.UUID, remoteClient.AgentId))
1303 {
1304 // Strip all but move and rotation from request
1305 data.change &= (ObjectChangeType.Group | ObjectChangeType.Position | ObjectChangeType.Rotation);
1306
1307 part.StoreUndoState(data.change);
1308 grp.doChangeObject(part, (ObjectChangeData)data);
1309 }
1310 }
1311 }
1312 }
1313 }
1314 }
1315 }
1316
1190 /// <summary> 1317 /// <summary>
1191 /// Update the scale of an individual prim. 1318 /// Update the scale of an individual prim.
1192 /// </summary> 1319 /// </summary>
@@ -1201,7 +1328,17 @@ namespace OpenSim.Region.Framework.Scenes
1201 { 1328 {
1202 if (m_parentScene.Permissions.CanEditObject(part.ParentGroup.UUID, remoteClient.AgentId)) 1329 if (m_parentScene.Permissions.CanEditObject(part.ParentGroup.UUID, remoteClient.AgentId))
1203 { 1330 {
1331 bool physbuild = false;
1332 if (part.ParentGroup.RootPart.PhysActor != null)
1333 {
1334 part.ParentGroup.RootPart.PhysActor.Building = true;
1335 physbuild = true;
1336 }
1337
1204 part.Resize(scale); 1338 part.Resize(scale);
1339
1340 if (physbuild)
1341 part.ParentGroup.RootPart.PhysActor.Building = false;
1205 } 1342 }
1206 } 1343 }
1207 } 1344 }
@@ -1213,7 +1350,17 @@ namespace OpenSim.Region.Framework.Scenes
1213 { 1350 {
1214 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId)) 1351 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1215 { 1352 {
1353 bool physbuild = false;
1354 if (group.RootPart.PhysActor != null)
1355 {
1356 group.RootPart.PhysActor.Building = true;
1357 physbuild = true;
1358 }
1359
1216 group.GroupResize(scale); 1360 group.GroupResize(scale);
1361
1362 if (physbuild)
1363 group.RootPart.PhysActor.Building = false;
1217 } 1364 }
1218 } 1365 }
1219 } 1366 }
@@ -1341,8 +1488,13 @@ namespace OpenSim.Region.Framework.Scenes
1341 { 1488 {
1342 if (group.IsAttachment || (group.RootPart.Shape.PCode == 9 && group.RootPart.Shape.State != 0)) 1489 if (group.IsAttachment || (group.RootPart.Shape.PCode == 9 && group.RootPart.Shape.State != 0))
1343 { 1490 {
1344 if (m_parentScene.AttachmentsModule != null) 1491 // Set the new attachment point data in the object
1345 m_parentScene.AttachmentsModule.UpdateAttachmentPosition(group, pos); 1492 byte attachmentPoint = group.GetAttachmentPoint();
1493 group.UpdateGroupPosition(pos);
1494 group.IsAttachment = false;
1495 group.AbsolutePosition = group.RootPart.AttachedPos;
1496 group.AttachmentPoint = attachmentPoint;
1497 group.HasGroupChanged = true;
1346 } 1498 }
1347 else 1499 else
1348 { 1500 {
@@ -1390,7 +1542,7 @@ namespace OpenSim.Region.Framework.Scenes
1390 /// <param name="SetPhantom"></param> 1542 /// <param name="SetPhantom"></param>
1391 /// <param name="remoteClient"></param> 1543 /// <param name="remoteClient"></param>
1392 protected internal void UpdatePrimFlags( 1544 protected internal void UpdatePrimFlags(
1393 uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, IClientAPI remoteClient) 1545 uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, ExtraPhysicsData PhysData, IClientAPI remoteClient)
1394 { 1546 {
1395 SceneObjectGroup group = GetGroupByPrim(localID); 1547 SceneObjectGroup group = GetGroupByPrim(localID);
1396 if (group != null) 1548 if (group != null)
@@ -1398,7 +1550,28 @@ namespace OpenSim.Region.Framework.Scenes
1398 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId)) 1550 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1399 { 1551 {
1400 // VolumeDetect can't be set via UI and will always be off when a change is made there 1552 // VolumeDetect can't be set via UI and will always be off when a change is made there
1401 group.UpdatePrimFlags(localID, UsePhysics, SetTemporary, SetPhantom, false); 1553 // now only change volume dtc if phantom off
1554
1555 if (PhysData.PhysShapeType == PhysShapeType.invalid) // check for extraPhysics data
1556 {
1557 bool vdtc;
1558 if (SetPhantom) // if phantom keep volumedtc
1559 vdtc = group.RootPart.VolumeDetectActive;
1560 else // else turn it off
1561 vdtc = false;
1562
1563 group.UpdatePrimFlags(localID, UsePhysics, SetTemporary, SetPhantom, vdtc);
1564 }
1565 else
1566 {
1567 SceneObjectPart part = GetSceneObjectPart(localID);
1568 if (part != null)
1569 {
1570 part.UpdateExtraPhysics(PhysData);
1571 if (part.UpdatePhysRequired)
1572 remoteClient.SendPartPhysicsProprieties(part);
1573 }
1574 }
1402 } 1575 }
1403 } 1576 }
1404 } 1577 }
@@ -1542,6 +1715,7 @@ namespace OpenSim.Region.Framework.Scenes
1542 { 1715 {
1543 part.Material = Convert.ToByte(material); 1716 part.Material = Convert.ToByte(material);
1544 group.HasGroupChanged = true; 1717 group.HasGroupChanged = true;
1718 remoteClient.SendPartPhysicsProprieties(part);
1545 } 1719 }
1546 } 1720 }
1547 } 1721 }
@@ -1606,6 +1780,12 @@ namespace OpenSim.Region.Framework.Scenes
1606 /// <param name="childPrims"></param> 1780 /// <param name="childPrims"></param>
1607 protected internal void LinkObjects(SceneObjectPart root, List<SceneObjectPart> children) 1781 protected internal void LinkObjects(SceneObjectPart root, List<SceneObjectPart> children)
1608 { 1782 {
1783 if (root.KeyframeMotion != null)
1784 {
1785 root.KeyframeMotion.Stop();
1786 root.KeyframeMotion = null;
1787 }
1788
1609 SceneObjectGroup parentGroup = root.ParentGroup; 1789 SceneObjectGroup parentGroup = root.ParentGroup;
1610 if (parentGroup == null) return; 1790 if (parentGroup == null) return;
1611 1791
@@ -1614,8 +1794,11 @@ namespace OpenSim.Region.Framework.Scenes
1614 return; 1794 return;
1615 1795
1616 Monitor.Enter(m_updateLock); 1796 Monitor.Enter(m_updateLock);
1797
1617 try 1798 try
1618 { 1799 {
1800 parentGroup.areUpdatesSuspended = true;
1801
1619 List<SceneObjectGroup> childGroups = new List<SceneObjectGroup>(); 1802 List<SceneObjectGroup> childGroups = new List<SceneObjectGroup>();
1620 1803
1621 // We do this in reverse to get the link order of the prims correct 1804 // We do this in reverse to get the link order of the prims correct
@@ -1630,9 +1813,13 @@ namespace OpenSim.Region.Framework.Scenes
1630 // Make sure no child prim is set for sale 1813 // Make sure no child prim is set for sale
1631 // So that, on delink, no prims are unwittingly 1814 // So that, on delink, no prims are unwittingly
1632 // left for sale and sold off 1815 // left for sale and sold off
1633 child.RootPart.ObjectSaleType = 0; 1816
1634 child.RootPart.SalePrice = 10; 1817 if (child != null)
1635 childGroups.Add(child); 1818 {
1819 child.RootPart.ObjectSaleType = 0;
1820 child.RootPart.SalePrice = 10;
1821 childGroups.Add(child);
1822 }
1636 } 1823 }
1637 1824
1638 foreach (SceneObjectGroup child in childGroups) 1825 foreach (SceneObjectGroup child in childGroups)
@@ -1659,6 +1846,16 @@ namespace OpenSim.Region.Framework.Scenes
1659 } 1846 }
1660 finally 1847 finally
1661 { 1848 {
1849 lock (SceneObjectGroupsByLocalPartID)
1850 {
1851 foreach (SceneObjectPart part in parentGroup.Parts)
1852 SceneObjectGroupsByLocalPartID[part.LocalId] = parentGroup;
1853 }
1854
1855 parentGroup.areUpdatesSuspended = false;
1856 parentGroup.HasGroupChanged = true;
1857 parentGroup.ProcessBackup(m_parentScene.SimulationDataService, true);
1858 parentGroup.ScheduleGroupForFullUpdate();
1662 Monitor.Exit(m_updateLock); 1859 Monitor.Exit(m_updateLock);
1663 } 1860 }
1664 } 1861 }
@@ -1681,6 +1878,11 @@ namespace OpenSim.Region.Framework.Scenes
1681 { 1878 {
1682 if (part != null) 1879 if (part != null)
1683 { 1880 {
1881 if (part.KeyframeMotion != null)
1882 {
1883 part.KeyframeMotion.Stop();
1884 part.KeyframeMotion = null;
1885 }
1684 if (part.ParentGroup.PrimCount != 1) // Skip single 1886 if (part.ParentGroup.PrimCount != 1) // Skip single
1685 { 1887 {
1686 if (part.LinkNum < 2) // Root 1888 if (part.LinkNum < 2) // Root
@@ -1695,21 +1897,24 @@ namespace OpenSim.Region.Framework.Scenes
1695 1897
1696 SceneObjectGroup group = part.ParentGroup; 1898 SceneObjectGroup group = part.ParentGroup;
1697 if (!affectedGroups.Contains(group)) 1899 if (!affectedGroups.Contains(group))
1900 {
1901 group.areUpdatesSuspended = true;
1698 affectedGroups.Add(group); 1902 affectedGroups.Add(group);
1903 }
1699 } 1904 }
1700 } 1905 }
1701 } 1906 }
1702 1907
1703 foreach (SceneObjectPart child in childParts) 1908 if (childParts.Count > 0)
1704 { 1909 {
1705 // Unlink all child parts from their groups 1910 foreach (SceneObjectPart child in childParts)
1706 // 1911 {
1707 child.ParentGroup.DelinkFromGroup(child, true); 1912 // Unlink all child parts from their groups
1708 1913 //
1709 // These are not in affected groups and will not be 1914 child.ParentGroup.DelinkFromGroup(child, true);
1710 // handled further. Do the honors here. 1915 child.ParentGroup.HasGroupChanged = true;
1711 child.ParentGroup.HasGroupChanged = true; 1916 child.ParentGroup.ScheduleGroupForFullUpdate();
1712 child.ParentGroup.ScheduleGroupForFullUpdate(); 1917 }
1713 } 1918 }
1714 1919
1715 foreach (SceneObjectPart root in rootParts) 1920 foreach (SceneObjectPart root in rootParts)
@@ -1719,56 +1924,68 @@ namespace OpenSim.Region.Framework.Scenes
1719 // However, editing linked parts and unlinking may be different 1924 // However, editing linked parts and unlinking may be different
1720 // 1925 //
1721 SceneObjectGroup group = root.ParentGroup; 1926 SceneObjectGroup group = root.ParentGroup;
1927 group.areUpdatesSuspended = true;
1722 1928
1723 List<SceneObjectPart> newSet = new List<SceneObjectPart>(group.Parts); 1929 List<SceneObjectPart> newSet = new List<SceneObjectPart>(group.Parts);
1724 int numChildren = newSet.Count; 1930 int numChildren = newSet.Count;
1725 1931
1932 if (numChildren == 1)
1933 break;
1934
1726 // If there are prims left in a link set, but the root is 1935 // If there are prims left in a link set, but the root is
1727 // slated for unlink, we need to do this 1936 // slated for unlink, we need to do this
1937 // Unlink the remaining set
1728 // 1938 //
1729 if (numChildren != 1) 1939 bool sendEventsToRemainder = true;
1730 { 1940 if (numChildren > 1)
1731 // Unlink the remaining set 1941 sendEventsToRemainder = false;
1732 //
1733 bool sendEventsToRemainder = true;
1734 if (numChildren > 1)
1735 sendEventsToRemainder = false;
1736 1942
1737 foreach (SceneObjectPart p in newSet) 1943 foreach (SceneObjectPart p in newSet)
1944 {
1945 if (p != group.RootPart)
1738 { 1946 {
1739 if (p != group.RootPart) 1947 group.DelinkFromGroup(p, sendEventsToRemainder);
1740 group.DelinkFromGroup(p, sendEventsToRemainder); 1948 if (numChildren > 2)
1949 {
1950 p.ParentGroup.areUpdatesSuspended = true;
1951 }
1952 else
1953 {
1954 p.ParentGroup.HasGroupChanged = true;
1955 p.ParentGroup.ScheduleGroupForFullUpdate();
1956 }
1741 } 1957 }
1958 }
1959
1960 // If there is more than one prim remaining, we
1961 // need to re-link
1962 //
1963 if (numChildren > 2)
1964 {
1965 // Remove old root
1966 //
1967 if (newSet.Contains(root))
1968 newSet.Remove(root);
1742 1969
1743 // If there is more than one prim remaining, we 1970 // Preserve link ordering
1744 // need to re-link
1745 // 1971 //
1746 if (numChildren > 2) 1972 newSet.Sort(delegate (SceneObjectPart a, SceneObjectPart b)
1747 { 1973 {
1748 // Remove old root 1974 return a.LinkNum.CompareTo(b.LinkNum);
1749 // 1975 });
1750 if (newSet.Contains(root))
1751 newSet.Remove(root);
1752
1753 // Preserve link ordering
1754 //
1755 newSet.Sort(delegate (SceneObjectPart a, SceneObjectPart b)
1756 {
1757 return a.LinkNum.CompareTo(b.LinkNum);
1758 });
1759 1976
1760 // Determine new root 1977 // Determine new root
1761 // 1978 //
1762 SceneObjectPart newRoot = newSet[0]; 1979 SceneObjectPart newRoot = newSet[0];
1763 newSet.RemoveAt(0); 1980 newSet.RemoveAt(0);
1764 1981
1765 foreach (SceneObjectPart newChild in newSet) 1982 foreach (SceneObjectPart newChild in newSet)
1766 newChild.ClearUpdateSchedule(); 1983 newChild.ClearUpdateSchedule();
1767 1984
1768 LinkObjects(newRoot, newSet); 1985 newRoot.ParentGroup.areUpdatesSuspended = true;
1769 if (!affectedGroups.Contains(newRoot.ParentGroup)) 1986 LinkObjects(newRoot, newSet);
1770 affectedGroups.Add(newRoot.ParentGroup); 1987 if (!affectedGroups.Contains(newRoot.ParentGroup))
1771 } 1988 affectedGroups.Add(newRoot.ParentGroup);
1772 } 1989 }
1773 } 1990 }
1774 1991
@@ -1776,8 +1993,14 @@ namespace OpenSim.Region.Framework.Scenes
1776 // 1993 //
1777 foreach (SceneObjectGroup g in affectedGroups) 1994 foreach (SceneObjectGroup g in affectedGroups)
1778 { 1995 {
1996 // Child prims that have been unlinked and deleted will
1997 // return unless the root is deleted. This will remove them
1998 // from the database. They will be rewritten immediately,
1999 // minus the rows for the unlinked child prims.
2000 m_parentScene.SimulationDataService.RemoveObject(g.UUID, m_parentScene.RegionInfo.RegionID);
1779 g.TriggerScriptChangedEvent(Changed.LINK); 2001 g.TriggerScriptChangedEvent(Changed.LINK);
1780 g.HasGroupChanged = true; // Persist 2002 g.HasGroupChanged = true; // Persist
2003 g.areUpdatesSuspended = false;
1781 g.ScheduleGroupForFullUpdate(); 2004 g.ScheduleGroupForFullUpdate();
1782 } 2005 }
1783 } 2006 }
@@ -1849,108 +2072,96 @@ namespace OpenSim.Region.Framework.Scenes
1849 /// <param name="GroupID"></param> 2072 /// <param name="GroupID"></param>
1850 /// <param name="rot"></param> 2073 /// <param name="rot"></param>
1851 /// <returns>null if duplication fails, otherwise the duplicated object</returns> 2074 /// <returns>null if duplication fails, otherwise the duplicated object</returns>
1852 public SceneObjectGroup DuplicateObject( 2075 /// <summary>
1853 uint originalPrimID, Vector3 offset, uint flags, UUID AgentID, UUID GroupID, Quaternion rot) 2076 public SceneObjectGroup DuplicateObject(uint originalPrimID, Vector3 offset, uint flags, UUID AgentID, UUID GroupID, Quaternion rot)
1854 { 2077 {
1855 Monitor.Enter(m_updateLock); 2078// m_log.DebugFormat(
2079// "[SCENE]: Duplication of object {0} at offset {1} requested by agent {2}",
2080// originalPrimID, offset, AgentID);
1856 2081
1857 try 2082 SceneObjectGroup original = GetGroupByPrim(originalPrimID);
2083 if (original != null)
1858 { 2084 {
1859 // m_log.DebugFormat( 2085 if (m_parentScene.Permissions.CanDuplicateObject(
1860 // "[SCENE]: Duplication of object {0} at offset {1} requested by agent {2}", 2086 original.PrimCount, original.UUID, AgentID, original.AbsolutePosition))
1861 // originalPrimID, offset, AgentID);
1862
1863 SceneObjectGroup original = GetGroupByPrim(originalPrimID);
1864 if (original == null)
1865 { 2087 {
1866 m_log.WarnFormat( 2088 SceneObjectGroup copy = original.Copy(true);
1867 "[SCENEGRAPH]: Attempt to duplicate nonexistant prim id {0} by {1}", originalPrimID, AgentID); 2089 copy.AbsolutePosition = copy.AbsolutePosition + offset;
1868 2090
1869 return null; 2091 if (original.OwnerID != AgentID)
1870 } 2092 {
2093 copy.SetOwnerId(AgentID);
2094 copy.SetRootPartOwner(copy.RootPart, AgentID, GroupID);
1871 2095
1872 if (!m_parentScene.Permissions.CanDuplicateObject( 2096 SceneObjectPart[] partList = copy.Parts;
1873 original.PrimCount, original.UUID, AgentID, original.AbsolutePosition))
1874 return null;
1875 2097
1876 SceneObjectGroup copy = original.Copy(true); 2098 if (m_parentScene.Permissions.PropagatePermissions())
1877 copy.AbsolutePosition = copy.AbsolutePosition + offset; 2099 {
2100 foreach (SceneObjectPart child in partList)
2101 {
2102 child.Inventory.ChangeInventoryOwner(AgentID);
2103 child.TriggerScriptChangedEvent(Changed.OWNER);
2104 child.ApplyNextOwnerPermissions();
2105 }
2106 }
2107 }
1878 2108
1879 if (original.OwnerID != AgentID) 2109 // FIXME: This section needs to be refactored so that it just calls AddSceneObject()
1880 { 2110 Entities.Add(copy);
1881 copy.SetOwnerId(AgentID);
1882 copy.SetRootPartOwner(copy.RootPart, AgentID, GroupID);
1883 2111
1884 SceneObjectPart[] partList = copy.Parts; 2112 lock (SceneObjectGroupsByFullID)
2113 SceneObjectGroupsByFullID[copy.UUID] = copy;
1885 2114
1886 if (m_parentScene.Permissions.PropagatePermissions()) 2115 SceneObjectPart[] children = copy.Parts;
2116
2117 lock (SceneObjectGroupsByFullPartID)
1887 { 2118 {
1888 foreach (SceneObjectPart child in partList) 2119 SceneObjectGroupsByFullPartID[copy.UUID] = copy;
1889 { 2120 foreach (SceneObjectPart part in children)
1890 child.Inventory.ChangeInventoryOwner(AgentID); 2121 SceneObjectGroupsByFullPartID[part.UUID] = copy;
1891 child.TriggerScriptChangedEvent(Changed.OWNER);
1892 child.ApplyNextOwnerPermissions();
1893 }
1894 } 2122 }
1895 2123
1896 copy.RootPart.ObjectSaleType = 0; 2124 lock (SceneObjectGroupsByLocalPartID)
1897 copy.RootPart.SalePrice = 10; 2125 {
1898 } 2126 SceneObjectGroupsByLocalPartID[copy.LocalId] = copy;
2127 foreach (SceneObjectPart part in children)
2128 SceneObjectGroupsByLocalPartID[part.LocalId] = copy;
2129 }
2130 // PROBABLE END OF FIXME
1899 2131
1900 // FIXME: This section needs to be refactored so that it just calls AddSceneObject() 2132 // Since we copy from a source group that is in selected
1901 Entities.Add(copy); 2133 // state, but the copy is shown deselected in the viewer,
1902 2134 // We need to clear the selection flag here, else that
1903 lock (SceneObjectGroupsByFullID) 2135 // prim never gets persisted at all. The client doesn't
1904 SceneObjectGroupsByFullID[copy.UUID] = copy; 2136 // think it's selected, so it will never send a deselect...
1905 2137 copy.IsSelected = false;
1906 SceneObjectPart[] children = copy.Parts; 2138
1907 2139 m_numPrim += copy.Parts.Length;
1908 lock (SceneObjectGroupsByFullPartID) 2140
1909 { 2141 if (rot != Quaternion.Identity)
1910 SceneObjectGroupsByFullPartID[copy.UUID] = copy; 2142 {
1911 foreach (SceneObjectPart part in children) 2143 copy.UpdateGroupRotationR(rot);
1912 SceneObjectGroupsByFullPartID[part.UUID] = copy; 2144 }
1913 }
1914
1915 lock (SceneObjectGroupsByLocalPartID)
1916 {
1917 SceneObjectGroupsByLocalPartID[copy.LocalId] = copy;
1918 foreach (SceneObjectPart part in children)
1919 SceneObjectGroupsByLocalPartID[part.LocalId] = copy;
1920 }
1921 // PROBABLE END OF FIXME
1922
1923 // Since we copy from a source group that is in selected
1924 // state, but the copy is shown deselected in the viewer,
1925 // We need to clear the selection flag here, else that
1926 // prim never gets persisted at all. The client doesn't
1927 // think it's selected, so it will never send a deselect...
1928 copy.IsSelected = false;
1929
1930 m_numPrim += copy.Parts.Length;
1931
1932 if (rot != Quaternion.Identity)
1933 {
1934 copy.UpdateGroupRotationR(rot);
1935 }
1936 2145
1937 copy.CreateScriptInstances(0, false, m_parentScene.DefaultScriptEngine, 1); 2146 copy.CreateScriptInstances(0, false, m_parentScene.DefaultScriptEngine, 1);
1938 copy.HasGroupChanged = true; 2147 copy.HasGroupChanged = true;
1939 copy.ScheduleGroupForFullUpdate(); 2148 copy.ScheduleGroupForFullUpdate();
1940 copy.ResumeScripts(); 2149 copy.ResumeScripts();
1941 2150
1942 // required for physics to update it's position 2151 // required for physics to update it's position
1943 copy.AbsolutePosition = copy.AbsolutePosition; 2152 copy.AbsolutePosition = copy.AbsolutePosition;
1944 2153
1945 return copy; 2154 return copy;
2155 }
1946 } 2156 }
1947 finally 2157 else
1948 { 2158 {
1949 Monitor.Exit(m_updateLock); 2159 m_log.WarnFormat("[SCENE]: Attempted to duplicate nonexistant prim id {0}", GroupID);
1950 } 2160 }
2161
2162 return null;
1951 } 2163 }
1952 2164
1953 /// <summary>
1954 /// Calculates the distance between two Vector3s 2165 /// Calculates the distance between two Vector3s
1955 /// </summary> 2166 /// </summary>
1956 /// <param name="v1"></param> 2167 /// <param name="v1"></param>
diff --git a/OpenSim/Region/Framework/Scenes/SceneManager.cs b/OpenSim/Region/Framework/Scenes/SceneManager.cs
index d73a959..e4eaf3a 100644
--- a/OpenSim/Region/Framework/Scenes/SceneManager.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneManager.cs
@@ -356,7 +356,7 @@ namespace OpenSim.Region.Framework.Scenes
356 356
357 public bool TrySetCurrentScene(UUID regionID) 357 public bool TrySetCurrentScene(UUID regionID)
358 { 358 {
359 m_log.Debug("Searching for Region: '" + regionID + "'"); 359// m_log.Debug("Searching for Region: '" + regionID + "'");
360 360
361 lock (m_localScenes) 361 lock (m_localScenes)
362 { 362 {
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs
index 10012d0..2effa25 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs
@@ -69,10 +69,6 @@ namespace OpenSim.Region.Framework.Scenes
69 /// <summary> 69 /// <summary>
70 /// Stop the scripts contained in all the prims in this group 70 /// Stop the scripts contained in all the prims in this group
71 /// </summary> 71 /// </summary>
72 /// <param name="sceneObjectBeingDeleted">
73 /// Should be true if these scripts are being removed because the scene
74 /// object is being deleted. This will prevent spurious updates to the client.
75 /// </param>
76 public void RemoveScriptInstances(bool sceneObjectBeingDeleted) 72 public void RemoveScriptInstances(bool sceneObjectBeingDeleted)
77 { 73 {
78 SceneObjectPart[] parts = m_parts.GetArray(); 74 SceneObjectPart[] parts = m_parts.GetArray();
@@ -227,6 +223,11 @@ namespace OpenSim.Region.Framework.Scenes
227 223
228 public uint GetEffectivePermissions() 224 public uint GetEffectivePermissions()
229 { 225 {
226 return GetEffectivePermissions(false);
227 }
228
229 public uint GetEffectivePermissions(bool useBase)
230 {
230 uint perms=(uint)(PermissionMask.Modify | 231 uint perms=(uint)(PermissionMask.Modify |
231 PermissionMask.Copy | 232 PermissionMask.Copy |
232 PermissionMask.Move | 233 PermissionMask.Move |
@@ -238,7 +239,10 @@ namespace OpenSim.Region.Framework.Scenes
238 for (int i = 0; i < parts.Length; i++) 239 for (int i = 0; i < parts.Length; i++)
239 { 240 {
240 SceneObjectPart part = parts[i]; 241 SceneObjectPart part = parts[i];
241 ownerMask &= part.OwnerMask; 242 if (useBase)
243 ownerMask &= part.BaseMask;
244 else
245 ownerMask &= part.OwnerMask;
242 perms &= part.Inventory.MaskEffectivePermissions(); 246 perms &= part.Inventory.MaskEffectivePermissions();
243 } 247 }
244 248
@@ -380,6 +384,9 @@ namespace OpenSim.Region.Framework.Scenes
380 384
381 public void ResumeScripts() 385 public void ResumeScripts()
382 { 386 {
387 if (m_scene.RegionInfo.RegionSettings.DisableScripts)
388 return;
389
383 SceneObjectPart[] parts = m_parts.GetArray(); 390 SceneObjectPart[] parts = m_parts.GetArray();
384 for (int i = 0; i < parts.Length; i++) 391 for (int i = 0; i < parts.Length; i++)
385 parts[i].Inventory.ResumeScripts(); 392 parts[i].Inventory.ResumeScripts();
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 05bea8d..72d96d1 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -24,11 +24,12 @@
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 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. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Drawing; 30using System.Drawing;
31using System.IO; 31using System.IO;
32using System.Diagnostics;
32using System.Linq; 33using System.Linq;
33using System.Threading; 34using System.Threading;
34using System.Xml; 35using System.Xml;
@@ -42,6 +43,7 @@ using OpenSim.Region.Framework.Scenes.Serialization;
42 43
43namespace OpenSim.Region.Framework.Scenes 44namespace OpenSim.Region.Framework.Scenes
44{ 45{
46
45 [Flags] 47 [Flags]
46 public enum scriptEvents 48 public enum scriptEvents
47 { 49 {
@@ -105,8 +107,29 @@ namespace OpenSim.Region.Framework.Scenes
105 /// since the group's last persistent backup 107 /// since the group's last persistent backup
106 /// </summary> 108 /// </summary>
107 private bool m_hasGroupChanged = false; 109 private bool m_hasGroupChanged = false;
108 private long timeFirstChanged; 110 private long timeFirstChanged = 0;
109 private long timeLastChanged; 111 private long timeLastChanged = 0;
112 private long m_maxPersistTime = 0;
113 private long m_minPersistTime = 0;
114 private Random m_rand;
115 private bool m_suspendUpdates;
116 private List<ScenePresence> m_linkedAvatars = new List<ScenePresence>();
117
118 public bool areUpdatesSuspended
119 {
120 get
121 {
122 return m_suspendUpdates;
123 }
124 set
125 {
126 m_suspendUpdates = value;
127 if (!value)
128 {
129 QueueForUpdateCheck();
130 }
131 }
132 }
110 133
111 public bool HasGroupChanged 134 public bool HasGroupChanged
112 { 135 {
@@ -114,9 +137,39 @@ namespace OpenSim.Region.Framework.Scenes
114 { 137 {
115 if (value) 138 if (value)
116 { 139 {
140 if (m_isBackedUp)
141 {
142 m_scene.SceneGraph.FireChangeBackup(this);
143 }
117 timeLastChanged = DateTime.Now.Ticks; 144 timeLastChanged = DateTime.Now.Ticks;
118 if (!m_hasGroupChanged) 145 if (!m_hasGroupChanged)
119 timeFirstChanged = DateTime.Now.Ticks; 146 timeFirstChanged = DateTime.Now.Ticks;
147 if (m_rootPart != null && m_rootPart.UUID != null && m_scene != null)
148 {
149 if (m_rand == null)
150 {
151 byte[] val = new byte[16];
152 m_rootPart.UUID.ToBytes(val, 0);
153 m_rand = new Random(BitConverter.ToInt32(val, 0));
154 }
155
156 if (m_scene.GetRootAgentCount() == 0)
157 {
158 //If the region is empty, this change has been made by an automated process
159 //and thus we delay the persist time by a random amount between 1.5 and 2.5.
160
161 float factor = 1.5f + (float)(m_rand.NextDouble());
162 m_maxPersistTime = (long)((float)m_scene.m_persistAfter * factor);
163 m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * factor);
164 }
165 else
166 {
167 //If the region is not empty, we want to obey the minimum and maximum persist times
168 //but add a random factor so we stagger the object persistance a little
169 m_maxPersistTime = (long)((float)m_scene.m_persistAfter * (1.0d - (m_rand.NextDouble() / 5.0d))); //Multiply by 1.0-1.5
170 m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * (1.0d + (m_rand.NextDouble() / 2.0d))); //Multiply by 0.8-1.0
171 }
172 }
120 } 173 }
121 m_hasGroupChanged = value; 174 m_hasGroupChanged = value;
122 175
@@ -131,7 +184,7 @@ namespace OpenSim.Region.Framework.Scenes
131 /// Has the group changed due to an unlink operation? We record this in order to optimize deletion, since 184 /// Has the group changed due to an unlink operation? We record this in order to optimize deletion, since
132 /// an unlinked group currently has to be persisted to the database before we can perform an unlink operation. 185 /// an unlinked group currently has to be persisted to the database before we can perform an unlink operation.
133 /// </summary> 186 /// </summary>
134 public bool HasGroupChangedDueToDelink { get; private set; } 187 public bool HasGroupChangedDueToDelink { get; set; }
135 188
136 private bool isTimeToPersist() 189 private bool isTimeToPersist()
137 { 190 {
@@ -141,8 +194,19 @@ namespace OpenSim.Region.Framework.Scenes
141 return false; 194 return false;
142 if (m_scene.ShuttingDown) 195 if (m_scene.ShuttingDown)
143 return true; 196 return true;
197
198 if (m_minPersistTime == 0 || m_maxPersistTime == 0)
199 {
200 m_maxPersistTime = m_scene.m_persistAfter;
201 m_minPersistTime = m_scene.m_dontPersistBefore;
202 }
203
144 long currentTime = DateTime.Now.Ticks; 204 long currentTime = DateTime.Now.Ticks;
145 if (currentTime - timeLastChanged > m_scene.m_dontPersistBefore || currentTime - timeFirstChanged > m_scene.m_persistAfter) 205
206 if (timeLastChanged == 0) timeLastChanged = currentTime;
207 if (timeFirstChanged == 0) timeFirstChanged = currentTime;
208
209 if (currentTime - timeLastChanged > m_minPersistTime || currentTime - timeFirstChanged > m_maxPersistTime)
146 return true; 210 return true;
147 return false; 211 return false;
148 } 212 }
@@ -245,10 +309,10 @@ namespace OpenSim.Region.Framework.Scenes
245 309
246 private bool m_scriptListens_atTarget; 310 private bool m_scriptListens_atTarget;
247 private bool m_scriptListens_notAtTarget; 311 private bool m_scriptListens_notAtTarget;
248
249 private bool m_scriptListens_atRotTarget; 312 private bool m_scriptListens_atRotTarget;
250 private bool m_scriptListens_notAtRotTarget; 313 private bool m_scriptListens_notAtRotTarget;
251 314
315 public bool m_dupeInProgress = false;
252 internal Dictionary<UUID, string> m_savedScriptState; 316 internal Dictionary<UUID, string> m_savedScriptState;
253 317
254 #region Properties 318 #region Properties
@@ -285,6 +349,16 @@ namespace OpenSim.Region.Framework.Scenes
285 get { return m_parts.Count; } 349 get { return m_parts.Count; }
286 } 350 }
287 351
352// protected Quaternion m_rotation = Quaternion.Identity;
353//
354// public virtual Quaternion Rotation
355// {
356// get { return m_rotation; }
357// set {
358// m_rotation = value;
359// }
360// }
361
288 public Quaternion GroupRotation 362 public Quaternion GroupRotation
289 { 363 {
290 get { return m_rootPart.RotationOffset; } 364 get { return m_rootPart.RotationOffset; }
@@ -391,7 +465,15 @@ namespace OpenSim.Region.Framework.Scenes
391 { 465 {
392 return (IsAttachment || (m_rootPart.Shape.PCode == 9 && m_rootPart.Shape.State != 0)); 466 return (IsAttachment || (m_rootPart.Shape.PCode == 9 && m_rootPart.Shape.State != 0));
393 } 467 }
394 468
469
470
471 private struct avtocrossInfo
472 {
473 public ScenePresence av;
474 public uint ParentID;
475 }
476
395 /// <summary> 477 /// <summary>
396 /// The absolute position of this scene object in the scene 478 /// The absolute position of this scene object in the scene
397 /// </summary> 479 /// </summary>
@@ -404,14 +486,128 @@ namespace OpenSim.Region.Framework.Scenes
404 486
405 if (Scene != null) 487 if (Scene != null)
406 { 488 {
407 if ((Scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E) || Scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W) 489 // if ((Scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E) || Scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W)
408 || Scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N) || Scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S)) 490 // || Scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N) || Scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S))
491 // && !IsAttachmentCheckFull() && (!Scene.LoadingPrims))
492 if ((Scene.TestBorderCross(val, Cardinals.E) || Scene.TestBorderCross(val, Cardinals.W)
493 || Scene.TestBorderCross(val, Cardinals.N) || Scene.TestBorderCross(val, Cardinals.S))
409 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims)) 494 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims))
410 { 495 {
411 m_scene.CrossPrimGroupIntoNewRegion(val, this, true); 496 IEntityTransferModule entityTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>();
497 uint x = 0;
498 uint y = 0;
499 string version = String.Empty;
500 Vector3 newpos = Vector3.Zero;
501 OpenSim.Services.Interfaces.GridRegion destination = null;
502
503 bool canCross = true;
504 foreach (ScenePresence av in m_linkedAvatars)
505 {
506 // We need to cross these agents. First, let's find
507 // out if any of them can't cross for some reason.
508 // We have to deny the crossing entirely if any
509 // of them are banned. Alternatively, we could
510 // unsit banned agents....
511
512
513 // We set the avatar position as being the object
514 // position to get the region to send to
515 if ((destination = entityTransfer.GetDestination(m_scene, av.UUID, val, out x, out y, out version, out newpos)) == null)
516 {
517 canCross = false;
518 break;
519 }
520
521 m_log.DebugFormat("[SCENE OBJECT]: Avatar {0} needs to be crossed to {1}", av.Name, destination.RegionName);
522 }
523
524 if (canCross)
525 {
526 // We unparent the SP quietly so that it won't
527 // be made to stand up
528
529 List<avtocrossInfo> avsToCross = new List<avtocrossInfo>();
530
531 foreach (ScenePresence av in m_linkedAvatars)
532 {
533 avtocrossInfo avinfo = new avtocrossInfo();
534 SceneObjectPart parentPart = m_scene.GetSceneObjectPart(av.ParentID);
535 if (parentPart != null)
536 av.ParentUUID = parentPart.UUID;
537
538 avinfo.av = av;
539 avinfo.ParentID = av.ParentID;
540 avsToCross.Add(avinfo);
541
542 av.ParentID = 0;
543 }
544
545// m_linkedAvatars.Clear();
546 m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
547
548 // Normalize
549 if (val.X >= Constants.RegionSize)
550 val.X -= Constants.RegionSize;
551 if (val.Y >= Constants.RegionSize)
552 val.Y -= Constants.RegionSize;
553 if (val.X < 0)
554 val.X += Constants.RegionSize;
555 if (val.Y < 0)
556 val.Y += Constants.RegionSize;
557
558 // If it's deleted, crossing was successful
559 if (IsDeleted)
560 {
561 // foreach (ScenePresence av in m_linkedAvatars)
562 foreach (avtocrossInfo avinfo in avsToCross)
563 {
564 ScenePresence av = avinfo.av;
565 if (!av.IsInTransit) // just in case...
566 {
567 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar {0} to {1}", av.Name, val);
568
569 av.IsInTransit = true;
570
571 CrossAgentToNewRegionDelegate d = entityTransfer.CrossAgentToNewRegionAsync;
572 d.BeginInvoke(av, val, x, y, destination, av.Flying, version, CrossAgentToNewRegionCompleted, d);
573 }
574 else
575 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar alreasy in transit {0} to {1}", av.Name, val);
576 }
577 avsToCross.Clear();
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// m_linkedAvatars.Add(av);
588 }
589 }
590 avsToCross.Clear();
591
592 }
593 else if (RootPart.PhysActor != null)
594 {
595 RootPart.PhysActor.CrossingFailure();
596 }
597
598 Vector3 oldp = AbsolutePosition;
599 val.X = Util.Clamp<float>(oldp.X, 0.5f, (float)Constants.RegionSize - 0.5f);
600 val.Y = Util.Clamp<float>(oldp.Y, 0.5f, (float)Constants.RegionSize - 0.5f);
601 val.Z = Util.Clamp<float>(oldp.Z, 0.5f, 4096.0f);
412 } 602 }
413 } 603 }
414 604
605/* don't see the need but worse don't see where is restored to false if things stay in
606 foreach (SceneObjectPart part in m_parts.GetArray())
607 {
608 part.IgnoreUndoUpdate = true;
609 }
610 */
415 if (RootPart.GetStatusSandbox()) 611 if (RootPart.GetStatusSandbox())
416 { 612 {
417 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) 613 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10)
@@ -425,10 +621,30 @@ namespace OpenSim.Region.Framework.Scenes
425 return; 621 return;
426 } 622 }
427 } 623 }
428
429 SceneObjectPart[] parts = m_parts.GetArray(); 624 SceneObjectPart[] parts = m_parts.GetArray();
430 for (int i = 0; i < parts.Length; i++) 625 bool triggerScriptEvent = m_rootPart.GroupPosition != val;
431 parts[i].GroupPosition = val; 626 if (m_dupeInProgress)
627 triggerScriptEvent = false;
628 foreach (SceneObjectPart part in parts)
629 {
630 part.GroupPosition = val;
631 if (triggerScriptEvent)
632 part.TriggerScriptChangedEvent(Changed.POSITION);
633 }
634 if (!m_dupeInProgress)
635 {
636 foreach (ScenePresence av in m_linkedAvatars)
637 {
638 SceneObjectPart p = m_scene.GetSceneObjectPart(av.ParentID);
639 if (p != null && m_parts.TryGetValue(p.UUID, out p))
640 {
641 Vector3 offset = p.GetWorldPosition() - av.ParentPosition;
642 av.AbsolutePosition += offset;
643 av.ParentPosition = p.GetWorldPosition(); //ParentPosition gets cleared by AbsolutePosition
644 av.SendAvatarDataToAllAgents();
645 }
646 }
647 }
432 648
433 //if (m_rootPart.PhysActor != null) 649 //if (m_rootPart.PhysActor != null)
434 //{ 650 //{
@@ -443,6 +659,40 @@ namespace OpenSim.Region.Framework.Scenes
443 } 659 }
444 } 660 }
445 661
662 public override Vector3 Velocity
663 {
664 get { return RootPart.Velocity; }
665 set { RootPart.Velocity = value; }
666 }
667
668 private void CrossAgentToNewRegionCompleted(IAsyncResult iar)
669 {
670 CrossAgentToNewRegionDelegate icon = (CrossAgentToNewRegionDelegate)iar.AsyncState;
671 ScenePresence agent = icon.EndInvoke(iar);
672
673 //// If the cross was successful, this agent is a child agent
674 if (agent.IsChildAgent)
675 {
676 if (agent.ParentUUID != UUID.Zero)
677 {
678 agent.ParentPart = null;
679 agent.ParentPosition = Vector3.Zero;
680 // agent.ParentUUID = UUID.Zero;
681 }
682 }
683
684 agent.ParentUUID = UUID.Zero;
685
686// agent.Reset();
687// else // Not successful
688// agent.RestoreInCurrentScene();
689
690 // In any case
691 agent.IsInTransit = false;
692
693 m_log.DebugFormat("[SCENE OBJECT]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname);
694 }
695
446 public override uint LocalId 696 public override uint LocalId
447 { 697 {
448 get { return m_rootPart.LocalId; } 698 get { return m_rootPart.LocalId; }
@@ -524,6 +774,11 @@ namespace OpenSim.Region.Framework.Scenes
524 m_isSelected = value; 774 m_isSelected = value;
525 // Tell physics engine that group is selected 775 // Tell physics engine that group is selected
526 776
777 // this is not right
778 // but ode engines should only really need to know about root part
779 // so they can put entire object simulation on hold and not colliding
780 // keep as was for now
781
527 PhysicsActor pa = m_rootPart.PhysActor; 782 PhysicsActor pa = m_rootPart.PhysActor;
528 if (pa != null) 783 if (pa != null)
529 { 784 {
@@ -540,6 +795,42 @@ namespace OpenSim.Region.Framework.Scenes
540 childPa.Selected = value; 795 childPa.Selected = value;
541 } 796 }
542 } 797 }
798 if (RootPart.KeyframeMotion != null)
799 RootPart.KeyframeMotion.Selected = value;
800 }
801 }
802
803 public void PartSelectChanged(bool partSelect)
804 {
805 // any part selected makes group selected
806 if (m_isSelected == partSelect)
807 return;
808
809 if (partSelect)
810 {
811 IsSelected = partSelect;
812// if (!IsAttachment)
813// ScheduleGroupForFullUpdate();
814 }
815 else
816 {
817 // bad bad bad 2 heavy for large linksets
818 // since viewer does send lot of (un)selects
819 // this needs to be replaced by a specific list or count ?
820 // but that will require extra code in several places
821
822 SceneObjectPart[] parts = m_parts.GetArray();
823 for (int i = 0; i < parts.Length; i++)
824 {
825 SceneObjectPart part = parts[i];
826 if (part.IsSelected)
827 return;
828 }
829 IsSelected = partSelect;
830 if (!IsAttachment)
831 {
832 ScheduleGroupForFullUpdate();
833 }
543 } 834 }
544 } 835 }
545 836
@@ -617,6 +908,7 @@ namespace OpenSim.Region.Framework.Scenes
617 /// </summary> 908 /// </summary>
618 public SceneObjectGroup() 909 public SceneObjectGroup()
619 { 910 {
911
620 } 912 }
621 913
622 /// <summary> 914 /// <summary>
@@ -633,7 +925,7 @@ namespace OpenSim.Region.Framework.Scenes
633 /// Constructor. This object is added to the scene later via AttachToScene() 925 /// Constructor. This object is added to the scene later via AttachToScene()
634 /// </summary> 926 /// </summary>
635 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 927 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
636 { 928 {
637 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)); 929 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
638 } 930 }
639 931
@@ -669,6 +961,9 @@ namespace OpenSim.Region.Framework.Scenes
669 /// </summary> 961 /// </summary>
670 public virtual void AttachToBackup() 962 public virtual void AttachToBackup()
671 { 963 {
964 if (IsAttachment) return;
965 m_scene.SceneGraph.FireAttachToBackup(this);
966
672 if (InSceneBackup) 967 if (InSceneBackup)
673 { 968 {
674 //m_log.DebugFormat( 969 //m_log.DebugFormat(
@@ -711,6 +1006,13 @@ namespace OpenSim.Region.Framework.Scenes
711 1006
712 ApplyPhysics(); 1007 ApplyPhysics();
713 1008
1009 if (RootPart.PhysActor != null)
1010 RootPart.Force = RootPart.Force;
1011 if (RootPart.PhysActor != null)
1012 RootPart.Torque = RootPart.Torque;
1013 if (RootPart.PhysActor != null)
1014 RootPart.Buoyancy = RootPart.Buoyancy;
1015
714 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled 1016 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled
715 // for the same object with very different properties. The caller must schedule the update. 1017 // for the same object with very different properties. The caller must schedule the update.
716 //ScheduleGroupForFullUpdate(); 1018 //ScheduleGroupForFullUpdate();
@@ -726,6 +1028,10 @@ namespace OpenSim.Region.Framework.Scenes
726 EntityIntersection result = new EntityIntersection(); 1028 EntityIntersection result = new EntityIntersection();
727 1029
728 SceneObjectPart[] parts = m_parts.GetArray(); 1030 SceneObjectPart[] parts = m_parts.GetArray();
1031
1032 // Find closest hit here
1033 float idist = float.MaxValue;
1034
729 for (int i = 0; i < parts.Length; i++) 1035 for (int i = 0; i < parts.Length; i++)
730 { 1036 {
731 SceneObjectPart part = parts[i]; 1037 SceneObjectPart part = parts[i];
@@ -740,11 +1046,6 @@ namespace OpenSim.Region.Framework.Scenes
740 1046
741 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters); 1047 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters);
742 1048
743 // This may need to be updated to the maximum draw distance possible..
744 // We might (and probably will) be checking for prim creation from other sims
745 // when the camera crosses the border.
746 float idist = Constants.RegionSize;
747
748 if (inter.HitTF) 1049 if (inter.HitTF)
749 { 1050 {
750 // We need to find the closest prim to return to the testcaller along the ray 1051 // We need to find the closest prim to return to the testcaller along the ray
@@ -755,10 +1056,11 @@ namespace OpenSim.Region.Framework.Scenes
755 result.obj = part; 1056 result.obj = part;
756 result.normal = inter.normal; 1057 result.normal = inter.normal;
757 result.distance = inter.distance; 1058 result.distance = inter.distance;
1059
1060 idist = inter.distance;
758 } 1061 }
759 } 1062 }
760 } 1063 }
761
762 return result; 1064 return result;
763 } 1065 }
764 1066
@@ -770,25 +1072,27 @@ namespace OpenSim.Region.Framework.Scenes
770 /// <returns></returns> 1072 /// <returns></returns>
771 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ) 1073 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ)
772 { 1074 {
773 maxX = -256f; 1075 maxX = float.MinValue;
774 maxY = -256f; 1076 maxY = float.MinValue;
775 maxZ = -256f; 1077 maxZ = float.MinValue;
776 minX = 256f; 1078 minX = float.MaxValue;
777 minY = 256f; 1079 minY = float.MaxValue;
778 minZ = 8192f; 1080 minZ = float.MaxValue;
779 1081
780 SceneObjectPart[] parts = m_parts.GetArray(); 1082 SceneObjectPart[] parts = m_parts.GetArray();
781 for (int i = 0; i < parts.Length; i++) 1083 foreach (SceneObjectPart part in parts)
782 { 1084 {
783 SceneObjectPart part = parts[i];
784
785 Vector3 worldPos = part.GetWorldPosition(); 1085 Vector3 worldPos = part.GetWorldPosition();
786 Vector3 offset = worldPos - AbsolutePosition; 1086 Vector3 offset = worldPos - AbsolutePosition;
787 Quaternion worldRot; 1087 Quaternion worldRot;
788 if (part.ParentID == 0) 1088 if (part.ParentID == 0)
1089 {
789 worldRot = part.RotationOffset; 1090 worldRot = part.RotationOffset;
1091 }
790 else 1092 else
1093 {
791 worldRot = part.GetWorldRotation(); 1094 worldRot = part.GetWorldRotation();
1095 }
792 1096
793 Vector3 frontTopLeft; 1097 Vector3 frontTopLeft;
794 Vector3 frontTopRight; 1098 Vector3 frontTopRight;
@@ -800,6 +1104,8 @@ namespace OpenSim.Region.Framework.Scenes
800 Vector3 backBottomLeft; 1104 Vector3 backBottomLeft;
801 Vector3 backBottomRight; 1105 Vector3 backBottomRight;
802 1106
1107 // Vector3[] corners = new Vector3[8];
1108
803 Vector3 orig = Vector3.Zero; 1109 Vector3 orig = Vector3.Zero;
804 1110
805 frontTopLeft.X = orig.X - (part.Scale.X / 2); 1111 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -834,6 +1140,38 @@ namespace OpenSim.Region.Framework.Scenes
834 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 1140 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
835 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 1141 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
836 1142
1143
1144
1145 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1146 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1147 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1148 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1149 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1150 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1151 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1152 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1153
1154 //for (int i = 0; i < 8; i++)
1155 //{
1156 // corners[i] = corners[i] * worldRot;
1157 // corners[i] += offset;
1158
1159 // if (corners[i].X > maxX)
1160 // maxX = corners[i].X;
1161 // if (corners[i].X < minX)
1162 // minX = corners[i].X;
1163
1164 // if (corners[i].Y > maxY)
1165 // maxY = corners[i].Y;
1166 // if (corners[i].Y < minY)
1167 // minY = corners[i].Y;
1168
1169 // if (corners[i].Z > maxZ)
1170 // maxZ = corners[i].Y;
1171 // if (corners[i].Z < minZ)
1172 // minZ = corners[i].Z;
1173 //}
1174
837 frontTopLeft = frontTopLeft * worldRot; 1175 frontTopLeft = frontTopLeft * worldRot;
838 frontTopRight = frontTopRight * worldRot; 1176 frontTopRight = frontTopRight * worldRot;
839 frontBottomLeft = frontBottomLeft * worldRot; 1177 frontBottomLeft = frontBottomLeft * worldRot;
@@ -855,6 +1193,15 @@ namespace OpenSim.Region.Framework.Scenes
855 backTopLeft += offset; 1193 backTopLeft += offset;
856 backTopRight += offset; 1194 backTopRight += offset;
857 1195
1196 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1197 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1198 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1199 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1200 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1201 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1202 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1203 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1204
858 if (frontTopRight.X > maxX) 1205 if (frontTopRight.X > maxX)
859 maxX = frontTopRight.X; 1206 maxX = frontTopRight.X;
860 if (frontTopLeft.X > maxX) 1207 if (frontTopLeft.X > maxX)
@@ -998,17 +1345,118 @@ namespace OpenSim.Region.Framework.Scenes
998 1345
999 #endregion 1346 #endregion
1000 1347
1348 public void GetResourcesCosts(SceneObjectPart apart,
1349 out float linksetResCost, out float linksetPhysCost, out float partCost, out float partPhysCost)
1350 {
1351 // this information may need to be cached
1352
1353 float cost;
1354 float tmpcost;
1355
1356 bool ComplexCost = false;
1357
1358 SceneObjectPart p;
1359 SceneObjectPart[] parts;
1360
1361 lock (m_parts)
1362 {
1363 parts = m_parts.GetArray();
1364 }
1365
1366 int nparts = parts.Length;
1367
1368
1369 for (int i = 0; i < nparts; i++)
1370 {
1371 p = parts[i];
1372
1373 if (p.UsesComplexCost)
1374 {
1375 ComplexCost = true;
1376 break;
1377 }
1378 }
1379
1380 if (ComplexCost)
1381 {
1382 linksetResCost = 0;
1383 linksetPhysCost = 0;
1384 partCost = 0;
1385 partPhysCost = 0;
1386
1387 for (int i = 0; i < nparts; i++)
1388 {
1389 p = parts[i];
1390
1391 cost = p.StreamingCost;
1392 tmpcost = p.SimulationCost;
1393 if (tmpcost > cost)
1394 cost = tmpcost;
1395 tmpcost = p.PhysicsCost;
1396 if (tmpcost > cost)
1397 cost = tmpcost;
1398
1399 linksetPhysCost += tmpcost;
1400 linksetResCost += cost;
1401
1402 if (p == apart)
1403 {
1404 partCost = cost;
1405 partPhysCost = tmpcost;
1406 }
1407 }
1408 }
1409 else
1410 {
1411 partPhysCost = 1.0f;
1412 partCost = 1.0f;
1413 linksetResCost = (float)nparts;
1414 linksetPhysCost = linksetResCost;
1415 }
1416 }
1417
1418 public void GetSelectedCosts(out float PhysCost, out float StreamCost, out float SimulCost)
1419 {
1420 SceneObjectPart p;
1421 SceneObjectPart[] parts;
1422
1423 lock (m_parts)
1424 {
1425 parts = m_parts.GetArray();
1426 }
1427
1428 int nparts = parts.Length;
1429
1430 PhysCost = 0;
1431 StreamCost = 0;
1432 SimulCost = 0;
1433
1434 for (int i = 0; i < nparts; i++)
1435 {
1436 p = parts[i];
1437
1438 StreamCost += p.StreamingCost;
1439 SimulCost += p.SimulationCost;
1440 PhysCost += p.PhysicsCost;
1441 }
1442 }
1443
1001 public void SaveScriptedState(XmlTextWriter writer) 1444 public void SaveScriptedState(XmlTextWriter writer)
1002 { 1445 {
1446 SaveScriptedState(writer, false);
1447 }
1448
1449 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1450 {
1003 XmlDocument doc = new XmlDocument(); 1451 XmlDocument doc = new XmlDocument();
1004 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1452 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
1005 1453
1006 SceneObjectPart[] parts = m_parts.GetArray(); 1454 SceneObjectPart[] parts = m_parts.GetArray();
1007 for (int i = 0; i < parts.Length; i++) 1455 for (int i = 0; i < parts.Length; i++)
1008 { 1456 {
1009 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1457 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
1010 foreach (KeyValuePair<UUID, string> kvp in pstates) 1458 foreach (KeyValuePair<UUID, string> kvp in pstates)
1011 states.Add(kvp.Key, kvp.Value); 1459 states[kvp.Key] = kvp.Value;
1012 } 1460 }
1013 1461
1014 if (states.Count > 0) 1462 if (states.Count > 0)
@@ -1028,6 +1476,169 @@ namespace OpenSim.Region.Framework.Scenes
1028 } 1476 }
1029 1477
1030 /// <summary> 1478 /// <summary>
1479 /// Add the avatar to this linkset (avatar is sat).
1480 /// </summary>
1481 /// <param name="agentID"></param>
1482 public void AddAvatar(UUID agentID)
1483 {
1484 ScenePresence presence;
1485 if (m_scene.TryGetScenePresence(agentID, out presence))
1486 {
1487 if (!m_linkedAvatars.Contains(presence))
1488 {
1489 m_linkedAvatars.Add(presence);
1490 }
1491 }
1492 }
1493
1494 /// <summary>
1495 /// Delete the avatar from this linkset (avatar is unsat).
1496 /// </summary>
1497 /// <param name="agentID"></param>
1498 public void DeleteAvatar(UUID agentID)
1499 {
1500 ScenePresence presence;
1501 if (m_scene.TryGetScenePresence(agentID, out presence))
1502 {
1503 if (m_linkedAvatars.Contains(presence))
1504 {
1505 m_linkedAvatars.Remove(presence);
1506 }
1507 }
1508 }
1509
1510 /// <summary>
1511 /// Returns the list of linked presences (avatars sat on this group)
1512 /// </summary>
1513 /// <param name="agentID"></param>
1514 public List<ScenePresence> GetLinkedAvatars()
1515 {
1516 return m_linkedAvatars;
1517 }
1518
1519 /// <summary>
1520 /// Attach this scene object to the given avatar.
1521 /// </summary>
1522 /// <param name="agentID"></param>
1523 /// <param name="attachmentpoint"></param>
1524 /// <param name="AttachOffset"></param>
1525 private void AttachToAgent(
1526 ScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent)
1527 {
1528 if (avatar != null)
1529 {
1530 // don't attach attachments to child agents
1531 if (avatar.IsChildAgent) return;
1532
1533 // Remove from database and parcel prim count
1534 m_scene.DeleteFromStorage(so.UUID);
1535 m_scene.EventManager.TriggerParcelPrimCountTainted();
1536
1537 so.AttachedAvatar = avatar.UUID;
1538
1539 if (so.RootPart.PhysActor != null)
1540 {
1541 m_scene.PhysicsScene.RemovePrim(so.RootPart.PhysActor);
1542 so.RootPart.PhysActor = null;
1543 }
1544
1545 so.AbsolutePosition = attachOffset;
1546 so.RootPart.AttachedPos = attachOffset;
1547 so.IsAttachment = true;
1548 so.RootPart.SetParentLocalId(avatar.LocalId);
1549 so.AttachmentPoint = attachmentpoint;
1550
1551 avatar.AddAttachment(this);
1552
1553 if (!silent)
1554 {
1555 // Killing it here will cause the client to deselect it
1556 // It then reappears on the avatar, deselected
1557 // through the full update below
1558 //
1559 if (IsSelected)
1560 {
1561 m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1562 }
1563
1564 IsSelected = false; // fudge....
1565 ScheduleGroupForFullUpdate();
1566 }
1567 }
1568 else
1569 {
1570 m_log.WarnFormat(
1571 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1572 UUID, avatar.ControllingClient.AgentId, Scene.RegionInfo.RegionName);
1573 }
1574 }
1575
1576 public byte GetAttachmentPoint()
1577 {
1578 return m_rootPart.Shape.State;
1579 }
1580
1581 public void DetachToGround()
1582 {
1583 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1584 if (avatar == null)
1585 return;
1586
1587 avatar.RemoveAttachment(this);
1588
1589 Vector3 detachedpos = new Vector3(127f,127f,127f);
1590 if (avatar == null)
1591 return;
1592
1593 detachedpos = avatar.AbsolutePosition;
1594 FromItemID = UUID.Zero;
1595
1596 AbsolutePosition = detachedpos;
1597 AttachedAvatar = UUID.Zero;
1598
1599 //SceneObjectPart[] parts = m_parts.GetArray();
1600 //for (int i = 0; i < parts.Length; i++)
1601 // parts[i].AttachedAvatar = UUID.Zero;
1602
1603 m_rootPart.SetParentLocalId(0);
1604 AttachmentPoint = (byte)0;
1605 // must check if buildind should be true or false here
1606 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive,false);
1607 HasGroupChanged = true;
1608 RootPart.Rezzed = DateTime.Now;
1609 RootPart.RemFlag(PrimFlags.TemporaryOnRez);
1610 AttachToBackup();
1611 m_scene.EventManager.TriggerParcelPrimCountTainted();
1612 m_rootPart.ScheduleFullUpdate();
1613 m_rootPart.ClearUndoState();
1614 }
1615
1616 public void DetachToInventoryPrep()
1617 {
1618 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1619 //Vector3 detachedpos = new Vector3(127f, 127f, 127f);
1620 if (avatar != null)
1621 {
1622 //detachedpos = avatar.AbsolutePosition;
1623 avatar.RemoveAttachment(this);
1624 }
1625
1626 AttachedAvatar = UUID.Zero;
1627
1628 /*SceneObjectPart[] parts = m_parts.GetArray();
1629 for (int i = 0; i < parts.Length; i++)
1630 parts[i].AttachedAvatar = UUID.Zero;*/
1631
1632 m_rootPart.SetParentLocalId(0);
1633 //m_rootPart.SetAttachmentPoint((byte)0);
1634 IsAttachment = false;
1635 AbsolutePosition = m_rootPart.AttachedPos;
1636 //m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_scene.m_physicalPrim);
1637 //AttachToBackup();
1638 //m_rootPart.ScheduleFullUpdate();
1639 }
1640
1641 /// <summary>
1031 /// 1642 ///
1032 /// </summary> 1643 /// </summary>
1033 /// <param name="part"></param> 1644 /// <param name="part"></param>
@@ -1077,7 +1688,10 @@ namespace OpenSim.Region.Framework.Scenes
1077 public void AddPart(SceneObjectPart part) 1688 public void AddPart(SceneObjectPart part)
1078 { 1689 {
1079 part.SetParent(this); 1690 part.SetParent(this);
1080 part.LinkNum = m_parts.Add(part.UUID, part); 1691 m_parts.Add(part.UUID, part);
1692
1693 part.LinkNum = m_parts.Count;
1694
1081 if (part.LinkNum == 2) 1695 if (part.LinkNum == 2)
1082 RootPart.LinkNum = 1; 1696 RootPart.LinkNum = 1;
1083 } 1697 }
@@ -1165,7 +1779,7 @@ namespace OpenSim.Region.Framework.Scenes
1165// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}", 1779// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}",
1166// remoteClient.Name, part.Name, part.LocalId, offsetPos); 1780// remoteClient.Name, part.Name, part.LocalId, offsetPos);
1167 1781
1168 part.StoreUndoState(); 1782// part.StoreUndoState();
1169 part.OnGrab(offsetPos, remoteClient); 1783 part.OnGrab(offsetPos, remoteClient);
1170 } 1784 }
1171 1785
@@ -1185,6 +1799,11 @@ namespace OpenSim.Region.Framework.Scenes
1185 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1799 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1186 public void DeleteGroupFromScene(bool silent) 1800 public void DeleteGroupFromScene(bool silent)
1187 { 1801 {
1802 // We need to keep track of this state in case this group is still queued for backup.
1803 IsDeleted = true;
1804
1805 DetachFromBackup();
1806
1188 SceneObjectPart[] parts = m_parts.GetArray(); 1807 SceneObjectPart[] parts = m_parts.GetArray();
1189 for (int i = 0; i < parts.Length; i++) 1808 for (int i = 0; i < parts.Length; i++)
1190 { 1809 {
@@ -1200,13 +1819,14 @@ namespace OpenSim.Region.Framework.Scenes
1200 part.ClearUpdateSchedule(); 1819 part.ClearUpdateSchedule();
1201 if (part == m_rootPart) 1820 if (part == m_rootPart)
1202 { 1821 {
1203 if (!IsAttachment || (AttachedAvatar == avatar.ControllingClient.AgentId) || 1822 if (!IsAttachment || (AttachedAvatar == avatar.ControllingClient.AgentId) ||
1204 (AttachmentPoint < 31) || (AttachmentPoint > 38)) 1823 (AttachmentPoint < 31) || (AttachmentPoint > 38))
1205 avatar.ControllingClient.SendKillObject(m_regionHandle, new List<uint> { part.LocalId }); 1824 avatar.ControllingClient.SendKillObject(m_regionHandle, new List<uint> { part.LocalId });
1206 } 1825 }
1207 } 1826 }
1208 }); 1827 });
1209 } 1828 }
1829
1210 } 1830 }
1211 1831
1212 public void AddScriptLPS(int count) 1832 public void AddScriptLPS(int count)
@@ -1276,28 +1896,43 @@ namespace OpenSim.Region.Framework.Scenes
1276 /// </summary> 1896 /// </summary>
1277 public void ApplyPhysics() 1897 public void ApplyPhysics()
1278 { 1898 {
1279 // Apply physics to the root prim
1280 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive);
1281
1282 // Apply physics to child prims
1283 SceneObjectPart[] parts = m_parts.GetArray(); 1899 SceneObjectPart[] parts = m_parts.GetArray();
1284 if (parts.Length > 1) 1900 if (parts.Length > 1)
1285 { 1901 {
1902 ResetChildPrimPhysicsPositions();
1903
1904 // Apply physics to the root prim
1905 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, true);
1906
1907
1286 for (int i = 0; i < parts.Length; i++) 1908 for (int i = 0; i < parts.Length; i++)
1287 { 1909 {
1288 SceneObjectPart part = parts[i]; 1910 SceneObjectPart part = parts[i];
1289 if (part.LocalId != m_rootPart.LocalId) 1911 if (part.LocalId != m_rootPart.LocalId)
1290 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive); 1912 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, true);
1291 } 1913 }
1292
1293 // Hack to get the physics scene geometries in the right spot 1914 // Hack to get the physics scene geometries in the right spot
1294 ResetChildPrimPhysicsPositions(); 1915// ResetChildPrimPhysicsPositions();
1916 if (m_rootPart.PhysActor != null)
1917 {
1918 m_rootPart.PhysActor.Building = false;
1919 }
1920 }
1921 else
1922 {
1923 // Apply physics to the root prim
1924 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, false);
1295 } 1925 }
1296 } 1926 }
1297 1927
1298 public void SetOwnerId(UUID userId) 1928 public void SetOwnerId(UUID userId)
1299 { 1929 {
1300 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1930 ForEachPart(delegate(SceneObjectPart part)
1931 {
1932
1933 part.OwnerID = userId;
1934
1935 });
1301 } 1936 }
1302 1937
1303 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1938 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1329,11 +1964,17 @@ namespace OpenSim.Region.Framework.Scenes
1329 return; 1964 return;
1330 } 1965 }
1331 1966
1967 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
1968 return;
1969
1332 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 1970 // Since this is the top of the section of call stack for backing up a particular scene object, don't let
1333 // any exception propogate upwards. 1971 // any exception propogate upwards.
1334 try 1972 try
1335 { 1973 {
1336 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 1974 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
1975 m_scene.LoginsDisabled || // We're starting up or doing maintenance, don't mess with things
1976 m_scene.LoadingPrims) // Land may not be valid yet
1977
1337 { 1978 {
1338 ILandObject parcel = m_scene.LandChannel.GetLandObject( 1979 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1339 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 1980 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1360,6 +2001,7 @@ namespace OpenSim.Region.Framework.Scenes
1360 } 2001 }
1361 } 2002 }
1362 } 2003 }
2004
1363 } 2005 }
1364 2006
1365 if (m_scene.UseBackup && HasGroupChanged) 2007 if (m_scene.UseBackup && HasGroupChanged)
@@ -1367,10 +2009,30 @@ namespace OpenSim.Region.Framework.Scenes
1367 // don't backup while it's selected or you're asking for changes mid stream. 2009 // don't backup while it's selected or you're asking for changes mid stream.
1368 if (isTimeToPersist() || forcedBackup) 2010 if (isTimeToPersist() || forcedBackup)
1369 { 2011 {
2012 if (m_rootPart.PhysActor != null &&
2013 (!m_rootPart.PhysActor.IsPhysical))
2014 {
2015 // Possible ghost prim
2016 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
2017 {
2018 foreach (SceneObjectPart part in m_parts.GetArray())
2019 {
2020 // Re-set physics actor positions and
2021 // orientations
2022 part.GroupPosition = m_rootPart.GroupPosition;
2023 }
2024 }
2025 }
1370// m_log.DebugFormat( 2026// m_log.DebugFormat(
1371// "[SCENE]: Storing {0}, {1} in {2}", 2027// "[SCENE]: Storing {0}, {1} in {2}",
1372// Name, UUID, m_scene.RegionInfo.RegionName); 2028// Name, UUID, m_scene.RegionInfo.RegionName);
1373 2029
2030 if (RootPart.Shape.PCode == 9 && RootPart.Shape.State != 0)
2031 {
2032 RootPart.Shape.State = 0;
2033 ScheduleGroupForFullUpdate();
2034 }
2035
1374 SceneObjectGroup backup_group = Copy(false); 2036 SceneObjectGroup backup_group = Copy(false);
1375 backup_group.RootPart.Velocity = RootPart.Velocity; 2037 backup_group.RootPart.Velocity = RootPart.Velocity;
1376 backup_group.RootPart.Acceleration = RootPart.Acceleration; 2038 backup_group.RootPart.Acceleration = RootPart.Acceleration;
@@ -1384,6 +2046,11 @@ namespace OpenSim.Region.Framework.Scenes
1384 2046
1385 backup_group.ForEachPart(delegate(SceneObjectPart part) 2047 backup_group.ForEachPart(delegate(SceneObjectPart part)
1386 { 2048 {
2049 if (part.KeyframeMotion != null)
2050 {
2051 part.KeyframeMotion = KeyframeMotion.FromData(backup_group, part.KeyframeMotion.Serialize());
2052 part.KeyframeMotion.UpdateSceneObject(this);
2053 }
1387 part.Inventory.ProcessInventoryBackup(datastore); 2054 part.Inventory.ProcessInventoryBackup(datastore);
1388 }); 2055 });
1389 2056
@@ -1436,10 +2103,14 @@ namespace OpenSim.Region.Framework.Scenes
1436 /// <returns></returns> 2103 /// <returns></returns>
1437 public SceneObjectGroup Copy(bool userExposed) 2104 public SceneObjectGroup Copy(bool userExposed)
1438 { 2105 {
2106 m_dupeInProgress = true;
1439 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 2107 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone();
1440 dupe.m_isBackedUp = false; 2108 dupe.m_isBackedUp = false;
1441 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 2109 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
1442 2110
2111 // new group as no sitting avatars
2112 dupe.m_linkedAvatars = new List<ScenePresence>();
2113
1443 // Warning, The following code related to previousAttachmentStatus is needed so that clones of 2114 // Warning, The following code related to previousAttachmentStatus is needed so that clones of
1444 // attachments do not bordercross while they're being duplicated. This is hacktastic! 2115 // attachments do not bordercross while they're being duplicated. This is hacktastic!
1445 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region! 2116 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
@@ -1450,7 +2121,7 @@ namespace OpenSim.Region.Framework.Scenes
1450 // This is only necessary when userExposed is false! 2121 // This is only necessary when userExposed is false!
1451 2122
1452 bool previousAttachmentStatus = dupe.IsAttachment; 2123 bool previousAttachmentStatus = dupe.IsAttachment;
1453 2124
1454 if (!userExposed) 2125 if (!userExposed)
1455 dupe.IsAttachment = true; 2126 dupe.IsAttachment = true;
1456 2127
@@ -1468,11 +2139,11 @@ namespace OpenSim.Region.Framework.Scenes
1468 dupe.m_rootPart.TrimPermissions(); 2139 dupe.m_rootPart.TrimPermissions();
1469 2140
1470 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 2141 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1471 2142
1472 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) 2143 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1473 { 2144 {
1474 return p1.LinkNum.CompareTo(p2.LinkNum); 2145 return p1.LinkNum.CompareTo(p2.LinkNum);
1475 } 2146 }
1476 ); 2147 );
1477 2148
1478 foreach (SceneObjectPart part in partList) 2149 foreach (SceneObjectPart part in partList)
@@ -1482,41 +2153,53 @@ namespace OpenSim.Region.Framework.Scenes
1482 { 2153 {
1483 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 2154 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1484 newPart.LinkNum = part.LinkNum; 2155 newPart.LinkNum = part.LinkNum;
1485 } 2156 if (userExposed)
2157 newPart.ParentID = dupe.m_rootPart.LocalId;
2158 }
1486 else 2159 else
1487 { 2160 {
1488 newPart = dupe.m_rootPart; 2161 newPart = dupe.m_rootPart;
1489 } 2162 }
2163/*
2164 bool isphys = ((newPart.Flags & PrimFlags.Physics) != 0);
2165 bool isphan = ((newPart.Flags & PrimFlags.Phantom) != 0);
1490 2166
1491 // Need to duplicate the physics actor as well 2167 // Need to duplicate the physics actor as well
1492 PhysicsActor originalPartPa = part.PhysActor; 2168 if (userExposed && (isphys || !isphan || newPart.VolumeDetectActive))
1493 if (originalPartPa != null && userExposed)
1494 { 2169 {
1495 PrimitiveBaseShape pbs = newPart.Shape; 2170 PrimitiveBaseShape pbs = newPart.Shape;
1496
1497 newPart.PhysActor 2171 newPart.PhysActor
1498 = m_scene.PhysicsScene.AddPrimShape( 2172 = m_scene.PhysicsScene.AddPrimShape(
1499 string.Format("{0}/{1}", newPart.Name, newPart.UUID), 2173 string.Format("{0}/{1}", newPart.Name, newPart.UUID),
1500 pbs, 2174 pbs,
1501 newPart.AbsolutePosition, 2175 newPart.AbsolutePosition,
1502 newPart.Scale, 2176 newPart.Scale,
1503 newPart.RotationOffset, 2177 newPart.GetWorldRotation(),
1504 originalPartPa.IsPhysical, 2178 isphys,
2179 isphan,
1505 newPart.LocalId); 2180 newPart.LocalId);
1506 2181
1507 newPart.DoPhysicsPropertyUpdate(originalPartPa.IsPhysical, true); 2182 newPart.DoPhysicsPropertyUpdate(isphys, true);
1508 } 2183 */
2184 if (userExposed)
2185 newPart.ApplyPhysics((uint)newPart.Flags,newPart.VolumeDetectActive,true);
2186// }
1509 } 2187 }
1510 2188
1511 if (userExposed) 2189 if (userExposed)
1512 { 2190 {
1513 dupe.UpdateParentIDs(); 2191// done above dupe.UpdateParentIDs();
2192
2193 if (dupe.m_rootPart.PhysActor != null)
2194 dupe.m_rootPart.PhysActor.Building = false; // tell physics to finish building
2195
1514 dupe.HasGroupChanged = true; 2196 dupe.HasGroupChanged = true;
1515 dupe.AttachToBackup(); 2197 dupe.AttachToBackup();
1516 2198
1517 ScheduleGroupForFullUpdate(); 2199 ScheduleGroupForFullUpdate();
1518 } 2200 }
1519 2201
2202 m_dupeInProgress = false;
1520 return dupe; 2203 return dupe;
1521 } 2204 }
1522 2205
@@ -1528,11 +2211,24 @@ namespace OpenSim.Region.Framework.Scenes
1528 /// <param name="cGroupID"></param> 2211 /// <param name="cGroupID"></param>
1529 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2212 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1530 { 2213 {
1531 SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed)); 2214 // SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed));
2215 // give newpart a new local ID lettng old part keep same
2216 SceneObjectPart newpart = part.Copy(part.LocalId, OwnerID, GroupID, 0, userExposed);
2217 newpart.LocalId = m_scene.AllocateLocalId();
2218
2219 SetRootPart(newpart);
2220 if (userExposed)
2221 RootPart.Velocity = Vector3.Zero; // In case source is moving
1532 } 2222 }
1533 2223
1534 public void ScriptSetPhysicsStatus(bool usePhysics) 2224 public void ScriptSetPhysicsStatus(bool usePhysics)
1535 { 2225 {
2226 if (usePhysics)
2227 {
2228 if (RootPart.KeyframeMotion != null)
2229 RootPart.KeyframeMotion.Stop();
2230 RootPart.KeyframeMotion = null;
2231 }
1536 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect); 2232 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
1537 } 2233 }
1538 2234
@@ -1580,13 +2276,14 @@ namespace OpenSim.Region.Framework.Scenes
1580 2276
1581 if (pa != null) 2277 if (pa != null)
1582 { 2278 {
1583 pa.AddForce(impulse, true); 2279 // false to be applied as a impulse
2280 pa.AddForce(impulse, false);
1584 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2281 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1585 } 2282 }
1586 } 2283 }
1587 } 2284 }
1588 2285
1589 public void applyAngularImpulse(Vector3 impulse) 2286 public void ApplyAngularImpulse(Vector3 impulse)
1590 { 2287 {
1591 PhysicsActor pa = RootPart.PhysActor; 2288 PhysicsActor pa = RootPart.PhysActor;
1592 2289
@@ -1594,21 +2291,8 @@ namespace OpenSim.Region.Framework.Scenes
1594 { 2291 {
1595 if (!IsAttachment) 2292 if (!IsAttachment)
1596 { 2293 {
1597 pa.AddAngularForce(impulse, true); 2294 // false to be applied as a impulse
1598 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2295 pa.AddAngularForce(impulse, false);
1599 }
1600 }
1601 }
1602
1603 public void setAngularImpulse(Vector3 impulse)
1604 {
1605 PhysicsActor pa = RootPart.PhysActor;
1606
1607 if (pa != null)
1608 {
1609 if (!IsAttachment)
1610 {
1611 pa.Torque = impulse;
1612 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2296 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1613 } 2297 }
1614 } 2298 }
@@ -1616,20 +2300,10 @@ namespace OpenSim.Region.Framework.Scenes
1616 2300
1617 public Vector3 GetTorque() 2301 public Vector3 GetTorque()
1618 { 2302 {
1619 PhysicsActor pa = RootPart.PhysActor; 2303 return RootPart.Torque;
1620
1621 if (pa != null)
1622 {
1623 if (!IsAttachment)
1624 {
1625 Vector3 torque = pa.Torque;
1626 return torque;
1627 }
1628 }
1629
1630 return Vector3.Zero;
1631 } 2304 }
1632 2305
2306 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1633 public void moveToTarget(Vector3 target, float tau) 2307 public void moveToTarget(Vector3 target, float tau)
1634 { 2308 {
1635 if (IsAttachment) 2309 if (IsAttachment)
@@ -1661,6 +2335,46 @@ namespace OpenSim.Region.Framework.Scenes
1661 pa.PIDActive = false; 2335 pa.PIDActive = false;
1662 } 2336 }
1663 2337
2338 public void rotLookAt(Quaternion target, float strength, float damping)
2339 {
2340 SceneObjectPart rootpart = m_rootPart;
2341 if (rootpart != null)
2342 {
2343 if (IsAttachment)
2344 {
2345 /*
2346 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
2347 if (avatar != null)
2348 {
2349 Rotate the Av?
2350 } */
2351 }
2352 else
2353 {
2354 if (rootpart.PhysActor != null)
2355 { // APID must be implemented in your physics system for this to function.
2356 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2357 rootpart.PhysActor.APIDStrength = strength;
2358 rootpart.PhysActor.APIDDamping = damping;
2359 rootpart.PhysActor.APIDActive = true;
2360 }
2361 }
2362 }
2363 }
2364
2365 public void stopLookAt()
2366 {
2367 SceneObjectPart rootpart = m_rootPart;
2368 if (rootpart != null)
2369 {
2370 if (rootpart.PhysActor != null)
2371 { // APID must be implemented in your physics system for this to function.
2372 rootpart.PhysActor.APIDActive = false;
2373 }
2374 }
2375
2376 }
2377
1664 /// <summary> 2378 /// <summary>
1665 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds. 2379 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
1666 /// </summary> 2380 /// </summary>
@@ -1677,7 +2391,7 @@ namespace OpenSim.Region.Framework.Scenes
1677 { 2391 {
1678 pa.PIDHoverHeight = height; 2392 pa.PIDHoverHeight = height;
1679 pa.PIDHoverType = hoverType; 2393 pa.PIDHoverType = hoverType;
1680 pa.PIDTau = tau; 2394 pa.PIDHoverTau = tau;
1681 pa.PIDHoverActive = true; 2395 pa.PIDHoverActive = true;
1682 } 2396 }
1683 else 2397 else
@@ -1717,7 +2431,12 @@ namespace OpenSim.Region.Framework.Scenes
1717 /// <param name="cGroupID"></param> 2431 /// <param name="cGroupID"></param>
1718 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2432 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1719 { 2433 {
1720 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2434 // give new ID to the new part, letting old keep original
2435 // SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2436 SceneObjectPart newPart = part.Copy(part.LocalId, OwnerID, GroupID, m_parts.Count, userExposed);
2437 newPart.LocalId = m_scene.AllocateLocalId();
2438 newPart.SetParent(this);
2439
1721 AddPart(newPart); 2440 AddPart(newPart);
1722 2441
1723 SetPartAsNonRoot(newPart); 2442 SetPartAsNonRoot(newPart);
@@ -1846,11 +2565,11 @@ namespace OpenSim.Region.Framework.Scenes
1846 /// Immediately send a full update for this scene object. 2565 /// Immediately send a full update for this scene object.
1847 /// </summary> 2566 /// </summary>
1848 public void SendGroupFullUpdate() 2567 public void SendGroupFullUpdate()
1849 { 2568 {
1850 if (IsDeleted) 2569 if (IsDeleted)
1851 return; 2570 return;
1852 2571
1853// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2572// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1854 2573
1855 RootPart.SendFullUpdateToAllClients(); 2574 RootPart.SendFullUpdateToAllClients();
1856 2575
@@ -1984,6 +2703,11 @@ namespace OpenSim.Region.Framework.Scenes
1984 2703
1985 SceneObjectPart linkPart = objectGroup.m_rootPart; 2704 SceneObjectPart linkPart = objectGroup.m_rootPart;
1986 2705
2706 if (m_rootPart.PhysActor != null)
2707 m_rootPart.PhysActor.Building = true;
2708 if (linkPart.PhysActor != null)
2709 linkPart.PhysActor.Building = true;
2710
1987 // physics flags from group to be applied to linked parts 2711 // physics flags from group to be applied to linked parts
1988 bool grpusephys = UsesPhysics; 2712 bool grpusephys = UsesPhysics;
1989 bool grptemporary = IsTemporary; 2713 bool grptemporary = IsTemporary;
@@ -1992,19 +2716,21 @@ namespace OpenSim.Region.Framework.Scenes
1992 Quaternion oldRootRotation = linkPart.RotationOffset; 2716 Quaternion oldRootRotation = linkPart.RotationOffset;
1993 2717
1994 linkPart.OffsetPosition = linkPart.GroupPosition - AbsolutePosition; 2718 linkPart.OffsetPosition = linkPart.GroupPosition - AbsolutePosition;
2719
1995 linkPart.ParentID = m_rootPart.LocalId; 2720 linkPart.ParentID = m_rootPart.LocalId;
1996 linkPart.GroupPosition = AbsolutePosition; 2721
1997 Vector3 axPos = linkPart.OffsetPosition; 2722 linkPart.GroupPosition = AbsolutePosition;
1998 2723
2724 Vector3 axPos = linkPart.OffsetPosition;
1999 Quaternion parentRot = m_rootPart.RotationOffset; 2725 Quaternion parentRot = m_rootPart.RotationOffset;
2000 axPos *= Quaternion.Inverse(parentRot); 2726 axPos *= Quaternion.Conjugate(parentRot);
2001
2002 linkPart.OffsetPosition = axPos; 2727 linkPart.OffsetPosition = axPos;
2728
2003 Quaternion oldRot = linkPart.RotationOffset; 2729 Quaternion oldRot = linkPart.RotationOffset;
2004 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2730 Quaternion newRot = Quaternion.Conjugate(parentRot) * oldRot;
2005 linkPart.RotationOffset = newRot; 2731 linkPart.RotationOffset = newRot;
2006 2732
2007 linkPart.ParentID = m_rootPart.LocalId; 2733// linkPart.ParentID = m_rootPart.LocalId; done above
2008 2734
2009 if (m_rootPart.LinkNum == 0) 2735 if (m_rootPart.LinkNum == 0)
2010 m_rootPart.LinkNum = 1; 2736 m_rootPart.LinkNum = 1;
@@ -2032,7 +2758,7 @@ namespace OpenSim.Region.Framework.Scenes
2032 linkPart.CreateSelected = true; 2758 linkPart.CreateSelected = true;
2033 2759
2034 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now 2760 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now
2035 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive); 2761 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive, true);
2036 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 2762 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
2037 { 2763 {
2038 linkPart.PhysActor.link(m_rootPart.PhysActor); 2764 linkPart.PhysActor.link(m_rootPart.PhysActor);
@@ -2040,6 +2766,7 @@ namespace OpenSim.Region.Framework.Scenes
2040 } 2766 }
2041 2767
2042 linkPart.LinkNum = linkNum++; 2768 linkPart.LinkNum = linkNum++;
2769 linkPart.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2043 2770
2044 SceneObjectPart[] ogParts = objectGroup.Parts; 2771 SceneObjectPart[] ogParts = objectGroup.Parts;
2045 Array.Sort(ogParts, delegate(SceneObjectPart a, SceneObjectPart b) 2772 Array.Sort(ogParts, delegate(SceneObjectPart a, SceneObjectPart b)
@@ -2054,7 +2781,7 @@ namespace OpenSim.Region.Framework.Scenes
2054 { 2781 {
2055 LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++); 2782 LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++);
2056 // let physics know 2783 // let physics know
2057 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive); 2784 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive, true);
2058 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 2785 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
2059 { 2786 {
2060 part.PhysActor.link(m_rootPart.PhysActor); 2787 part.PhysActor.link(m_rootPart.PhysActor);
@@ -2069,7 +2796,7 @@ namespace OpenSim.Region.Framework.Scenes
2069 objectGroup.IsDeleted = true; 2796 objectGroup.IsDeleted = true;
2070 2797
2071 objectGroup.m_parts.Clear(); 2798 objectGroup.m_parts.Clear();
2072 2799
2073 // Can't do this yet since backup still makes use of the root part without any synchronization 2800 // Can't do this yet since backup still makes use of the root part without any synchronization
2074// objectGroup.m_rootPart = null; 2801// objectGroup.m_rootPart = null;
2075 2802
@@ -2080,6 +2807,9 @@ namespace OpenSim.Region.Framework.Scenes
2080 // unmoved prims! 2807 // unmoved prims!
2081 ResetChildPrimPhysicsPositions(); 2808 ResetChildPrimPhysicsPositions();
2082 2809
2810 if (m_rootPart.PhysActor != null)
2811 m_rootPart.PhysActor.Building = false;
2812
2083 //HasGroupChanged = true; 2813 //HasGroupChanged = true;
2084 //ScheduleGroupForFullUpdate(); 2814 //ScheduleGroupForFullUpdate();
2085 } 2815 }
@@ -2147,7 +2877,10 @@ namespace OpenSim.Region.Framework.Scenes
2147// m_log.DebugFormat( 2877// m_log.DebugFormat(
2148// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", 2878// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
2149// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); 2879// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
2150 2880
2881 if (m_rootPart.PhysActor != null)
2882 m_rootPart.PhysActor.Building = true;
2883
2151 linkPart.ClearUndoState(); 2884 linkPart.ClearUndoState();
2152 2885
2153 Quaternion worldRot = linkPart.GetWorldRotation(); 2886 Quaternion worldRot = linkPart.GetWorldRotation();
@@ -2207,6 +2940,14 @@ namespace OpenSim.Region.Framework.Scenes
2207 2940
2208 // When we delete a group, we currently have to force persist to the database if the object id has changed 2941 // When we delete a group, we currently have to force persist to the database if the object id has changed
2209 // (since delete works by deleting all rows which have a given object id) 2942 // (since delete works by deleting all rows which have a given object id)
2943
2944 // this is as it seems to be in sl now
2945 if(linkPart.PhysicsShapeType == (byte)PhysShapeType.none)
2946 linkPart.PhysicsShapeType = linkPart.DefaultPhysicsShapeType(); // root prims can't have type none for now
2947
2948 if (m_rootPart.PhysActor != null)
2949 m_rootPart.PhysActor.Building = false;
2950
2210 objectGroup.HasGroupChangedDueToDelink = true; 2951 objectGroup.HasGroupChangedDueToDelink = true;
2211 2952
2212 return objectGroup; 2953 return objectGroup;
@@ -2218,6 +2959,7 @@ namespace OpenSim.Region.Framework.Scenes
2218 /// <param name="objectGroup"></param> 2959 /// <param name="objectGroup"></param>
2219 public virtual void DetachFromBackup() 2960 public virtual void DetachFromBackup()
2220 { 2961 {
2962 m_scene.SceneGraph.FireDetachFromBackup(this);
2221 if (m_isBackedUp && Scene != null) 2963 if (m_isBackedUp && Scene != null)
2222 m_scene.EventManager.OnBackup -= ProcessBackup; 2964 m_scene.EventManager.OnBackup -= ProcessBackup;
2223 2965
@@ -2236,7 +2978,8 @@ namespace OpenSim.Region.Framework.Scenes
2236 2978
2237 axPos *= parentRot; 2979 axPos *= parentRot;
2238 part.OffsetPosition = axPos; 2980 part.OffsetPosition = axPos;
2239 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 2981 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
2982 part.GroupPosition = newPos;
2240 part.OffsetPosition = Vector3.Zero; 2983 part.OffsetPosition = Vector3.Zero;
2241 part.RotationOffset = worldRot; 2984 part.RotationOffset = worldRot;
2242 2985
@@ -2247,20 +2990,20 @@ namespace OpenSim.Region.Framework.Scenes
2247 2990
2248 part.LinkNum = linkNum; 2991 part.LinkNum = linkNum;
2249 2992
2250 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 2993 part.OffsetPosition = newPos - AbsolutePosition;
2251 2994
2252 Quaternion rootRotation = m_rootPart.RotationOffset; 2995 Quaternion rootRotation = m_rootPart.RotationOffset;
2253 2996
2254 Vector3 pos = part.OffsetPosition; 2997 Vector3 pos = part.OffsetPosition;
2255 pos *= Quaternion.Inverse(rootRotation); 2998 pos *= Quaternion.Conjugate(rootRotation);
2256 part.OffsetPosition = pos; 2999 part.OffsetPosition = pos;
2257 3000
2258 parentRot = m_rootPart.RotationOffset; 3001 parentRot = m_rootPart.RotationOffset;
2259 oldRot = part.RotationOffset; 3002 oldRot = part.RotationOffset;
2260 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 3003 Quaternion newRot = Quaternion.Conjugate(parentRot) * worldRot;
2261 part.RotationOffset = newRot; 3004 part.RotationOffset = newRot;
2262 3005
2263 part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect); 3006 part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2264 } 3007 }
2265 3008
2266 /// <summary> 3009 /// <summary>
@@ -2511,8 +3254,22 @@ namespace OpenSim.Region.Framework.Scenes
2511 } 3254 }
2512 } 3255 }
2513 3256
2514 for (int i = 0; i < parts.Length; i++) 3257 if (parts.Length > 1)
2515 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 3258 {
3259 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3260
3261 for (int i = 0; i < parts.Length; i++)
3262 {
3263
3264 if (parts[i].UUID != m_rootPart.UUID)
3265 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3266 }
3267
3268 if (m_rootPart.PhysActor != null)
3269 m_rootPart.PhysActor.Building = false;
3270 }
3271 else
3272 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, false);
2516 } 3273 }
2517 } 3274 }
2518 3275
@@ -2525,6 +3282,17 @@ namespace OpenSim.Region.Framework.Scenes
2525 } 3282 }
2526 } 3283 }
2527 3284
3285
3286
3287 /// <summary>
3288 /// Gets the number of parts
3289 /// </summary>
3290 /// <returns></returns>
3291 public int GetPartCount()
3292 {
3293 return Parts.Count();
3294 }
3295
2528 /// <summary> 3296 /// <summary>
2529 /// Update the texture entry for this part 3297 /// Update the texture entry for this part
2530 /// </summary> 3298 /// </summary>
@@ -2586,11 +3354,6 @@ namespace OpenSim.Region.Framework.Scenes
2586 /// <param name="scale"></param> 3354 /// <param name="scale"></param>
2587 public void GroupResize(Vector3 scale) 3355 public void GroupResize(Vector3 scale)
2588 { 3356 {
2589// m_log.DebugFormat(
2590// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale);
2591
2592 RootPart.StoreUndoState(true);
2593
2594 scale.X = Math.Min(scale.X, Scene.m_maxNonphys); 3357 scale.X = Math.Min(scale.X, Scene.m_maxNonphys);
2595 scale.Y = Math.Min(scale.Y, Scene.m_maxNonphys); 3358 scale.Y = Math.Min(scale.Y, Scene.m_maxNonphys);
2596 scale.Z = Math.Min(scale.Z, Scene.m_maxNonphys); 3359 scale.Z = Math.Min(scale.Z, Scene.m_maxNonphys);
@@ -2617,7 +3380,6 @@ namespace OpenSim.Region.Framework.Scenes
2617 SceneObjectPart obPart = parts[i]; 3380 SceneObjectPart obPart = parts[i];
2618 if (obPart.UUID != m_rootPart.UUID) 3381 if (obPart.UUID != m_rootPart.UUID)
2619 { 3382 {
2620// obPart.IgnoreUndoUpdate = true;
2621 Vector3 oldSize = new Vector3(obPart.Scale); 3383 Vector3 oldSize = new Vector3(obPart.Scale);
2622 3384
2623 float f = 1.0f; 3385 float f = 1.0f;
@@ -2681,8 +3443,6 @@ namespace OpenSim.Region.Framework.Scenes
2681 z *= a; 3443 z *= a;
2682 } 3444 }
2683 } 3445 }
2684
2685// obPart.IgnoreUndoUpdate = false;
2686 } 3446 }
2687 } 3447 }
2688 } 3448 }
@@ -2692,9 +3452,7 @@ namespace OpenSim.Region.Framework.Scenes
2692 prevScale.Y *= y; 3452 prevScale.Y *= y;
2693 prevScale.Z *= z; 3453 prevScale.Z *= z;
2694 3454
2695// RootPart.IgnoreUndoUpdate = true;
2696 RootPart.Resize(prevScale); 3455 RootPart.Resize(prevScale);
2697// RootPart.IgnoreUndoUpdate = false;
2698 3456
2699 parts = m_parts.GetArray(); 3457 parts = m_parts.GetArray();
2700 for (int i = 0; i < parts.Length; i++) 3458 for (int i = 0; i < parts.Length; i++)
@@ -2703,8 +3461,6 @@ namespace OpenSim.Region.Framework.Scenes
2703 3461
2704 if (obPart.UUID != m_rootPart.UUID) 3462 if (obPart.UUID != m_rootPart.UUID)
2705 { 3463 {
2706 obPart.IgnoreUndoUpdate = true;
2707
2708 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3464 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2709 currentpos.X *= x; 3465 currentpos.X *= x;
2710 currentpos.Y *= y; 3466 currentpos.Y *= y;
@@ -2717,16 +3473,12 @@ namespace OpenSim.Region.Framework.Scenes
2717 3473
2718 obPart.Resize(newSize); 3474 obPart.Resize(newSize);
2719 obPart.UpdateOffSet(currentpos); 3475 obPart.UpdateOffSet(currentpos);
2720
2721 obPart.IgnoreUndoUpdate = false;
2722 } 3476 }
2723 3477
2724// obPart.IgnoreUndoUpdate = false; 3478 HasGroupChanged = true;
2725// obPart.StoreUndoState(); 3479 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3480 ScheduleGroupForTerseUpdate();
2726 } 3481 }
2727
2728// m_log.DebugFormat(
2729// "[SCENE OBJECT GROUP]: Finished group resizing {0} {1} to {2}", Name, LocalId, RootPart.Scale);
2730 } 3482 }
2731 3483
2732 #endregion 3484 #endregion
@@ -2739,14 +3491,6 @@ namespace OpenSim.Region.Framework.Scenes
2739 /// <param name="pos"></param> 3491 /// <param name="pos"></param>
2740 public void UpdateGroupPosition(Vector3 pos) 3492 public void UpdateGroupPosition(Vector3 pos)
2741 { 3493 {
2742// m_log.DebugFormat("[SCENE OBJECT GROUP]: Updating group position on {0} {1} to {2}", Name, LocalId, pos);
2743
2744 RootPart.StoreUndoState(true);
2745
2746// SceneObjectPart[] parts = m_parts.GetArray();
2747// for (int i = 0; i < parts.Length; i++)
2748// parts[i].StoreUndoState();
2749
2750 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 3494 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2751 { 3495 {
2752 if (IsAttachment) 3496 if (IsAttachment)
@@ -2779,21 +3523,17 @@ namespace OpenSim.Region.Framework.Scenes
2779 /// </summary> 3523 /// </summary>
2780 /// <param name="pos"></param> 3524 /// <param name="pos"></param>
2781 /// <param name="localID"></param> 3525 /// <param name="localID"></param>
3526 ///
3527
2782 public void UpdateSinglePosition(Vector3 pos, uint localID) 3528 public void UpdateSinglePosition(Vector3 pos, uint localID)
2783 { 3529 {
2784 SceneObjectPart part = GetPart(localID); 3530 SceneObjectPart part = GetPart(localID);
2785 3531
2786// SceneObjectPart[] parts = m_parts.GetArray();
2787// for (int i = 0; i < parts.Length; i++)
2788// parts[i].StoreUndoState();
2789
2790 if (part != null) 3532 if (part != null)
2791 { 3533 {
2792// m_log.DebugFormat( 3534// unlock parts position change
2793// "[SCENE OBJECT GROUP]: Updating single position of {0} {1} to {2}", part.Name, part.LocalId, pos); 3535 if (m_rootPart.PhysActor != null)
2794 3536 m_rootPart.PhysActor.Building = true;
2795 part.StoreUndoState(false);
2796 part.IgnoreUndoUpdate = true;
2797 3537
2798 if (part.UUID == m_rootPart.UUID) 3538 if (part.UUID == m_rootPart.UUID)
2799 { 3539 {
@@ -2804,8 +3544,10 @@ namespace OpenSim.Region.Framework.Scenes
2804 part.UpdateOffSet(pos); 3544 part.UpdateOffSet(pos);
2805 } 3545 }
2806 3546
3547 if (m_rootPart.PhysActor != null)
3548 m_rootPart.PhysActor.Building = false;
3549
2807 HasGroupChanged = true; 3550 HasGroupChanged = true;
2808 part.IgnoreUndoUpdate = false;
2809 } 3551 }
2810 } 3552 }
2811 3553
@@ -2815,13 +3557,7 @@ namespace OpenSim.Region.Framework.Scenes
2815 /// <param name="pos"></param> 3557 /// <param name="pos"></param>
2816 public void UpdateRootPosition(Vector3 pos) 3558 public void UpdateRootPosition(Vector3 pos)
2817 { 3559 {
2818// m_log.DebugFormat( 3560 // needs to be called with phys building true
2819// "[SCENE OBJECT GROUP]: Updating root position of {0} {1} to {2}", Name, LocalId, pos);
2820
2821// SceneObjectPart[] parts = m_parts.GetArray();
2822// for (int i = 0; i < parts.Length; i++)
2823// parts[i].StoreUndoState();
2824
2825 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3561 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
2826 Vector3 oldPos = 3562 Vector3 oldPos =
2827 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X, 3563 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X,
@@ -2844,7 +3580,14 @@ namespace OpenSim.Region.Framework.Scenes
2844 AbsolutePosition = newPos; 3580 AbsolutePosition = newPos;
2845 3581
2846 HasGroupChanged = true; 3582 HasGroupChanged = true;
2847 ScheduleGroupForTerseUpdate(); 3583 if (m_rootPart.Undoing)
3584 {
3585 ScheduleGroupForFullUpdate();
3586 }
3587 else
3588 {
3589 ScheduleGroupForTerseUpdate();
3590 }
2848 } 3591 }
2849 3592
2850 #endregion 3593 #endregion
@@ -2857,24 +3600,16 @@ namespace OpenSim.Region.Framework.Scenes
2857 /// <param name="rot"></param> 3600 /// <param name="rot"></param>
2858 public void UpdateGroupRotationR(Quaternion rot) 3601 public void UpdateGroupRotationR(Quaternion rot)
2859 { 3602 {
2860// m_log.DebugFormat(
2861// "[SCENE OBJECT GROUP]: Updating group rotation R of {0} {1} to {2}", Name, LocalId, rot);
2862
2863// SceneObjectPart[] parts = m_parts.GetArray();
2864// for (int i = 0; i < parts.Length; i++)
2865// parts[i].StoreUndoState();
2866
2867 m_rootPart.StoreUndoState(true);
2868
2869 m_rootPart.UpdateRotation(rot); 3603 m_rootPart.UpdateRotation(rot);
2870 3604
3605/* this is done by rootpart RotationOffset set called by UpdateRotation
2871 PhysicsActor actor = m_rootPart.PhysActor; 3606 PhysicsActor actor = m_rootPart.PhysActor;
2872 if (actor != null) 3607 if (actor != null)
2873 { 3608 {
2874 actor.Orientation = m_rootPart.RotationOffset; 3609 actor.Orientation = m_rootPart.RotationOffset;
2875 m_scene.PhysicsScene.AddPhysicsActorTaint(actor); 3610 m_scene.PhysicsScene.AddPhysicsActorTaint(actor);
2876 } 3611 }
2877 3612*/
2878 HasGroupChanged = true; 3613 HasGroupChanged = true;
2879 ScheduleGroupForTerseUpdate(); 3614 ScheduleGroupForTerseUpdate();
2880 } 3615 }
@@ -2886,16 +3621,6 @@ namespace OpenSim.Region.Framework.Scenes
2886 /// <param name="rot"></param> 3621 /// <param name="rot"></param>
2887 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) 3622 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot)
2888 { 3623 {
2889// m_log.DebugFormat(
2890// "[SCENE OBJECT GROUP]: Updating group rotation PR of {0} {1} to {2}", Name, LocalId, rot);
2891
2892// SceneObjectPart[] parts = m_parts.GetArray();
2893// for (int i = 0; i < parts.Length; i++)
2894// parts[i].StoreUndoState();
2895
2896 RootPart.StoreUndoState(true);
2897 RootPart.IgnoreUndoUpdate = true;
2898
2899 m_rootPart.UpdateRotation(rot); 3624 m_rootPart.UpdateRotation(rot);
2900 3625
2901 PhysicsActor actor = m_rootPart.PhysActor; 3626 PhysicsActor actor = m_rootPart.PhysActor;
@@ -2909,8 +3634,6 @@ namespace OpenSim.Region.Framework.Scenes
2909 3634
2910 HasGroupChanged = true; 3635 HasGroupChanged = true;
2911 ScheduleGroupForTerseUpdate(); 3636 ScheduleGroupForTerseUpdate();
2912
2913 RootPart.IgnoreUndoUpdate = false;
2914 } 3637 }
2915 3638
2916 /// <summary> 3639 /// <summary>
@@ -2923,13 +3646,11 @@ namespace OpenSim.Region.Framework.Scenes
2923 SceneObjectPart part = GetPart(localID); 3646 SceneObjectPart part = GetPart(localID);
2924 3647
2925 SceneObjectPart[] parts = m_parts.GetArray(); 3648 SceneObjectPart[] parts = m_parts.GetArray();
2926 for (int i = 0; i < parts.Length; i++)
2927 parts[i].StoreUndoState();
2928 3649
2929 if (part != null) 3650 if (part != null)
2930 { 3651 {
2931// m_log.DebugFormat( 3652 if (m_rootPart.PhysActor != null)
2932// "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot); 3653 m_rootPart.PhysActor.Building = true;
2933 3654
2934 if (part.UUID == m_rootPart.UUID) 3655 if (part.UUID == m_rootPart.UUID)
2935 { 3656 {
@@ -2939,6 +3660,9 @@ namespace OpenSim.Region.Framework.Scenes
2939 { 3660 {
2940 part.UpdateRotation(rot); 3661 part.UpdateRotation(rot);
2941 } 3662 }
3663
3664 if (m_rootPart.PhysActor != null)
3665 m_rootPart.PhysActor.Building = false;
2942 } 3666 }
2943 } 3667 }
2944 3668
@@ -2952,12 +3676,8 @@ namespace OpenSim.Region.Framework.Scenes
2952 SceneObjectPart part = GetPart(localID); 3676 SceneObjectPart part = GetPart(localID);
2953 if (part != null) 3677 if (part != null)
2954 { 3678 {
2955// m_log.DebugFormat( 3679 if (m_rootPart.PhysActor != null)
2956// "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}", 3680 m_rootPart.PhysActor.Building = true;
2957// part.Name, part.LocalId, rot);
2958
2959 part.StoreUndoState();
2960 part.IgnoreUndoUpdate = true;
2961 3681
2962 if (part.UUID == m_rootPart.UUID) 3682 if (part.UUID == m_rootPart.UUID)
2963 { 3683 {
@@ -2970,7 +3690,8 @@ namespace OpenSim.Region.Framework.Scenes
2970 part.OffsetPosition = pos; 3690 part.OffsetPosition = pos;
2971 } 3691 }
2972 3692
2973 part.IgnoreUndoUpdate = false; 3693 if (m_rootPart.PhysActor != null)
3694 m_rootPart.PhysActor.Building = false;
2974 } 3695 }
2975 } 3696 }
2976 3697
@@ -2980,15 +3701,12 @@ namespace OpenSim.Region.Framework.Scenes
2980 /// <param name="rot"></param> 3701 /// <param name="rot"></param>
2981 public void UpdateRootRotation(Quaternion rot) 3702 public void UpdateRootRotation(Quaternion rot)
2982 { 3703 {
2983// m_log.DebugFormat( 3704 // needs to be called with phys building true
2984// "[SCENE OBJECT GROUP]: Updating root rotation of {0} {1} to {2}",
2985// Name, LocalId, rot);
2986
2987 Quaternion axRot = rot; 3705 Quaternion axRot = rot;
2988 Quaternion oldParentRot = m_rootPart.RotationOffset; 3706 Quaternion oldParentRot = m_rootPart.RotationOffset;
2989 3707
2990 m_rootPart.StoreUndoState(); 3708 //Don't use UpdateRotation because it schedules an update prematurely
2991 m_rootPart.UpdateRotation(rot); 3709 m_rootPart.RotationOffset = rot;
2992 3710
2993 PhysicsActor pa = m_rootPart.PhysActor; 3711 PhysicsActor pa = m_rootPart.PhysActor;
2994 3712
@@ -3004,35 +3722,144 @@ namespace OpenSim.Region.Framework.Scenes
3004 SceneObjectPart prim = parts[i]; 3722 SceneObjectPart prim = parts[i];
3005 if (prim.UUID != m_rootPart.UUID) 3723 if (prim.UUID != m_rootPart.UUID)
3006 { 3724 {
3007 prim.IgnoreUndoUpdate = true; 3725 Quaternion NewRot = oldParentRot * prim.RotationOffset;
3726 NewRot = Quaternion.Inverse(axRot) * NewRot;
3727 prim.RotationOffset = NewRot;
3728
3008 Vector3 axPos = prim.OffsetPosition; 3729 Vector3 axPos = prim.OffsetPosition;
3730
3009 axPos *= oldParentRot; 3731 axPos *= oldParentRot;
3010 axPos *= Quaternion.Inverse(axRot); 3732 axPos *= Quaternion.Inverse(axRot);
3011 prim.OffsetPosition = axPos; 3733 prim.OffsetPosition = axPos;
3012 Quaternion primsRot = prim.RotationOffset; 3734 }
3013 Quaternion newRot = oldParentRot * primsRot; 3735 }
3014 newRot = Quaternion.Inverse(axRot) * newRot;
3015 prim.RotationOffset = newRot;
3016 prim.ScheduleTerseUpdate();
3017 prim.IgnoreUndoUpdate = false;
3018 }
3019 }
3020
3021// for (int i = 0; i < parts.Length; i++)
3022// {
3023// SceneObjectPart childpart = parts[i];
3024// if (childpart != m_rootPart)
3025// {
3026//// childpart.IgnoreUndoUpdate = false;
3027//// childpart.StoreUndoState();
3028// }
3029// }
3030 3736
3031 m_rootPart.ScheduleTerseUpdate(); 3737 HasGroupChanged = true;
3738 ScheduleGroupForFullUpdate();
3739 }
3032 3740
3033// m_log.DebugFormat( 3741 private enum updatetype :int
3034// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 3742 {
3035// Name, LocalId, rot); 3743 none = 0,
3744 partterse = 1,
3745 partfull = 2,
3746 groupterse = 3,
3747 groupfull = 4
3748 }
3749
3750 public void doChangeObject(SceneObjectPart part, ObjectChangeData data)
3751 {
3752 // TODO this still as excessive *.Schedule*Update()s
3753
3754 if (part != null && part.ParentGroup != null)
3755 {
3756 ObjectChangeType change = data.change;
3757 bool togroup = ((change & ObjectChangeType.Group) != 0);
3758 // bool uniform = ((what & ObjectChangeType.UniformScale) != 0); not in use
3759
3760 SceneObjectGroup group = part.ParentGroup;
3761 PhysicsActor pha = group.RootPart.PhysActor;
3762
3763 updatetype updateType = updatetype.none;
3764
3765 if (togroup)
3766 {
3767 // related to group
3768 if ((change & (ObjectChangeType.Rotation | ObjectChangeType.Position)) != 0)
3769 {
3770 if ((change & ObjectChangeType.Rotation) != 0)
3771 {
3772 group.RootPart.UpdateRotation(data.rotation);
3773 updateType = updatetype.none;
3774 }
3775 if ((change & ObjectChangeType.Position) != 0)
3776 {
3777 UpdateGroupPosition(data.position);
3778 updateType = updatetype.groupterse;
3779 }
3780 else
3781 // ugly rotation update of all parts
3782 {
3783 group.AbsolutePosition = AbsolutePosition;
3784 }
3785
3786 }
3787 if ((change & ObjectChangeType.Scale) != 0)
3788 {
3789 if (pha != null)
3790 pha.Building = true;
3791
3792 group.GroupResize(data.scale);
3793 updateType = updatetype.none;
3794
3795 if (pha != null)
3796 pha.Building = false;
3797 }
3798 }
3799 else
3800 {
3801 // related to single prim in a link-set ( ie group)
3802 if (pha != null)
3803 pha.Building = true;
3804
3805 // root part is special
3806 // parts offset positions or rotations need to change also
3807
3808 if (part == group.RootPart)
3809 {
3810 if ((change & ObjectChangeType.Rotation) != 0)
3811 group.UpdateRootRotation(data.rotation);
3812 if ((change & ObjectChangeType.Position) != 0)
3813 group.UpdateRootPosition(data.position);
3814 if ((change & ObjectChangeType.Scale) != 0)
3815 part.Resize(data.scale);
3816 }
3817 else
3818 {
3819 if ((change & ObjectChangeType.Position) != 0)
3820 {
3821 part.OffsetPosition = data.position;
3822 updateType = updatetype.partterse;
3823 }
3824 if ((change & ObjectChangeType.Rotation) != 0)
3825 {
3826 part.UpdateRotation(data.rotation);
3827 updateType = updatetype.none;
3828 }
3829 if ((change & ObjectChangeType.Scale) != 0)
3830 {
3831 part.Resize(data.scale);
3832 updateType = updatetype.none;
3833 }
3834 }
3835
3836 if (pha != null)
3837 pha.Building = false;
3838 }
3839
3840 if (updateType != updatetype.none)
3841 {
3842 group.HasGroupChanged = true;
3843
3844 switch (updateType)
3845 {
3846 case updatetype.partterse:
3847 part.ScheduleTerseUpdate();
3848 break;
3849 case updatetype.partfull:
3850 part.ScheduleFullUpdate();
3851 break;
3852 case updatetype.groupterse:
3853 group.ScheduleGroupForTerseUpdate();
3854 break;
3855 case updatetype.groupfull:
3856 group.ScheduleGroupForFullUpdate();
3857 break;
3858 default:
3859 break;
3860 }
3861 }
3862 }
3036 } 3863 }
3037 3864
3038 #endregion 3865 #endregion
@@ -3252,11 +4079,50 @@ namespace OpenSim.Region.Framework.Scenes
3252 } 4079 }
3253 } 4080 }
3254 } 4081 }
3255 4082
4083 public Vector3 GetGeometricCenter()
4084 {
4085 // this is not real geometric center but a average of positions relative to root prim acording to
4086 // http://wiki.secondlife.com/wiki/llGetGeometricCenter
4087 // ignoring tortured prims details since sl also seems to ignore
4088 // so no real use in doing it on physics
4089
4090 Vector3 gc = Vector3.Zero;
4091
4092 int nparts = m_parts.Count;
4093 if (nparts <= 1)
4094 return gc;
4095
4096 SceneObjectPart[] parts = m_parts.GetArray();
4097 nparts = parts.Length; // just in case it changed
4098 if (nparts <= 1)
4099 return gc;
4100
4101 Quaternion parentRot = RootPart.RotationOffset;
4102 Vector3 pPos;
4103
4104 // average all parts positions
4105 for (int i = 0; i < nparts; i++)
4106 {
4107 // do it directly
4108 // gc += parts[i].GetWorldPosition();
4109 if (parts[i] != RootPart)
4110 {
4111 pPos = parts[i].OffsetPosition;
4112 gc += pPos;
4113 }
4114
4115 }
4116 gc /= nparts;
4117
4118 // relative to root:
4119// gc -= AbsolutePosition;
4120 return gc;
4121 }
4122
3256 public float GetMass() 4123 public float GetMass()
3257 { 4124 {
3258 float retmass = 0f; 4125 float retmass = 0f;
3259
3260 SceneObjectPart[] parts = m_parts.GetArray(); 4126 SceneObjectPart[] parts = m_parts.GetArray();
3261 for (int i = 0; i < parts.Length; i++) 4127 for (int i = 0; i < parts.Length; i++)
3262 retmass += parts[i].GetMass(); 4128 retmass += parts[i].GetMass();
@@ -3264,6 +4130,39 @@ namespace OpenSim.Region.Framework.Scenes
3264 return retmass; 4130 return retmass;
3265 } 4131 }
3266 4132
4133 // center of mass of full object
4134 public Vector3 GetCenterOfMass()
4135 {
4136 PhysicsActor pa = RootPart.PhysActor;
4137
4138 if(((RootPart.Flags & PrimFlags.Physics) !=0) && pa !=null)
4139 {
4140 // physics knows better about center of mass of physical prims
4141 Vector3 tmp = pa.CenterOfMass;
4142 return tmp;
4143 }
4144
4145 Vector3 Ptot = Vector3.Zero;
4146 float totmass = 0f;
4147 float m;
4148
4149 SceneObjectPart[] parts = m_parts.GetArray();
4150 for (int i = 0; i < parts.Length; i++)
4151 {
4152 m = parts[i].GetMass();
4153 Ptot += parts[i].GetPartCenterOfMass() * m;
4154 totmass += m;
4155 }
4156
4157 if (totmass == 0)
4158 totmass = 0;
4159 else
4160 totmass = 1 / totmass;
4161 Ptot *= totmass;
4162
4163 return Ptot;
4164 }
4165
3267 /// <summary> 4166 /// <summary>
3268 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that 4167 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that
3269 /// the physics engine can use it. 4168 /// the physics engine can use it.
@@ -3417,6 +4316,14 @@ namespace OpenSim.Region.Framework.Scenes
3417 FromItemID = uuid; 4316 FromItemID = uuid;
3418 } 4317 }
3419 4318
4319 public void ResetOwnerChangeFlag()
4320 {
4321 ForEachPart(delegate(SceneObjectPart part)
4322 {
4323 part.ResetOwnerChangeFlag();
4324 });
4325 }
4326
3420 #endregion 4327 #endregion
3421 } 4328 }
3422} 4329}
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
index f911ef8..82bba35 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
@@ -62,7 +62,8 @@ namespace OpenSim.Region.Framework.Scenes
62 TELEPORT = 512, 62 TELEPORT = 512,
63 REGION_RESTART = 1024, 63 REGION_RESTART = 1024,
64 MEDIA = 2048, 64 MEDIA = 2048,
65 ANIMATION = 16384 65 ANIMATION = 16384,
66 POSITION = 32768
66 } 67 }
67 68
68 // I don't really know where to put this except here. 69 // I don't really know where to put this except here.
@@ -121,6 +122,11 @@ namespace OpenSim.Region.Framework.Scenes
121 /// Denote all sides of the prim 122 /// Denote all sides of the prim
122 /// </value> 123 /// </value>
123 public const int ALL_SIDES = -1; 124 public const int ALL_SIDES = -1;
125
126 private const scriptEvents PhyscicsNeededSubsEvents = (
127 scriptEvents.collision | scriptEvents.collision_start | scriptEvents.collision_end |
128 scriptEvents.land_collision | scriptEvents.land_collision_start | scriptEvents.land_collision_end
129 );
124 130
125 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 131 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
126 132
@@ -182,6 +188,18 @@ namespace OpenSim.Region.Framework.Scenes
182 188
183 public uint TimeStampTerse; 189 public uint TimeStampTerse;
184 190
191 // The following two are to hold the attachment data
192 // while an object is inworld
193 [XmlIgnore]
194 public byte AttachPoint = 0;
195
196 [XmlIgnore]
197 public Vector3 AttachOffset = Vector3.Zero;
198
199 [XmlIgnore]
200 public Quaternion AttachRotation = Quaternion.Identity;
201
202 [XmlIgnore]
185 public int STATUS_ROTATE_X; 203 public int STATUS_ROTATE_X;
186 204
187 public int STATUS_ROTATE_Y; 205 public int STATUS_ROTATE_Y;
@@ -208,8 +226,7 @@ namespace OpenSim.Region.Framework.Scenes
208 226
209 public Vector3 RotationAxis = Vector3.One; 227 public Vector3 RotationAxis = Vector3.One;
210 228
211 public bool VolumeDetectActive; // XmlIgnore set to avoid problems with persistance until I come to care for this 229 public bool VolumeDetectActive;
212 // Certainly this must be a persistant setting finally
213 230
214 public bool IsWaitingForFirstSpinUpdatePacket; 231 public bool IsWaitingForFirstSpinUpdatePacket;
215 232
@@ -249,10 +266,10 @@ namespace OpenSim.Region.Framework.Scenes
249 private Quaternion m_sitTargetOrientation = Quaternion.Identity; 266 private Quaternion m_sitTargetOrientation = Quaternion.Identity;
250 private Vector3 m_sitTargetPosition; 267 private Vector3 m_sitTargetPosition;
251 private string m_sitAnimation = "SIT"; 268 private string m_sitAnimation = "SIT";
269 private bool m_occupied; // KF if any av is sitting on this prim
252 private string m_text = String.Empty; 270 private string m_text = String.Empty;
253 private string m_touchName = String.Empty; 271 private string m_touchName = String.Empty;
254 private readonly Stack<UndoState> m_undo = new Stack<UndoState>(5); 272 private UndoRedoState m_UndoRedo = null;
255 private readonly Stack<UndoState> m_redo = new Stack<UndoState>(5);
256 273
257 private bool m_passTouches; 274 private bool m_passTouches;
258 275
@@ -280,7 +297,19 @@ namespace OpenSim.Region.Framework.Scenes
280 protected Vector3 m_lastAcceleration; 297 protected Vector3 m_lastAcceleration;
281 protected Vector3 m_lastAngularVelocity; 298 protected Vector3 m_lastAngularVelocity;
282 protected int m_lastTerseSent; 299 protected int m_lastTerseSent;
283 300 protected float m_buoyancy = 0.0f;
301 protected Vector3 m_force;
302 protected Vector3 m_torque;
303
304 protected byte m_physicsShapeType = (byte)PhysShapeType.prim;
305 protected float m_density = 1000.0f; // in kg/m^3
306 protected float m_gravitymod = 1.0f;
307 protected float m_friction = 0.6f; // wood
308 protected float m_bounce = 0.5f; // wood
309
310
311 protected bool m_isSelected = false;
312
284 /// <summary> 313 /// <summary>
285 /// Stores media texture data 314 /// Stores media texture data
286 /// </summary> 315 /// </summary>
@@ -296,6 +325,17 @@ namespace OpenSim.Region.Framework.Scenes
296 private UUID m_collisionSound; 325 private UUID m_collisionSound;
297 private float m_collisionSoundVolume; 326 private float m_collisionSoundVolume;
298 327
328
329 private SOPVehicle m_vehicle = null;
330
331 private KeyframeMotion m_keyframeMotion = null;
332
333 public KeyframeMotion KeyframeMotion
334 {
335 get; set;
336 }
337
338
299 #endregion Fields 339 #endregion Fields
300 340
301// ~SceneObjectPart() 341// ~SceneObjectPart()
@@ -338,7 +378,7 @@ namespace OpenSim.Region.Framework.Scenes
338 UUID ownerID, PrimitiveBaseShape shape, Vector3 groupPosition, 378 UUID ownerID, PrimitiveBaseShape shape, Vector3 groupPosition,
339 Quaternion rotationOffset, Vector3 offsetPosition) : this() 379 Quaternion rotationOffset, Vector3 offsetPosition) : this()
340 { 380 {
341 m_name = "Primitive"; 381 m_name = "Object";
342 382
343 CreationDate = (int)Utils.DateTimeToUnixTime(Rezzed); 383 CreationDate = (int)Utils.DateTimeToUnixTime(Rezzed);
344 LastOwnerID = CreatorID = OwnerID = ownerID; 384 LastOwnerID = CreatorID = OwnerID = ownerID;
@@ -378,7 +418,7 @@ namespace OpenSim.Region.Framework.Scenes
378 private uint _ownerMask = (uint)PermissionMask.All; 418 private uint _ownerMask = (uint)PermissionMask.All;
379 private uint _groupMask = (uint)PermissionMask.None; 419 private uint _groupMask = (uint)PermissionMask.None;
380 private uint _everyoneMask = (uint)PermissionMask.None; 420 private uint _everyoneMask = (uint)PermissionMask.None;
381 private uint _nextOwnerMask = (uint)PermissionMask.All; 421 private uint _nextOwnerMask = (uint)(PermissionMask.Move | PermissionMask.Modify | PermissionMask.Transfer);
382 private PrimFlags _flags = PrimFlags.None; 422 private PrimFlags _flags = PrimFlags.None;
383 private DateTime m_expires; 423 private DateTime m_expires;
384 private DateTime m_rezzed; 424 private DateTime m_rezzed;
@@ -472,12 +512,16 @@ namespace OpenSim.Region.Framework.Scenes
472 } 512 }
473 513
474 /// <value> 514 /// <value>
475 /// Access should be via Inventory directly - this property temporarily remains for xml serialization purposes 515 /// Get the inventory list
476 /// </value> 516 /// </value>
477 public TaskInventoryDictionary TaskInventory 517 public TaskInventoryDictionary TaskInventory
478 { 518 {
479 get { return m_inventory.Items; } 519 get {
480 set { m_inventory.Items = value; } 520 return m_inventory.Items;
521 }
522 set {
523 m_inventory.Items = value;
524 }
481 } 525 }
482 526
483 /// <summary> 527 /// <summary>
@@ -527,32 +571,28 @@ namespace OpenSim.Region.Framework.Scenes
527 } 571 }
528 } 572 }
529 573
530 public byte Material 574 public bool PassTouches
531 { 575 {
532 get { return (byte) m_material; } 576 get { return m_passTouches; }
533 set 577 set
534 { 578 {
535 m_material = (Material)value; 579 m_passTouches = value;
536
537 PhysicsActor pa = PhysActor;
538 580
539 if (pa != null) 581 if (ParentGroup != null)
540 pa.SetMaterial((int)value); 582 ParentGroup.HasGroupChanged = true;
541 } 583 }
542 } 584 }
543 585
544 public bool PassTouches 586 public bool IsSelected
545 { 587 {
546 get { return m_passTouches; } 588 get { return m_isSelected; }
547 set 589 set
548 { 590 {
549 m_passTouches = value; 591 m_isSelected = value;
550
551 if (ParentGroup != null) 592 if (ParentGroup != null)
552 ParentGroup.HasGroupChanged = true; 593 ParentGroup.PartSelectChanged(value);
553 } 594 }
554 } 595 }
555
556 596
557 597
558 public Dictionary<int, string> CollisionFilter 598 public Dictionary<int, string> CollisionFilter
@@ -623,14 +663,12 @@ namespace OpenSim.Region.Framework.Scenes
623 set { m_LoopSoundSlavePrims = value; } 663 set { m_LoopSoundSlavePrims = value; }
624 } 664 }
625 665
626
627 public Byte[] TextureAnimation 666 public Byte[] TextureAnimation
628 { 667 {
629 get { return m_TextureAnimation; } 668 get { return m_TextureAnimation; }
630 set { m_TextureAnimation = value; } 669 set { m_TextureAnimation = value; }
631 } 670 }
632 671
633
634 public Byte[] ParticleSystem 672 public Byte[] ParticleSystem
635 { 673 {
636 get { return m_particleSystem; } 674 get { return m_particleSystem; }
@@ -667,8 +705,12 @@ namespace OpenSim.Region.Framework.Scenes
667 { 705 {
668 // If this is a linkset, we don't want the physics engine mucking up our group position here. 706 // If this is a linkset, we don't want the physics engine mucking up our group position here.
669 PhysicsActor actor = PhysActor; 707 PhysicsActor actor = PhysActor;
670 if (actor != null && ParentID == 0) 708 if (ParentID == 0)
671 m_groupPosition = actor.Position; 709 {
710 if (actor != null)
711 m_groupPosition = actor.Position;
712 return m_groupPosition;
713 }
672 714
673 if (ParentGroup.IsAttachment) 715 if (ParentGroup.IsAttachment)
674 { 716 {
@@ -677,12 +719,14 @@ namespace OpenSim.Region.Framework.Scenes
677 return sp.AbsolutePosition; 719 return sp.AbsolutePosition;
678 } 720 }
679 721
722 // use root prim's group position. Physics may have updated it
723 if (ParentGroup.RootPart != this)
724 m_groupPosition = ParentGroup.RootPart.GroupPosition;
680 return m_groupPosition; 725 return m_groupPosition;
681 } 726 }
682 set 727 set
683 { 728 {
684 m_groupPosition = value; 729 m_groupPosition = value;
685
686 PhysicsActor actor = PhysActor; 730 PhysicsActor actor = PhysActor;
687 if (actor != null) 731 if (actor != null)
688 { 732 {
@@ -708,16 +752,6 @@ namespace OpenSim.Region.Framework.Scenes
708 m_log.Error("[SCENEOBJECTPART]: GROUP POSITION. " + e.Message); 752 m_log.Error("[SCENEOBJECTPART]: GROUP POSITION. " + e.Message);
709 } 753 }
710 } 754 }
711
712 // TODO if we decide to do sitting in a more SL compatible way (multiple avatars per prim), this has to be fixed, too
713 if (SitTargetAvatar != UUID.Zero)
714 {
715 ScenePresence avatar;
716 if (ParentGroup.Scene.TryGetScenePresence(SitTargetAvatar, out avatar))
717 {
718 avatar.ParentPosition = GetWorldPosition();
719 }
720 }
721 } 755 }
722 } 756 }
723 757
@@ -726,7 +760,7 @@ namespace OpenSim.Region.Framework.Scenes
726 get { return m_offsetPosition; } 760 get { return m_offsetPosition; }
727 set 761 set
728 { 762 {
729// StoreUndoState(); 763 Vector3 oldpos = m_offsetPosition;
730 m_offsetPosition = value; 764 m_offsetPosition = value;
731 765
732 if (ParentGroup != null && !ParentGroup.IsDeleted) 766 if (ParentGroup != null && !ParentGroup.IsDeleted)
@@ -741,7 +775,22 @@ namespace OpenSim.Region.Framework.Scenes
741 if (ParentGroup.Scene != null) 775 if (ParentGroup.Scene != null)
742 ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor); 776 ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor);
743 } 777 }
778
779 if (!m_parentGroup.m_dupeInProgress)
780 {
781 List<ScenePresence> avs = ParentGroup.GetLinkedAvatars();
782 foreach (ScenePresence av in avs)
783 {
784 if (av.ParentID == m_localId)
785 {
786 Vector3 offset = (m_offsetPosition - oldpos);
787 av.AbsolutePosition += offset;
788 av.SendAvatarDataToAllAgents();
789 }
790 }
791 }
744 } 792 }
793 TriggerScriptChangedEvent(Changed.POSITION);
745 } 794 }
746 } 795 }
747 796
@@ -790,7 +839,7 @@ namespace OpenSim.Region.Framework.Scenes
790 839
791 set 840 set
792 { 841 {
793 StoreUndoState(); 842// StoreUndoState();
794 m_rotationOffset = value; 843 m_rotationOffset = value;
795 844
796 PhysicsActor actor = PhysActor; 845 PhysicsActor actor = PhysActor;
@@ -878,7 +927,7 @@ namespace OpenSim.Region.Framework.Scenes
878 get 927 get
879 { 928 {
880 PhysicsActor actor = PhysActor; 929 PhysicsActor actor = PhysActor;
881 if ((actor != null) && actor.IsPhysical) 930 if ((actor != null) && actor.IsPhysical && ParentGroup.RootPart == this)
882 { 931 {
883 m_angularVelocity = actor.RotationalVelocity; 932 m_angularVelocity = actor.RotationalVelocity;
884 } 933 }
@@ -890,7 +939,16 @@ namespace OpenSim.Region.Framework.Scenes
890 /// <summary></summary> 939 /// <summary></summary>
891 public Vector3 Acceleration 940 public Vector3 Acceleration
892 { 941 {
893 get { return m_acceleration; } 942 get
943 {
944 PhysicsActor actor = PhysActor;
945 if (actor != null)
946 {
947 m_acceleration = actor.Acceleration;
948 }
949 return m_acceleration;
950 }
951
894 set { m_acceleration = value; } 952 set { m_acceleration = value; }
895 } 953 }
896 954
@@ -947,7 +1005,10 @@ namespace OpenSim.Region.Framework.Scenes
947 public PrimitiveBaseShape Shape 1005 public PrimitiveBaseShape Shape
948 { 1006 {
949 get { return m_shape; } 1007 get { return m_shape; }
950 set { m_shape = value;} 1008 set
1009 {
1010 m_shape = value;
1011 }
951 } 1012 }
952 1013
953 /// <summary> 1014 /// <summary>
@@ -960,7 +1021,6 @@ namespace OpenSim.Region.Framework.Scenes
960 { 1021 {
961 if (m_shape != null) 1022 if (m_shape != null)
962 { 1023 {
963 StoreUndoState();
964 1024
965 m_shape.Scale = value; 1025 m_shape.Scale = value;
966 1026
@@ -987,6 +1047,7 @@ namespace OpenSim.Region.Framework.Scenes
987 } 1047 }
988 1048
989 public UpdateRequired UpdateFlag { get; set; } 1049 public UpdateRequired UpdateFlag { get; set; }
1050 public bool UpdatePhysRequired { get; set; }
990 1051
991 /// <summary> 1052 /// <summary>
992 /// Used for media on a prim. 1053 /// Used for media on a prim.
@@ -1027,10 +1088,7 @@ namespace OpenSim.Region.Framework.Scenes
1027 { 1088 {
1028 get 1089 get
1029 { 1090 {
1030 if (ParentGroup.IsAttachment) 1091 return GroupPosition + (m_offsetPosition * ParentGroup.RootPart.RotationOffset);
1031 return GroupPosition;
1032
1033 return m_offsetPosition + m_groupPosition;
1034 } 1092 }
1035 } 1093 }
1036 1094
@@ -1208,6 +1266,13 @@ namespace OpenSim.Region.Framework.Scenes
1208 _flags = value; 1266 _flags = value;
1209 } 1267 }
1210 } 1268 }
1269
1270 [XmlIgnore]
1271 public bool IsOccupied // KF If an av is sittingon this prim
1272 {
1273 get { return m_occupied; }
1274 set { m_occupied = value; }
1275 }
1211 1276
1212 /// <summary> 1277 /// <summary>
1213 /// ID of the avatar that is sat on us. If there is no such avatar then is UUID.Zero 1278 /// ID of the avatar that is sat on us. If there is no such avatar then is UUID.Zero
@@ -1267,6 +1332,316 @@ namespace OpenSim.Region.Framework.Scenes
1267 set { m_collisionSoundVolume = value; } 1332 set { m_collisionSoundVolume = value; }
1268 } 1333 }
1269 1334
1335 public float Buoyancy
1336 {
1337 get
1338 {
1339 if (ParentGroup.RootPart == this)
1340 return m_buoyancy;
1341
1342 return ParentGroup.RootPart.Buoyancy;
1343 }
1344 set
1345 {
1346 if (ParentGroup != null && ParentGroup.RootPart != null && ParentGroup.RootPart != this)
1347 {
1348 ParentGroup.RootPart.Buoyancy = value;
1349 return;
1350 }
1351 m_buoyancy = value;
1352 if (PhysActor != null)
1353 PhysActor.Buoyancy = value;
1354 }
1355 }
1356
1357 public Vector3 Force
1358 {
1359 get
1360 {
1361 if (ParentGroup.RootPart == this)
1362 return m_force;
1363
1364 return ParentGroup.RootPart.Force;
1365 }
1366
1367 set
1368 {
1369 if (ParentGroup != null && ParentGroup.RootPart != null && ParentGroup.RootPart != this)
1370 {
1371 ParentGroup.RootPart.Force = value;
1372 return;
1373 }
1374 m_force = value;
1375 if (PhysActor != null)
1376 PhysActor.Force = value;
1377 }
1378 }
1379
1380 public Vector3 Torque
1381 {
1382 get
1383 {
1384 if (ParentGroup.RootPart == this)
1385 return m_torque;
1386
1387 return ParentGroup.RootPart.Torque;
1388 }
1389
1390 set
1391 {
1392 if (ParentGroup != null && ParentGroup.RootPart != null && ParentGroup.RootPart != this)
1393 {
1394 ParentGroup.RootPart.Torque = value;
1395 return;
1396 }
1397 m_torque = value;
1398 if (PhysActor != null)
1399 PhysActor.Torque = value;
1400 }
1401 }
1402
1403 public byte Material
1404 {
1405 get { return (byte)m_material; }
1406 set
1407 {
1408 if (value >= 0 && value <= (byte)SOPMaterialData.MaxMaterial)
1409 {
1410 bool update = false;
1411
1412 if (m_material != (Material)value)
1413 {
1414 update = true;
1415 m_material = (Material)value;
1416 }
1417
1418 if (m_friction != SOPMaterialData.friction(m_material))
1419 {
1420 update = true;
1421 m_friction = SOPMaterialData.friction(m_material);
1422 }
1423
1424 if (m_bounce != SOPMaterialData.bounce(m_material))
1425 {
1426 update = true;
1427 m_bounce = SOPMaterialData.bounce(m_material);
1428 }
1429
1430 if (update)
1431 {
1432 if (PhysActor != null)
1433 {
1434 PhysActor.SetMaterial((int)value);
1435 }
1436 if(ParentGroup != null)
1437 ParentGroup.HasGroupChanged = true;
1438 ScheduleFullUpdateIfNone();
1439 UpdatePhysRequired = true;
1440 }
1441 }
1442 }
1443 }
1444
1445 // not a propriety to move to methods place later
1446 private bool HasMesh()
1447 {
1448 if (Shape != null && (Shape.SculptType == (byte)SculptType.Mesh))
1449 return true;
1450 return false;
1451 }
1452
1453 // not a propriety to move to methods place later
1454 public byte DefaultPhysicsShapeType()
1455 {
1456 byte type;
1457
1458 if (Shape != null && (Shape.SculptType == (byte)SculptType.Mesh))
1459 type = (byte)PhysShapeType.convex;
1460 else
1461 type = (byte)PhysShapeType.prim;
1462
1463 return type;
1464 }
1465
1466 [XmlIgnore]
1467 public bool UsesComplexCost
1468 {
1469 get
1470 {
1471 byte pst = PhysicsShapeType;
1472 if(pst == (byte) PhysShapeType.none || pst == (byte) PhysShapeType.convex || HasMesh())
1473 return true;
1474 return false;
1475 }
1476 }
1477
1478 [XmlIgnore]
1479 public float PhysicsCost
1480 {
1481 get
1482 {
1483 if(PhysicsShapeType == (byte)PhysShapeType.none)
1484 return 0;
1485
1486 float cost = 0.1f;
1487 if (PhysActor != null)
1488// cost += PhysActor.Cost;
1489
1490 if ((Flags & PrimFlags.Physics) != 0)
1491 cost *= (1.0f + 0.01333f * Scale.LengthSquared()); // 0.01333 == 0.04/3
1492 return cost;
1493 }
1494 }
1495
1496 [XmlIgnore]
1497 public float StreamingCost
1498 {
1499 get
1500 {
1501
1502
1503 return 0.1f;
1504 }
1505 }
1506
1507 [XmlIgnore]
1508 public float SimulationCost
1509 {
1510 get
1511 {
1512 // ignoring scripts. Don't like considering them for this
1513 if((Flags & PrimFlags.Physics) != 0)
1514 return 1.0f;
1515
1516 return 0.5f;
1517 }
1518 }
1519
1520 public byte PhysicsShapeType
1521 {
1522 get { return m_physicsShapeType; }
1523 set
1524 {
1525 byte oldv = m_physicsShapeType;
1526
1527 if (value >= 0 && value <= (byte)PhysShapeType.convex)
1528 {
1529 if (value == (byte)PhysShapeType.none && ParentGroup != null && ParentGroup.RootPart == this)
1530 m_physicsShapeType = DefaultPhysicsShapeType();
1531 else
1532 m_physicsShapeType = value;
1533 }
1534 else
1535 m_physicsShapeType = DefaultPhysicsShapeType();
1536
1537 if (m_physicsShapeType != oldv && ParentGroup != null)
1538 {
1539 if (m_physicsShapeType == (byte)PhysShapeType.none)
1540 {
1541 if (PhysActor != null)
1542 {
1543 Velocity = new Vector3(0, 0, 0);
1544 Acceleration = new Vector3(0, 0, 0);
1545 if (ParentGroup.RootPart == this)
1546 AngularVelocity = new Vector3(0, 0, 0);
1547 ParentGroup.Scene.RemovePhysicalPrim(1);
1548 RemoveFromPhysics();
1549 }
1550 }
1551 else if (PhysActor == null)
1552 ApplyPhysics((uint)Flags, VolumeDetectActive, false);
1553 else
1554 {
1555 PhysActor.PhysicsShapeType = m_physicsShapeType;
1556 if (Shape.SculptEntry)
1557 CheckSculptAndLoad();
1558 }
1559
1560 if (ParentGroup != null)
1561 ParentGroup.HasGroupChanged = true;
1562 }
1563
1564 if (m_physicsShapeType != value)
1565 {
1566 UpdatePhysRequired = true;
1567 }
1568 }
1569 }
1570
1571 public float Density // in kg/m^3
1572 {
1573 get { return m_density; }
1574 set
1575 {
1576 if (value >=1 && value <= 22587.0)
1577 {
1578 m_density = value;
1579 UpdatePhysRequired = true;
1580 }
1581
1582 ScheduleFullUpdateIfNone();
1583
1584 if (ParentGroup != null)
1585 ParentGroup.HasGroupChanged = true;
1586 }
1587 }
1588
1589 public float GravityModifier
1590 {
1591 get { return m_gravitymod; }
1592 set
1593 {
1594 if( value >= -1 && value <=28.0f)
1595 {
1596 m_gravitymod = value;
1597 UpdatePhysRequired = true;
1598 }
1599
1600 ScheduleFullUpdateIfNone();
1601
1602 if (ParentGroup != null)
1603 ParentGroup.HasGroupChanged = true;
1604
1605 }
1606 }
1607
1608 public float Friction
1609 {
1610 get { return m_friction; }
1611 set
1612 {
1613 if (value >= 0 && value <= 255.0f)
1614 {
1615 m_friction = value;
1616 UpdatePhysRequired = true;
1617 }
1618
1619 ScheduleFullUpdateIfNone();
1620
1621 if (ParentGroup != null)
1622 ParentGroup.HasGroupChanged = true;
1623 }
1624 }
1625
1626 public float Bounciness
1627 {
1628 get { return m_bounce; }
1629 set
1630 {
1631 if (value >= 0 && value <= 1.0f)
1632 {
1633 m_bounce = value;
1634 UpdatePhysRequired = true;
1635 }
1636
1637 ScheduleFullUpdateIfNone();
1638
1639 if (ParentGroup != null)
1640 ParentGroup.HasGroupChanged = true;
1641 }
1642 }
1643
1644
1270 #endregion Public Properties with only Get 1645 #endregion Public Properties with only Get
1271 1646
1272 private uint ApplyMask(uint val, bool set, uint mask) 1647 private uint ApplyMask(uint val, bool set, uint mask)
@@ -1432,7 +1807,7 @@ namespace OpenSim.Region.Framework.Scenes
1432 impulse = newimpulse; 1807 impulse = newimpulse;
1433 } 1808 }
1434 1809
1435 ParentGroup.applyAngularImpulse(impulse); 1810 ParentGroup.ApplyAngularImpulse(impulse);
1436 } 1811 }
1437 1812
1438 /// <summary> 1813 /// <summary>
@@ -1442,20 +1817,24 @@ namespace OpenSim.Region.Framework.Scenes
1442 /// </summary> 1817 /// </summary>
1443 /// <param name="impulsei">Vector force</param> 1818 /// <param name="impulsei">Vector force</param>
1444 /// <param name="localGlobalTF">true for the local frame, false for the global frame</param> 1819 /// <param name="localGlobalTF">true for the local frame, false for the global frame</param>
1445 public void SetAngularImpulse(Vector3 impulsei, bool localGlobalTF) 1820
1821 // this is actualy Set Torque.. keeping naming so not to edit lslapi also
1822 public void SetAngularImpulse(Vector3 torquei, bool localGlobalTF)
1446 { 1823 {
1447 Vector3 impulse = impulsei; 1824 Vector3 torque = torquei;
1448 1825
1449 if (localGlobalTF) 1826 if (localGlobalTF)
1450 { 1827 {
1828/*
1451 Quaternion grot = GetWorldRotation(); 1829 Quaternion grot = GetWorldRotation();
1452 Quaternion AXgrot = grot; 1830 Quaternion AXgrot = grot;
1453 Vector3 AXimpulsei = impulsei; 1831 Vector3 AXimpulsei = impulsei;
1454 Vector3 newimpulse = AXimpulsei * AXgrot; 1832 Vector3 newimpulse = AXimpulsei * AXgrot;
1455 impulse = newimpulse; 1833 */
1834 torque *= GetWorldRotation();
1456 } 1835 }
1457 1836
1458 ParentGroup.setAngularImpulse(impulse); 1837 Torque = torque;
1459 } 1838 }
1460 1839
1461 /// <summary> 1840 /// <summary>
@@ -1463,17 +1842,23 @@ namespace OpenSim.Region.Framework.Scenes
1463 /// </summary> 1842 /// </summary>
1464 /// <param name="rootObjectFlags"></param> 1843 /// <param name="rootObjectFlags"></param>
1465 /// <param name="VolumeDetectActive"></param> 1844 /// <param name="VolumeDetectActive"></param>
1466 public void ApplyPhysics(uint rootObjectFlags, bool VolumeDetectActive) 1845 /// <param name="building"></param>
1846
1847 public void ApplyPhysics(uint _ObjectFlags, bool _VolumeDetectActive, bool building)
1467 { 1848 {
1849 VolumeDetectActive = _VolumeDetectActive;
1850
1468 if (!ParentGroup.Scene.CollidablePrims) 1851 if (!ParentGroup.Scene.CollidablePrims)
1469 return; 1852 return;
1470 1853
1471// m_log.DebugFormat( 1854 if (PhysicsShapeType == (byte)PhysShapeType.none)
1472// "[SCENE OBJECT PART]: Applying physics to {0} {1}, m_physicalPrim {2}", 1855 return;
1473// Name, LocalId, UUID, m_physicalPrim); 1856
1857 bool isPhysical = (_ObjectFlags & (uint) PrimFlags.Physics) != 0;
1858 bool isPhantom = (_ObjectFlags & (uint)PrimFlags.Phantom) != 0;
1474 1859
1475 bool isPhysical = (rootObjectFlags & (uint) PrimFlags.Physics) != 0; 1860 if (_VolumeDetectActive)
1476 bool isPhantom = (rootObjectFlags & (uint) PrimFlags.Phantom) != 0; 1861 isPhantom = true;
1477 1862
1478 if (IsJoint()) 1863 if (IsJoint())
1479 { 1864 {
@@ -1481,22 +1866,11 @@ namespace OpenSim.Region.Framework.Scenes
1481 } 1866 }
1482 else 1867 else
1483 { 1868 {
1484 // Special case for VolumeDetection: If VolumeDetection is set, the phantom flag is locally ignored 1869 if ((!isPhantom || isPhysical || _VolumeDetectActive) && !ParentGroup.IsAttachment
1485 if (VolumeDetectActive) 1870 && !(Shape.PathCurve == (byte)Extrusion.Flexible))
1486 isPhantom = false; 1871 AddToPhysics(isPhysical, isPhantom, building, isPhysical);
1487 1872 else
1488 // 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 1873 PhysActor = null; // just to be sure
1489 // or flexible
1490 if (!isPhantom && !ParentGroup.IsAttachment && !(Shape.PathCurve == (byte)Extrusion.Flexible))
1491 {
1492 // Added clarification.. since A rigid body is an object that you can kick around, etc.
1493 bool rigidBody = isPhysical && !isPhantom;
1494
1495 PhysicsActor pa = AddToPhysics(rigidBody);
1496
1497 if (pa != null)
1498 pa.SetVolumeDetect(VolumeDetectActive ? 1 : 0);
1499 }
1500 } 1874 }
1501 } 1875 }
1502 1876
@@ -1548,6 +1922,12 @@ namespace OpenSim.Region.Framework.Scenes
1548 dupe.Category = Category; 1922 dupe.Category = Category;
1549 dupe.m_rezzed = m_rezzed; 1923 dupe.m_rezzed = m_rezzed;
1550 1924
1925 dupe.m_UndoRedo = null;
1926 dupe.m_isSelected = false;
1927
1928 dupe.IgnoreUndoUpdate = false;
1929 dupe.Undoing = false;
1930
1551 dupe.m_inventory = new SceneObjectPartInventory(dupe); 1931 dupe.m_inventory = new SceneObjectPartInventory(dupe);
1552 dupe.m_inventory.Items = (TaskInventoryDictionary)m_inventory.Items.Clone(); 1932 dupe.m_inventory.Items = (TaskInventoryDictionary)m_inventory.Items.Clone();
1553 1933
@@ -1563,6 +1943,7 @@ namespace OpenSim.Region.Framework.Scenes
1563 1943
1564 // Move afterwards ResetIDs as it clears the localID 1944 // Move afterwards ResetIDs as it clears the localID
1565 dupe.LocalId = localID; 1945 dupe.LocalId = localID;
1946
1566 // This may be wrong... it might have to be applied in SceneObjectGroup to the object that's being duplicated. 1947 // This may be wrong... it might have to be applied in SceneObjectGroup to the object that's being duplicated.
1567 dupe.LastOwnerID = OwnerID; 1948 dupe.LastOwnerID = OwnerID;
1568 1949
@@ -1582,6 +1963,9 @@ namespace OpenSim.Region.Framework.Scenes
1582 dupe.DoPhysicsPropertyUpdate(UsePhysics, true); 1963 dupe.DoPhysicsPropertyUpdate(UsePhysics, true);
1583 } 1964 }
1584 1965
1966 if (dupe.PhysActor != null)
1967 dupe.PhysActor.LocalID = localID;
1968
1585 ParentGroup.Scene.EventManager.TriggerOnSceneObjectPartCopy(dupe, this, userExposed); 1969 ParentGroup.Scene.EventManager.TriggerOnSceneObjectPartCopy(dupe, this, userExposed);
1586 1970
1587// m_log.DebugFormat("[SCENE OBJECT PART]: Clone of {0} {1} finished", Name, UUID); 1971// m_log.DebugFormat("[SCENE OBJECT PART]: Clone of {0} {1} finished", Name, UUID);
@@ -1701,6 +2085,7 @@ namespace OpenSim.Region.Framework.Scenes
1701 2085
1702 /// <summary> 2086 /// <summary>
1703 /// Do a physics propery update for this part. 2087 /// Do a physics propery update for this part.
2088 /// now also updates phantom and volume detector
1704 /// </summary> 2089 /// </summary>
1705 /// <param name="UsePhysics"></param> 2090 /// <param name="UsePhysics"></param>
1706 /// <param name="isNew"></param> 2091 /// <param name="isNew"></param>
@@ -1726,61 +2111,69 @@ namespace OpenSim.Region.Framework.Scenes
1726 { 2111 {
1727 if (pa.IsPhysical) // implies UsePhysics==false for this block 2112 if (pa.IsPhysical) // implies UsePhysics==false for this block
1728 { 2113 {
1729 if (!isNew) 2114 if (!isNew) // implies UsePhysics==false for this block
2115 {
1730 ParentGroup.Scene.RemovePhysicalPrim(1); 2116 ParentGroup.Scene.RemovePhysicalPrim(1);
1731 2117
1732 pa.OnRequestTerseUpdate -= PhysicsRequestingTerseUpdate; 2118 Velocity = new Vector3(0, 0, 0);
1733 pa.OnOutOfBounds -= PhysicsOutOfBounds; 2119 Acceleration = new Vector3(0, 0, 0);
1734 pa.delink(); 2120 if (ParentGroup.RootPart == this)
2121 AngularVelocity = new Vector3(0, 0, 0);
1735 2122
1736 if (ParentGroup.Scene.PhysicsScene.SupportsNINJAJoints && (!isNew)) 2123 if (pa.Phantom && !VolumeDetectActive)
1737 { 2124 {
1738 // destroy all joints connected to this now deactivated body 2125 RemoveFromPhysics();
1739 ParentGroup.Scene.PhysicsScene.RemoveAllJointsConnectedToActorThreadLocked(pa); 2126 return;
1740 } 2127 }
1741 2128
1742 // stop client-side interpolation of all joint proxy objects that have just been deleted 2129 pa.IsPhysical = UsePhysics;
1743 // this is done because RemoveAllJointsConnectedToActor invokes the OnJointDeactivated callback, 2130 pa.OnRequestTerseUpdate -= PhysicsRequestingTerseUpdate;
1744 // which stops client-side interpolation of deactivated joint proxy objects. 2131 pa.OnOutOfBounds -= PhysicsOutOfBounds;
2132 pa.delink();
2133 if (ParentGroup.Scene.PhysicsScene.SupportsNINJAJoints)
2134 {
2135 // destroy all joints connected to this now deactivated body
2136 ParentGroup.Scene.PhysicsScene.RemoveAllJointsConnectedToActorThreadLocked(pa);
2137 }
2138 }
1745 } 2139 }
1746 2140
1747 if (!UsePhysics && !isNew) 2141 if (pa.IsPhysical != UsePhysics)
1748 { 2142 pa.IsPhysical = UsePhysics;
1749 // reset velocity to 0 on physics switch-off. Without that, the client thinks the
1750 // prim still has velocity and continues to interpolate its position along the old
1751 // velocity-vector.
1752 Velocity = new Vector3(0, 0, 0);
1753 Acceleration = new Vector3(0, 0, 0);
1754 AngularVelocity = new Vector3(0, 0, 0);
1755 //RotationalVelocity = new Vector3(0, 0, 0);
1756 }
1757 2143
1758 pa.IsPhysical = UsePhysics; 2144 if (UsePhysics)
2145 {
2146 if (ParentGroup.RootPart.KeyframeMotion != null)
2147 ParentGroup.RootPart.KeyframeMotion.Stop();
2148 ParentGroup.RootPart.KeyframeMotion = null;
2149 ParentGroup.Scene.AddPhysicalPrim(1);
1759 2150
1760 // If we're not what we're supposed to be in the physics scene, recreate ourselves. 2151 PhysActor.OnRequestTerseUpdate += PhysicsRequestingTerseUpdate;
1761 //m_parentGroup.Scene.PhysicsScene.RemovePrim(PhysActor); 2152 PhysActor.OnOutOfBounds += PhysicsOutOfBounds;
1762 /// that's not wholesome. Had to make Scene public
1763 //PhysActor = null;
1764 2153
1765 if ((Flags & PrimFlags.Phantom) == 0) 2154 if (ParentID != 0 && ParentID != LocalId)
1766 {
1767 if (UsePhysics)
1768 { 2155 {
1769 ParentGroup.Scene.AddPhysicalPrim(1); 2156 PhysicsActor parentPa = ParentGroup.RootPart.PhysActor;
1770 2157
1771 pa.OnRequestTerseUpdate += PhysicsRequestingTerseUpdate; 2158 if (parentPa != null)
1772 pa.OnOutOfBounds += PhysicsOutOfBounds;
1773 if (ParentID != 0 && ParentID != LocalId)
1774 { 2159 {
1775 PhysicsActor parentPa = ParentGroup.RootPart.PhysActor; 2160 pa.link(parentPa);
1776
1777 if (parentPa != null)
1778 {
1779 pa.link(parentPa);
1780 }
1781 } 2161 }
1782 } 2162 }
1783 } 2163 }
2164 }
2165
2166 bool phan = ((Flags & PrimFlags.Phantom) != 0);
2167 if (pa.Phantom != phan)
2168 pa.Phantom = phan;
2169
2170// some engines dont' have this check still
2171// if (VolumeDetectActive != pa.IsVolumeDtc)
2172 {
2173 if (VolumeDetectActive)
2174 pa.SetVolumeDetect(1);
2175 else
2176 pa.SetVolumeDetect(0);
1784 } 2177 }
1785 2178
1786 // If this part is a sculpt then delay the physics update until we've asynchronously loaded the 2179 // If this part is a sculpt then delay the physics update until we've asynchronously loaded the
@@ -1899,12 +2292,26 @@ namespace OpenSim.Region.Framework.Scenes
1899 2292
1900 public Vector3 GetGeometricCenter() 2293 public Vector3 GetGeometricCenter()
1901 { 2294 {
1902 PhysicsActor pa = PhysActor; 2295 // this is not real geometric center but a average of positions relative to root prim acording to
1903 2296 // http://wiki.secondlife.com/wiki/llGetGeometricCenter
1904 if (pa != null) 2297 // ignoring tortured prims details since sl also seems to ignore
1905 return new Vector3(pa.CenterOfMass.X, pa.CenterOfMass.Y, pa.CenterOfMass.Z); 2298 // so no real use in doing it on physics
1906 else 2299 if (ParentGroup.IsDeleted)
1907 return new Vector3(0, 0, 0); 2300 return new Vector3(0, 0, 0);
2301
2302 return ParentGroup.GetGeometricCenter();
2303
2304 /*
2305 PhysicsActor pa = PhysActor;
2306
2307 if (pa != null)
2308 {
2309 Vector3 vtmp = pa.CenterOfMass;
2310 return vtmp;
2311 }
2312 else
2313 return new Vector3(0, 0, 0);
2314 */
1908 } 2315 }
1909 2316
1910 public float GetMass() 2317 public float GetMass()
@@ -1917,14 +2324,43 @@ namespace OpenSim.Region.Framework.Scenes
1917 return 0; 2324 return 0;
1918 } 2325 }
1919 2326
1920 public Vector3 GetForce() 2327 public Vector3 GetCenterOfMass()
1921 { 2328 {
2329 if (ParentGroup.RootPart == this)
2330 {
2331 if (ParentGroup.IsDeleted)
2332 return AbsolutePosition;
2333 return ParentGroup.GetCenterOfMass();
2334 }
2335
1922 PhysicsActor pa = PhysActor; 2336 PhysicsActor pa = PhysActor;
1923 2337
1924 if (pa != null) 2338 if (pa != null)
1925 return pa.Force; 2339 {
2340 Vector3 tmp = pa.CenterOfMass;
2341 return tmp;
2342 }
1926 else 2343 else
1927 return Vector3.Zero; 2344 return AbsolutePosition;
2345 }
2346
2347 public Vector3 GetPartCenterOfMass()
2348 {
2349 PhysicsActor pa = PhysActor;
2350
2351 if (pa != null)
2352 {
2353 Vector3 tmp = pa.CenterOfMass;
2354 return tmp;
2355 }
2356 else
2357 return AbsolutePosition;
2358 }
2359
2360
2361 public Vector3 GetForce()
2362 {
2363 return Force;
1928 } 2364 }
1929 2365
1930 /// <summary> 2366 /// <summary>
@@ -2560,9 +2996,9 @@ namespace OpenSim.Region.Framework.Scenes
2560 Vector3 newpos = new Vector3(pa.Position.GetBytes(), 0); 2996 Vector3 newpos = new Vector3(pa.Position.GetBytes(), 0);
2561 2997
2562 if (ParentGroup.Scene.TestBorderCross(newpos, Cardinals.N) 2998 if (ParentGroup.Scene.TestBorderCross(newpos, Cardinals.N)
2563 | ParentGroup.Scene.TestBorderCross(newpos, Cardinals.S) 2999 || ParentGroup.Scene.TestBorderCross(newpos, Cardinals.S)
2564 | ParentGroup.Scene.TestBorderCross(newpos, Cardinals.E) 3000 || ParentGroup.Scene.TestBorderCross(newpos, Cardinals.E)
2565 | ParentGroup.Scene.TestBorderCross(newpos, Cardinals.W)) 3001 || ParentGroup.Scene.TestBorderCross(newpos, Cardinals.W))
2566 { 3002 {
2567 ParentGroup.AbsolutePosition = newpos; 3003 ParentGroup.AbsolutePosition = newpos;
2568 return; 3004 return;
@@ -2584,17 +3020,18 @@ namespace OpenSim.Region.Framework.Scenes
2584 //Trys to fetch sound id from prim's inventory. 3020 //Trys to fetch sound id from prim's inventory.
2585 //Prim's inventory doesn't support non script items yet 3021 //Prim's inventory doesn't support non script items yet
2586 3022
2587 lock (TaskInventory) 3023 TaskInventory.LockItemsForRead(true);
3024
3025 foreach (KeyValuePair<UUID, TaskInventoryItem> item in TaskInventory)
2588 { 3026 {
2589 foreach (KeyValuePair<UUID, TaskInventoryItem> item in TaskInventory) 3027 if (item.Value.Name == sound)
2590 { 3028 {
2591 if (item.Value.Name == sound) 3029 soundID = item.Value.ItemID;
2592 { 3030 break;
2593 soundID = item.Value.ItemID;
2594 break;
2595 }
2596 } 3031 }
2597 } 3032 }
3033
3034 TaskInventory.LockItemsForRead(false);
2598 } 3035 }
2599 3036
2600 ParentGroup.Scene.ForEachRootScenePresence(delegate(ScenePresence sp) 3037 ParentGroup.Scene.ForEachRootScenePresence(delegate(ScenePresence sp)
@@ -2717,6 +3154,19 @@ namespace OpenSim.Region.Framework.Scenes
2717 APIDTarget = Quaternion.Identity; 3154 APIDTarget = Quaternion.Identity;
2718 } 3155 }
2719 3156
3157
3158
3159 public void ScheduleFullUpdateIfNone()
3160 {
3161 if (ParentGroup == null)
3162 return;
3163
3164// ??? ParentGroup.HasGroupChanged = true;
3165
3166 if (UpdateFlag != UpdateRequired.FULL)
3167 ScheduleFullUpdate();
3168 }
3169
2720 /// <summary> 3170 /// <summary>
2721 /// Schedules this prim for a full update 3171 /// Schedules this prim for a full update
2722 /// </summary> 3172 /// </summary>
@@ -2918,8 +3368,8 @@ namespace OpenSim.Region.Framework.Scenes
2918 { 3368 {
2919 const float ROTATION_TOLERANCE = 0.01f; 3369 const float ROTATION_TOLERANCE = 0.01f;
2920 const float VELOCITY_TOLERANCE = 0.001f; 3370 const float VELOCITY_TOLERANCE = 0.001f;
2921 const float POSITION_TOLERANCE = 0.05f; 3371 const float POSITION_TOLERANCE = 0.05f; // I don't like this, but I suppose it's necessary
2922 const int TIME_MS_TOLERANCE = 3000; 3372 const int TIME_MS_TOLERANCE = 200; //llSetPos has a 200ms delay. This should NOT be 3 seconds.
2923 3373
2924 switch (UpdateFlag) 3374 switch (UpdateFlag)
2925 { 3375 {
@@ -2981,17 +3431,16 @@ namespace OpenSim.Region.Framework.Scenes
2981 if (!UUID.TryParse(sound, out soundID)) 3431 if (!UUID.TryParse(sound, out soundID))
2982 { 3432 {
2983 // search sound file from inventory 3433 // search sound file from inventory
2984 lock (TaskInventory) 3434 TaskInventory.LockItemsForRead(true);
3435 foreach (KeyValuePair<UUID, TaskInventoryItem> item in TaskInventory)
2985 { 3436 {
2986 foreach (KeyValuePair<UUID, TaskInventoryItem> item in TaskInventory) 3437 if (item.Value.Name == sound && item.Value.Type == (int)AssetType.Sound)
2987 { 3438 {
2988 if (item.Value.Name == sound && item.Value.Type == (int)AssetType.Sound) 3439 soundID = item.Value.ItemID;
2989 { 3440 break;
2990 soundID = item.Value.ItemID;
2991 break;
2992 }
2993 } 3441 }
2994 } 3442 }
3443 TaskInventory.LockItemsForRead(false);
2995 } 3444 }
2996 3445
2997 if (soundID == UUID.Zero) 3446 if (soundID == UUID.Zero)
@@ -3076,10 +3525,13 @@ namespace OpenSim.Region.Framework.Scenes
3076 3525
3077 public void SetBuoyancy(float fvalue) 3526 public void SetBuoyancy(float fvalue)
3078 { 3527 {
3079 PhysicsActor pa = PhysActor; 3528 Buoyancy = fvalue;
3080 3529/*
3081 if (pa != null) 3530 if (PhysActor != null)
3082 pa.Buoyancy = fvalue; 3531 {
3532 PhysActor.Buoyancy = fvalue;
3533 }
3534 */
3083 } 3535 }
3084 3536
3085 public void SetDieAtEdge(bool p) 3537 public void SetDieAtEdge(bool p)
@@ -3095,47 +3547,111 @@ namespace OpenSim.Region.Framework.Scenes
3095 PhysicsActor pa = PhysActor; 3547 PhysicsActor pa = PhysActor;
3096 3548
3097 if (pa != null) 3549 if (pa != null)
3098 pa.FloatOnWater = floatYN == 1; 3550 pa.FloatOnWater = (floatYN == 1);
3099 } 3551 }
3100 3552
3101 public void SetForce(Vector3 force) 3553 public void SetForce(Vector3 force)
3102 { 3554 {
3103 PhysicsActor pa = PhysActor; 3555 Force = force;
3556 }
3104 3557
3105 if (pa != null) 3558 public SOPVehicle sopVehicle
3106 pa.Force = force; 3559 {
3560 get
3561 {
3562 return m_vehicle;
3563 }
3564 set
3565 {
3566 m_vehicle = value;
3567 }
3568 }
3569
3570
3571 public int VehicleType
3572 {
3573 get
3574 {
3575 if (m_vehicle == null)
3576 return (int)Vehicle.TYPE_NONE;
3577 else
3578 return (int)m_vehicle.Type;
3579 }
3580 set
3581 {
3582 SetVehicleType(value);
3583 }
3107 } 3584 }
3108 3585
3109 public void SetVehicleType(int type) 3586 public void SetVehicleType(int type)
3110 { 3587 {
3111 PhysicsActor pa = PhysActor; 3588 m_vehicle = null;
3589
3590 if (type == (int)Vehicle.TYPE_NONE)
3591 {
3592 if (_parentID ==0 && PhysActor != null)
3593 PhysActor.VehicleType = (int)Vehicle.TYPE_NONE;
3594 return;
3595 }
3596 m_vehicle = new SOPVehicle();
3597 m_vehicle.ProcessTypeChange((Vehicle)type);
3598 {
3599 if (_parentID ==0 && PhysActor != null)
3600 PhysActor.VehicleType = type;
3601 return;
3602 }
3603 }
3112 3604
3113 if (pa != null) 3605 public void SetVehicleFlags(int param, bool remove)
3114 pa.VehicleType = type; 3606 {
3607 if (m_vehicle == null)
3608 return;
3609
3610 m_vehicle.ProcessVehicleFlags(param, remove);
3611
3612 if (_parentID ==0 && PhysActor != null)
3613 {
3614 PhysActor.VehicleFlags(param, remove);
3615 }
3115 } 3616 }
3116 3617
3117 public void SetVehicleFloatParam(int param, float value) 3618 public void SetVehicleFloatParam(int param, float value)
3118 { 3619 {
3119 PhysicsActor pa = PhysActor; 3620 if (m_vehicle == null)
3621 return;
3120 3622
3121 if (pa != null) 3623 m_vehicle.ProcessFloatVehicleParam((Vehicle)param, value);
3122 pa.VehicleFloatParam(param, value); 3624
3625 if (_parentID == 0 && PhysActor != null)
3626 {
3627 PhysActor.VehicleFloatParam(param, value);
3628 }
3123 } 3629 }
3124 3630
3125 public void SetVehicleVectorParam(int param, Vector3 value) 3631 public void SetVehicleVectorParam(int param, Vector3 value)
3126 { 3632 {
3127 PhysicsActor pa = PhysActor; 3633 if (m_vehicle == null)
3634 return;
3128 3635
3129 if (pa != null) 3636 m_vehicle.ProcessVectorVehicleParam((Vehicle)param, value);
3130 pa.VehicleVectorParam(param, value); 3637
3638 if (_parentID == 0 && PhysActor != null)
3639 {
3640 PhysActor.VehicleVectorParam(param, value);
3641 }
3131 } 3642 }
3132 3643
3133 public void SetVehicleRotationParam(int param, Quaternion rotation) 3644 public void SetVehicleRotationParam(int param, Quaternion rotation)
3134 { 3645 {
3135 PhysicsActor pa = PhysActor; 3646 if (m_vehicle == null)
3647 return;
3136 3648
3137 if (pa != null) 3649 m_vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation);
3138 pa.VehicleRotationParam(param, rotation); 3650
3651 if (_parentID == 0 && PhysActor != null)
3652 {
3653 PhysActor.VehicleRotationParam(param, rotation);
3654 }
3139 } 3655 }
3140 3656
3141 /// <summary> 3657 /// <summary>
@@ -3319,14 +3835,6 @@ namespace OpenSim.Region.Framework.Scenes
3319 hasProfileCut = hasDimple; // is it the same thing? 3835 hasProfileCut = hasDimple; // is it the same thing?
3320 } 3836 }
3321 3837
3322 public void SetVehicleFlags(int param, bool remove)
3323 {
3324 PhysicsActor pa = PhysActor;
3325
3326 if (pa != null)
3327 pa.VehicleFlags(param, remove);
3328 }
3329
3330 public void SetGroup(UUID groupID, IClientAPI client) 3838 public void SetGroup(UUID groupID, IClientAPI client)
3331 { 3839 {
3332 // Scene.AddNewPrims() calls with client == null so can't use this. 3840 // Scene.AddNewPrims() calls with client == null so can't use this.
@@ -3430,68 +3938,18 @@ namespace OpenSim.Region.Framework.Scenes
3430 //ParentGroup.ScheduleGroupForFullUpdate(); 3938 //ParentGroup.ScheduleGroupForFullUpdate();
3431 } 3939 }
3432 3940
3433 public void StoreUndoState() 3941 public void StoreUndoState(ObjectChangeType change)
3434 { 3942 {
3435 StoreUndoState(false); 3943 if (m_UndoRedo == null)
3436 } 3944 m_UndoRedo = new UndoRedoState(5);
3437 3945
3438 public void StoreUndoState(bool forGroup) 3946 lock (m_UndoRedo)
3439 {
3440 if (!Undoing)
3441 { 3947 {
3442 if (!IgnoreUndoUpdate) 3948 if (!Undoing && !IgnoreUndoUpdate && ParentGroup != null) // just to read better - undo is in progress, or suspended
3443 { 3949 {
3444 if (ParentGroup != null) 3950 m_UndoRedo.StoreUndo(this, change);
3445 {
3446 lock (m_undo)
3447 {
3448 if (m_undo.Count > 0)
3449 {
3450 UndoState last = m_undo.Peek();
3451 if (last != null)
3452 {
3453 // TODO: May need to fix for group comparison
3454 if (last.Compare(this))
3455 {
3456 // m_log.DebugFormat(
3457 // "[SCENE OBJECT PART]: Not storing undo for {0} {1} since current state is same as last undo state, initial stack size {2}",
3458 // Name, LocalId, m_undo.Count);
3459
3460 return;
3461 }
3462 }
3463 }
3464
3465 // m_log.DebugFormat(
3466 // "[SCENE OBJECT PART]: Storing undo state for {0} {1}, forGroup {2}, initial stack size {3}",
3467 // Name, LocalId, forGroup, m_undo.Count);
3468
3469 if (ParentGroup.GetSceneMaxUndo() > 0)
3470 {
3471 UndoState nUndo = new UndoState(this, forGroup);
3472
3473 m_undo.Push(nUndo);
3474
3475 if (m_redo.Count > 0)
3476 m_redo.Clear();
3477
3478 // m_log.DebugFormat(
3479 // "[SCENE OBJECT PART]: Stored undo state for {0} {1}, forGroup {2}, stack size now {3}",
3480 // Name, LocalId, forGroup, m_undo.Count);
3481 }
3482 }
3483 }
3484 } 3951 }
3485// else
3486// {
3487// m_log.DebugFormat("[SCENE OBJECT PART]: Ignoring undo store for {0} {1}", Name, LocalId);
3488// }
3489 } 3952 }
3490// else
3491// {
3492// m_log.DebugFormat(
3493// "[SCENE OBJECT PART]: Ignoring undo store for {0} {1} since already undoing", Name, LocalId);
3494// }
3495 } 3953 }
3496 3954
3497 /// <summary> 3955 /// <summary>
@@ -3501,84 +3959,46 @@ namespace OpenSim.Region.Framework.Scenes
3501 { 3959 {
3502 get 3960 get
3503 { 3961 {
3504 lock (m_undo) 3962 if (m_UndoRedo == null)
3505 return m_undo.Count; 3963 return 0;
3964 return m_UndoRedo.Count;
3506 } 3965 }
3507 } 3966 }
3508 3967
3509 public void Undo() 3968 public void Undo()
3510 { 3969 {
3511 lock (m_undo) 3970 if (m_UndoRedo == null || Undoing || ParentGroup == null)
3512 { 3971 return;
3513// m_log.DebugFormat(
3514// "[SCENE OBJECT PART]: Handling undo request for {0} {1}, stack size {2}",
3515// Name, LocalId, m_undo.Count);
3516
3517 if (m_undo.Count > 0)
3518 {
3519 UndoState goback = m_undo.Pop();
3520
3521 if (goback != null)
3522 {
3523 UndoState nUndo = null;
3524
3525 if (ParentGroup.GetSceneMaxUndo() > 0)
3526 {
3527 nUndo = new UndoState(this, goback.ForGroup);
3528 }
3529
3530 goback.PlaybackState(this);
3531
3532 if (nUndo != null)
3533 m_redo.Push(nUndo);
3534 }
3535 }
3536 3972
3537// m_log.DebugFormat( 3973 lock (m_UndoRedo)
3538// "[SCENE OBJECT PART]: Handled undo request for {0} {1}, stack size now {2}", 3974 {
3539// Name, LocalId, m_undo.Count); 3975 Undoing = true;
3976 m_UndoRedo.Undo(this);
3977 Undoing = false;
3540 } 3978 }
3541 } 3979 }
3542 3980
3543 public void Redo() 3981 public void Redo()
3544 { 3982 {
3545 lock (m_undo) 3983 if (m_UndoRedo == null || Undoing || ParentGroup == null)
3546 { 3984 return;
3547// m_log.DebugFormat(
3548// "[SCENE OBJECT PART]: Handling redo request for {0} {1}, stack size {2}",
3549// Name, LocalId, m_redo.Count);
3550
3551 if (m_redo.Count > 0)
3552 {
3553 UndoState gofwd = m_redo.Pop();
3554
3555 if (gofwd != null)
3556 {
3557 if (ParentGroup.GetSceneMaxUndo() > 0)
3558 {
3559 UndoState nUndo = new UndoState(this, gofwd.ForGroup);
3560
3561 m_undo.Push(nUndo);
3562 }
3563
3564 gofwd.PlayfwdState(this);
3565 }
3566 3985
3567// m_log.DebugFormat( 3986 lock (m_UndoRedo)
3568// "[SCENE OBJECT PART]: Handled redo request for {0} {1}, stack size now {2}", 3987 {
3569// Name, LocalId, m_redo.Count); 3988 Undoing = true;
3570 } 3989 m_UndoRedo.Redo(this);
3990 Undoing = false;
3571 } 3991 }
3572 } 3992 }
3573 3993
3574 public void ClearUndoState() 3994 public void ClearUndoState()
3575 { 3995 {
3576// m_log.DebugFormat("[SCENE OBJECT PART]: Clearing undo and redo stacks in {0} {1}", Name, LocalId); 3996 if (m_UndoRedo == null || Undoing)
3997 return;
3577 3998
3578 lock (m_undo) 3999 lock (m_UndoRedo)
3579 { 4000 {
3580 m_undo.Clear(); 4001 m_UndoRedo.Clear();
3581 m_redo.Clear();
3582 } 4002 }
3583 } 4003 }
3584 4004
@@ -4208,6 +4628,27 @@ namespace OpenSim.Region.Framework.Scenes
4208 } 4628 }
4209 } 4629 }
4210 4630
4631
4632 public void UpdateExtraPhysics(ExtraPhysicsData physdata)
4633 {
4634 if (physdata.PhysShapeType == PhysShapeType.invalid || ParentGroup == null)
4635 return;
4636
4637 if (PhysicsShapeType != (byte)physdata.PhysShapeType)
4638 {
4639 PhysicsShapeType = (byte)physdata.PhysShapeType;
4640
4641 }
4642
4643 if(Density != physdata.Density)
4644 Density = physdata.Density;
4645 if(GravityModifier != physdata.GravitationModifier)
4646 GravityModifier = physdata.GravitationModifier;
4647 if(Friction != physdata.Friction)
4648 Friction = physdata.Friction;
4649 if(Bounciness != physdata.Bounce)
4650 Bounciness = physdata.Bounce;
4651 }
4211 /// <summary> 4652 /// <summary>
4212 /// Update the flags on this prim. This covers properties such as phantom, physics and temporary. 4653 /// Update the flags on this prim. This covers properties such as phantom, physics and temporary.
4213 /// </summary> 4654 /// </summary>
@@ -4215,7 +4656,7 @@ namespace OpenSim.Region.Framework.Scenes
4215 /// <param name="SetTemporary"></param> 4656 /// <param name="SetTemporary"></param>
4216 /// <param name="SetPhantom"></param> 4657 /// <param name="SetPhantom"></param>
4217 /// <param name="SetVD"></param> 4658 /// <param name="SetVD"></param>
4218 public void UpdatePrimFlags(bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVD) 4659 public void UpdatePrimFlags(bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVD, bool building)
4219 { 4660 {
4220 bool wasUsingPhysics = ((Flags & PrimFlags.Physics) != 0); 4661 bool wasUsingPhysics = ((Flags & PrimFlags.Physics) != 0);
4221 bool wasTemporary = ((Flags & PrimFlags.TemporaryOnRez) != 0); 4662 bool wasTemporary = ((Flags & PrimFlags.TemporaryOnRez) != 0);
@@ -4225,219 +4666,205 @@ namespace OpenSim.Region.Framework.Scenes
4225 if ((UsePhysics == wasUsingPhysics) && (wasTemporary == SetTemporary) && (wasPhantom == SetPhantom) && (SetVD == wasVD)) 4666 if ((UsePhysics == wasUsingPhysics) && (wasTemporary == SetTemporary) && (wasPhantom == SetPhantom) && (SetVD == wasVD))
4226 return; 4667 return;
4227 4668
4228 PhysicsActor pa = PhysActor; 4669 VolumeDetectActive = SetVD;
4229
4230 // Special cases for VD. VD can only be called from a script
4231 // and can't be combined with changes to other states. So we can rely
4232 // that...
4233 // ... if VD is changed, all others are not.
4234 // ... if one of the others is changed, VD is not.
4235 if (SetVD) // VD is active, special logic applies
4236 {
4237 // State machine logic for VolumeDetect
4238 // More logic below
4239 bool phanReset = (SetPhantom != wasPhantom) && !SetPhantom;
4240
4241 if (phanReset) // Phantom changes from on to off switch VD off too
4242 {
4243 SetVD = false; // Switch it of for the course of this routine
4244 VolumeDetectActive = false; // and also permanently
4245
4246 if (pa != null)
4247 pa.SetVolumeDetect(0); // Let physics know about it too
4248 }
4249 else
4250 {
4251 // If volumedetect is active we don't want phantom to be applied.
4252 // If this is a new call to VD out of the state "phantom"
4253 // this will also cause the prim to be visible to physics
4254 SetPhantom = false;
4255 }
4256 }
4257 4670
4258 if (UsePhysics && IsJoint()) 4671 // volume detector implies phantom
4259 { 4672 if (VolumeDetectActive)
4260 SetPhantom = true; 4673 SetPhantom = true;
4261 }
4262 4674
4263 if (UsePhysics) 4675 if (UsePhysics)
4264 {
4265 AddFlag(PrimFlags.Physics); 4676 AddFlag(PrimFlags.Physics);
4266 if (!wasUsingPhysics)
4267 {
4268 DoPhysicsPropertyUpdate(UsePhysics, false);
4269
4270 if (!ParentGroup.IsDeleted)
4271 {
4272 if (LocalId == ParentGroup.RootPart.LocalId)
4273 {
4274 ParentGroup.CheckSculptAndLoad();
4275 }
4276 }
4277 }
4278 }
4279 else 4677 else
4280 {
4281 RemFlag(PrimFlags.Physics); 4678 RemFlag(PrimFlags.Physics);
4282 if (wasUsingPhysics)
4283 {
4284 DoPhysicsPropertyUpdate(UsePhysics, false);
4285 }
4286 }
4287 4679
4288 if (SetPhantom 4680 if (SetPhantom)
4289 || ParentGroup.IsAttachment
4290 || (Shape.PathCurve == (byte)Extrusion.Flexible)) // note: this may have been changed above in the case of joints
4291 {
4292 AddFlag(PrimFlags.Phantom); 4681 AddFlag(PrimFlags.Phantom);
4682 else
4683 RemFlag(PrimFlags.Phantom);
4293 4684
4294 if (PhysActor != null) 4685 if (SetTemporary)
4686 AddFlag(PrimFlags.TemporaryOnRez);
4687 else
4688 RemFlag(PrimFlags.TemporaryOnRez);
4689
4690
4691 if (ParentGroup.Scene == null)
4692 return;
4693
4694 PhysicsActor pa = PhysActor;
4695
4696 if (pa != null && building && pa.Building != building)
4697 pa.Building = building;
4698
4699 if ((SetPhantom && !UsePhysics && !SetVD) || ParentGroup.IsAttachment || PhysicsShapeType == (byte)PhysShapeType.none
4700 || (Shape.PathCurve == (byte)Extrusion.Flexible))
4701 {
4702 if (pa != null)
4295 { 4703 {
4704 ParentGroup.Scene.RemovePhysicalPrim(1);
4296 RemoveFromPhysics(); 4705 RemoveFromPhysics();
4297 pa = null;
4298 } 4706 }
4707
4708 Velocity = new Vector3(0, 0, 0);
4709 Acceleration = new Vector3(0, 0, 0);
4710 if (ParentGroup.RootPart == this)
4711 AngularVelocity = new Vector3(0, 0, 0);
4299 } 4712 }
4300 else // Not phantom 4713 else
4301 { 4714 {
4302 RemFlag(PrimFlags.Phantom); 4715 if (ParentGroup.Scene.CollidablePrims)
4303
4304 if (ParentGroup.Scene == null)
4305 return;
4306
4307 if (ParentGroup.Scene.CollidablePrims && pa == null)
4308 { 4716 {
4309 pa = AddToPhysics(UsePhysics); 4717 if (pa == null)
4310
4311 if (pa != null)
4312 { 4718 {
4313 pa.SetMaterial(Material); 4719 AddToPhysics(UsePhysics, SetPhantom, building , false);
4314 DoPhysicsPropertyUpdate(UsePhysics, true); 4720 pa = PhysActor;
4315 4721
4316 if (!ParentGroup.IsDeleted) 4722 if (pa != null)
4317 { 4723 {
4318 if (LocalId == ParentGroup.RootPart.LocalId) 4724 if (
4725// ((AggregateScriptEvents & scriptEvents.collision) != 0) ||
4726// ((AggregateScriptEvents & scriptEvents.collision_end) != 0) ||
4727// ((AggregateScriptEvents & scriptEvents.collision_start) != 0) ||
4728// ((AggregateScriptEvents & scriptEvents.land_collision_start) != 0) ||
4729// ((AggregateScriptEvents & scriptEvents.land_collision) != 0) ||
4730// ((AggregateScriptEvents & scriptEvents.land_collision_end) != 0) ||
4731 ((AggregateScriptEvents & PhyscicsNeededSubsEvents) != 0) || (CollisionSound != UUID.Zero)
4732// (CollisionSound != UUID.Zero)
4733 )
4319 { 4734 {
4320 ParentGroup.CheckSculptAndLoad(); 4735 pa.OnCollisionUpdate += PhysicsCollision;
4736 pa.SubscribeEvents(1000);
4321 } 4737 }
4322 } 4738 }
4323
4324 if (
4325 ((AggregateScriptEvents & scriptEvents.collision) != 0) ||
4326 ((AggregateScriptEvents & scriptEvents.collision_end) != 0) ||
4327 ((AggregateScriptEvents & scriptEvents.collision_start) != 0) ||
4328 ((AggregateScriptEvents & scriptEvents.land_collision_start) != 0) ||
4329 ((AggregateScriptEvents & scriptEvents.land_collision) != 0) ||
4330 ((AggregateScriptEvents & scriptEvents.land_collision_end) != 0) ||
4331 (CollisionSound != UUID.Zero)
4332 )
4333 {
4334 pa.OnCollisionUpdate += PhysicsCollision;
4335 pa.SubscribeEvents(1000);
4336 }
4337 } 4739 }
4338 } 4740 else // it already has a physical representation
4339 else // it already has a physical representation
4340 {
4341 DoPhysicsPropertyUpdate(UsePhysics, false); // Update physical status. If it's phantom this will remove the prim
4342
4343 if (!ParentGroup.IsDeleted)
4344 { 4741 {
4345 if (LocalId == ParentGroup.RootPart.LocalId) 4742 DoPhysicsPropertyUpdate(UsePhysics, false); // Update physical status.
4346 { 4743 /* moved into DoPhysicsPropertyUpdate
4347 ParentGroup.CheckSculptAndLoad(); 4744 if(VolumeDetectActive)
4348 } 4745 pa.SetVolumeDetect(1);
4746 else
4747 pa.SetVolumeDetect(0);
4748 */
4749 if (pa.Building != building)
4750 pa.Building = building;
4349 } 4751 }
4350 } 4752 }
4351 } 4753 }
4352
4353 if (SetVD)
4354 {
4355 // If the above logic worked (this is urgent candidate to unit tests!)
4356 // we now have a physicsactor.
4357 // Defensive programming calls for a check here.
4358 // Better would be throwing an exception that could be catched by a unit test as the internal
4359 // logic should make sure, this Physactor is always here.
4360 if (pa != null)
4361 {
4362 pa.SetVolumeDetect(1);
4363 AddFlag(PrimFlags.Phantom); // We set this flag also if VD is active
4364 VolumeDetectActive = true;
4365 }
4366 }
4367 else
4368 {
4369 // Remove VolumeDetect in any case. Note, it's safe to call SetVolumeDetect as often as you like
4370 // (mumbles, well, at least if you have infinte CPU powers :-))
4371 if (pa != null)
4372 pa.SetVolumeDetect(0);
4373
4374 VolumeDetectActive = false;
4375 }
4376
4377 if (SetTemporary)
4378 {
4379 AddFlag(PrimFlags.TemporaryOnRez);
4380 }
4381 else
4382 {
4383 RemFlag(PrimFlags.TemporaryOnRez);
4384 }
4385 4754
4386 // m_log.Debug("Update: PHY:" + UsePhysics.ToString() + ", T:" + IsTemporary.ToString() + ", PHA:" + IsPhantom.ToString() + " S:" + CastsShadows.ToString()); 4755 // m_log.Debug("Update: PHY:" + UsePhysics.ToString() + ", T:" + IsTemporary.ToString() + ", PHA:" + IsPhantom.ToString() + " S:" + CastsShadows.ToString());
4387 4756
4757 // and last in case we have a new actor and not building
4758
4388 if (ParentGroup != null) 4759 if (ParentGroup != null)
4389 { 4760 {
4390 ParentGroup.HasGroupChanged = true; 4761 ParentGroup.HasGroupChanged = true;
4391 ScheduleFullUpdate(); 4762 ScheduleFullUpdate();
4392 } 4763 }
4393 4764
4394// m_log.DebugFormat("[SCENE OBJECT PART]: Updated PrimFlags on {0} {1} to {2}", Name, LocalId, Flags); 4765// m_log.DebugFormat("[SCENE OBJECT PART]: Updated PrimFlags on {0} {1} to {2}", Name, LocalId, Flags);
4395 } 4766 }
4396 4767
4397 /// <summary> 4768 /// <summary>
4398 /// Adds this part to the physics scene. 4769 /// Adds this part to the physics scene.
4770 /// and sets the PhysActor property
4399 /// </summary> 4771 /// </summary>
4400 /// <remarks>This method also sets the PhysActor property.</remarks> 4772 /// <param name="isPhysical">Add this prim as physical.</param>
4401 /// <param name="rigidBody">Add this prim with a rigid body.</param> 4773 /// <param name="isPhantom">Add this prim as phantom.</param>
4402 /// <returns> 4774 /// <param name="building">tells physics to delay full construction of object</param>
4403 /// The physics actor. null if there was a failure. 4775 /// <param name="applyDynamics">applies velocities, force and torque</param>
4404 /// </returns> 4776 private void AddToPhysics(bool isPhysical, bool isPhantom, bool building, bool applyDynamics)
4405 private PhysicsActor AddToPhysics(bool rigidBody) 4777 {
4406 {
4407 PhysicsActor pa; 4778 PhysicsActor pa;
4408 4779
4780 Vector3 velocity = Velocity;
4781 Vector3 rotationalVelocity = AngularVelocity;;
4782
4409 try 4783 try
4410 { 4784 {
4411 pa = ParentGroup.Scene.PhysicsScene.AddPrimShape( 4785 pa = ParentGroup.Scene.PhysicsScene.AddPrimShape(
4412 string.Format("{0}/{1}", Name, UUID), 4786 string.Format("{0}/{1}", Name, UUID),
4413 Shape, 4787 Shape,
4414 AbsolutePosition, 4788 AbsolutePosition,
4415 Scale, 4789 Scale,
4416 RotationOffset, 4790 GetWorldRotation(),
4417 rigidBody, 4791 isPhysical,
4418 m_localId); 4792 isPhantom,
4793 PhysicsShapeType,
4794 m_localId);
4419 } 4795 }
4420 catch 4796 catch (Exception ex)
4421 { 4797 {
4422 m_log.ErrorFormat("[SCENE]: caught exception meshing object {0}. Object set to phantom.", m_uuid); 4798 m_log.ErrorFormat("[SCENE]: AddToPhysics object {0} failed: {1}", m_uuid, ex.Message);
4423 pa = null; 4799 pa = null;
4424 } 4800 }
4425 4801
4426 // FIXME: Ideally we wouldn't set the property here to reduce situations where threads changing physical
4427 // properties can stop on each other. However, DoPhysicsPropertyUpdate() currently relies on PhysActor
4428 // being set.
4429 PhysActor = pa;
4430
4431 // Basic Physics can also return null as well as an exception catch.
4432 if (pa != null) 4802 if (pa != null)
4433 { 4803 {
4434 pa.SOPName = this.Name; // save object into the PhysActor so ODE internals know the joint/body info 4804 pa.SOPName = this.Name; // save object into the PhysActor so ODE internals know the joint/body info
4435 pa.SetMaterial(Material); 4805 pa.SetMaterial(Material);
4436 DoPhysicsPropertyUpdate(rigidBody, true); 4806
4807 if (VolumeDetectActive) // change if not the default only
4808 pa.SetVolumeDetect(1);
4809
4810 if (m_vehicle != null && LocalId == ParentGroup.RootPart.LocalId)
4811 m_vehicle.SetVehicle(pa);
4812
4813 // we are going to tell rest of code about physics so better have this here
4814 PhysActor = pa;
4815
4816 // DoPhysicsPropertyUpdate(isPhysical, true);
4817 // lets expand it here just with what it really needs to do
4818
4819 if (isPhysical)
4820 {
4821 if (ParentGroup.RootPart.KeyframeMotion != null)
4822 ParentGroup.RootPart.KeyframeMotion.Stop();
4823 ParentGroup.RootPart.KeyframeMotion = null;
4824 ParentGroup.Scene.AddPhysicalPrim(1);
4825
4826 pa.OnRequestTerseUpdate += PhysicsRequestingTerseUpdate;
4827 pa.OnOutOfBounds += PhysicsOutOfBounds;
4828
4829 if (ParentID != 0 && ParentID != LocalId)
4830 {
4831 PhysicsActor parentPa = ParentGroup.RootPart.PhysActor;
4832
4833 if (parentPa != null)
4834 {
4835 pa.link(parentPa);
4836 }
4837 }
4838 }
4839
4840 if (applyDynamics)
4841 // do independent of isphysical so parameters get setted (at least some)
4842 {
4843 Velocity = velocity;
4844 AngularVelocity = rotationalVelocity;
4845// pa.Velocity = velocity;
4846 pa.RotationalVelocity = rotationalVelocity;
4847
4848 // if not vehicle and root part apply force and torque
4849 if ((m_vehicle == null || m_vehicle.Type == Vehicle.TYPE_NONE)
4850 && LocalId == ParentGroup.RootPart.LocalId)
4851 {
4852 pa.Force = Force;
4853 pa.Torque = Torque;
4854 }
4855 }
4856
4857 if (Shape.SculptEntry)
4858 CheckSculptAndLoad();
4859 else
4860 ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(pa);
4861
4862 if (!building)
4863 pa.Building = false;
4437 } 4864 }
4438 4865
4439 return pa; 4866 PhysActor = pa;
4440 } 4867 }
4441 4868
4442 /// <summary> 4869 /// <summary>
4443 /// This removes the part from the physics scene. 4870 /// This removes the part from the physics scene.
@@ -4644,33 +5071,28 @@ namespace OpenSim.Region.Framework.Scenes
4644 } 5071 }
4645 5072
4646 PhysicsActor pa = PhysActor; 5073 PhysicsActor pa = PhysActor;
4647 5074 if (pa != null)
4648 if (
4649 ((AggregateScriptEvents & scriptEvents.collision) != 0) ||
4650 ((AggregateScriptEvents & scriptEvents.collision_end) != 0) ||
4651 ((AggregateScriptEvents & scriptEvents.collision_start) != 0) ||
4652 ((AggregateScriptEvents & scriptEvents.land_collision_start) != 0) ||
4653 ((AggregateScriptEvents & scriptEvents.land_collision) != 0) ||
4654 ((AggregateScriptEvents & scriptEvents.land_collision_end) != 0) ||
4655 (CollisionSound != UUID.Zero)
4656 )
4657 { 5075 {
4658 // subscribe to physics updates. 5076 if (
4659 if (pa != null) 5077// ((AggregateScriptEvents & scriptEvents.collision) != 0) ||
5078// ((AggregateScriptEvents & scriptEvents.collision_end) != 0) ||
5079// ((AggregateScriptEvents & scriptEvents.collision_start) != 0) ||
5080// ((AggregateScriptEvents & scriptEvents.land_collision_start) != 0) ||
5081// ((AggregateScriptEvents & scriptEvents.land_collision) != 0) ||
5082// ((AggregateScriptEvents & scriptEvents.land_collision_end) != 0) ||
5083 ((AggregateScriptEvents & PhyscicsNeededSubsEvents) != 0) || (CollisionSound != UUID.Zero)
5084 )
4660 { 5085 {
5086 // subscribe to physics updates.
4661 pa.OnCollisionUpdate += PhysicsCollision; 5087 pa.OnCollisionUpdate += PhysicsCollision;
4662 pa.SubscribeEvents(1000); 5088 pa.SubscribeEvents(1000);
4663 } 5089 }
4664 } 5090 else
4665 else
4666 {
4667 if (pa != null)
4668 { 5091 {
4669 pa.UnSubscribeEvents(); 5092 pa.UnSubscribeEvents();
4670 pa.OnCollisionUpdate -= PhysicsCollision; 5093 pa.OnCollisionUpdate -= PhysicsCollision;
4671 } 5094 }
4672 } 5095 }
4673
4674 //if ((GetEffectiveObjectFlags() & (uint)PrimFlags.Scripted) != 0) 5096 //if ((GetEffectiveObjectFlags() & (uint)PrimFlags.Scripted) != 0)
4675 //{ 5097 //{
4676 // ParentGroup.Scene.EventManager.OnScriptTimerEvent += handleTimerAccounting; 5098 // ParentGroup.Scene.EventManager.OnScriptTimerEvent += handleTimerAccounting;
@@ -4797,5 +5219,17 @@ namespace OpenSim.Region.Framework.Scenes
4797 Color color = Color; 5219 Color color = Color;
4798 return new Color4(color.R, color.G, color.B, (byte)(0xFF - color.A)); 5220 return new Color4(color.R, color.G, color.B, (byte)(0xFF - color.A));
4799 } 5221 }
5222
5223 public void ResetOwnerChangeFlag()
5224 {
5225 List<UUID> inv = Inventory.GetInventoryList();
5226
5227 foreach (UUID itemID in inv)
5228 {
5229 TaskInventoryItem item = Inventory.GetInventoryItem(itemID);
5230 item.OwnerChanged = false;
5231 Inventory.UpdateInventoryItem(item, false, false);
5232 }
5233 }
4800 } 5234 }
4801} 5235}
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs
index 3734e03..141cf66 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs
@@ -48,6 +48,9 @@ namespace OpenSim.Region.Framework.Scenes
48 private string m_inventoryFileName = String.Empty; 48 private string m_inventoryFileName = String.Empty;
49 private byte[] m_inventoryFileData = new byte[0]; 49 private byte[] m_inventoryFileData = new byte[0];
50 private uint m_inventoryFileNameSerial = 0; 50 private uint m_inventoryFileNameSerial = 0;
51 private bool m_inventoryPrivileged = false;
52
53 private Dictionary<UUID, ArrayList> m_scriptErrors = new Dictionary<UUID, ArrayList>();
51 54
52 /// <value> 55 /// <value>
53 /// The part to which the inventory belongs. 56 /// The part to which the inventory belongs.
@@ -84,11 +87,14 @@ namespace OpenSim.Region.Framework.Scenes
84 /// </value> 87 /// </value>
85 protected internal TaskInventoryDictionary Items 88 protected internal TaskInventoryDictionary Items
86 { 89 {
87 get { return m_items; } 90 get {
91 return m_items;
92 }
88 set 93 set
89 { 94 {
90 m_items = value; 95 m_items = value;
91 m_inventorySerial++; 96 m_inventorySerial++;
97 QueryScriptStates();
92 } 98 }
93 } 99 }
94 100
@@ -123,38 +129,45 @@ namespace OpenSim.Region.Framework.Scenes
123 public void ResetInventoryIDs() 129 public void ResetInventoryIDs()
124 { 130 {
125 if (null == m_part) 131 if (null == m_part)
126 return; 132 m_items.LockItemsForWrite(true);
127 133
128 lock (m_items) 134 if (Items.Count == 0)
129 { 135 {
130 if (0 == m_items.Count) 136 m_items.LockItemsForWrite(false);
131 return; 137 return;
138 }
132 139
133 IList<TaskInventoryItem> items = GetInventoryItems(); 140 IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values);
134 m_items.Clear(); 141 Items.Clear();
135 142
136 foreach (TaskInventoryItem item in items) 143 foreach (TaskInventoryItem item in items)
137 { 144 {
138 item.ResetIDs(m_part.UUID); 145 item.ResetIDs(m_part.UUID);
139 m_items.Add(item.ItemID, item); 146 Items.Add(item.ItemID, item);
140 }
141 } 147 }
148 m_items.LockItemsForWrite(false);
142 } 149 }
143 150
144 public void ResetObjectID() 151 public void ResetObjectID()
145 { 152 {
146 lock (Items) 153 m_items.LockItemsForWrite(true);
154
155 if (Items.Count == 0)
147 { 156 {
148 IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values); 157 m_items.LockItemsForWrite(false);
149 Items.Clear(); 158 return;
150
151 foreach (TaskInventoryItem item in items)
152 {
153 item.ParentPartID = m_part.UUID;
154 item.ParentID = m_part.UUID;
155 Items.Add(item.ItemID, item);
156 }
157 } 159 }
160
161 IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values);
162 Items.Clear();
163
164 foreach (TaskInventoryItem item in items)
165 {
166 item.ParentPartID = m_part.UUID;
167 item.ParentID = m_part.UUID;
168 Items.Add(item.ItemID, item);
169 }
170 m_items.LockItemsForWrite(false);
158 } 171 }
159 172
160 /// <summary> 173 /// <summary>
@@ -163,12 +176,11 @@ namespace OpenSim.Region.Framework.Scenes
163 /// <param name="ownerId"></param> 176 /// <param name="ownerId"></param>
164 public void ChangeInventoryOwner(UUID ownerId) 177 public void ChangeInventoryOwner(UUID ownerId)
165 { 178 {
166 lock (Items) 179 m_items.LockItemsForWrite(true);
180 if (0 == Items.Count)
167 { 181 {
168 if (0 == Items.Count) 182 m_items.LockItemsForWrite(false);
169 { 183 return;
170 return;
171 }
172 } 184 }
173 185
174 HasInventoryChanged = true; 186 HasInventoryChanged = true;
@@ -184,6 +196,7 @@ namespace OpenSim.Region.Framework.Scenes
184 item.PermsGranter = UUID.Zero; 196 item.PermsGranter = UUID.Zero;
185 item.OwnerChanged = true; 197 item.OwnerChanged = true;
186 } 198 }
199 m_items.LockItemsForWrite(false);
187 } 200 }
188 201
189 /// <summary> 202 /// <summary>
@@ -192,12 +205,11 @@ namespace OpenSim.Region.Framework.Scenes
192 /// <param name="groupID"></param> 205 /// <param name="groupID"></param>
193 public void ChangeInventoryGroup(UUID groupID) 206 public void ChangeInventoryGroup(UUID groupID)
194 { 207 {
195 lock (Items) 208 m_items.LockItemsForWrite(true);
209 if (0 == Items.Count)
196 { 210 {
197 if (0 == Items.Count) 211 m_items.LockItemsForWrite(false);
198 { 212 return;
199 return;
200 }
201 } 213 }
202 214
203 // Don't let this set the HasGroupChanged flag for attachments 215 // Don't let this set the HasGroupChanged flag for attachments
@@ -209,12 +221,45 @@ namespace OpenSim.Region.Framework.Scenes
209 m_part.ParentGroup.HasGroupChanged = true; 221 m_part.ParentGroup.HasGroupChanged = true;
210 } 222 }
211 223
212 List<TaskInventoryItem> items = GetInventoryItems(); 224 IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values);
213 foreach (TaskInventoryItem item in items) 225 foreach (TaskInventoryItem item in items)
214 { 226 {
215 if (groupID != item.GroupID) 227 if (groupID != item.GroupID)
228 {
216 item.GroupID = groupID; 229 item.GroupID = groupID;
230 }
231 }
232 m_items.LockItemsForWrite(false);
233 }
234
235 private void QueryScriptStates()
236 {
237 if (m_part == null || m_part.ParentGroup == null)
238 return;
239
240 IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces<IScriptModule>();
241 if (engines == null) // No engine at all
242 return;
243
244 Items.LockItemsForRead(true);
245 foreach (TaskInventoryItem item in Items.Values)
246 {
247 if (item.InvType == (int)InventoryType.LSL)
248 {
249 foreach (IScriptModule e in engines)
250 {
251 bool running;
252
253 if (e.HasScript(item.ItemID, out running))
254 {
255 item.ScriptRunning = running;
256 break;
257 }
258 }
259 }
217 } 260 }
261
262 Items.LockItemsForRead(false);
218 } 263 }
219 264
220 /// <summary> 265 /// <summary>
@@ -257,7 +302,10 @@ namespace OpenSim.Region.Framework.Scenes
257 { 302 {
258 List<TaskInventoryItem> scripts = GetInventoryItems(InventoryType.LSL); 303 List<TaskInventoryItem> scripts = GetInventoryItems(InventoryType.LSL);
259 foreach (TaskInventoryItem item in scripts) 304 foreach (TaskInventoryItem item in scripts)
305 {
260 RemoveScriptInstance(item.ItemID, sceneObjectBeingDeleted); 306 RemoveScriptInstance(item.ItemID, sceneObjectBeingDeleted);
307 m_part.RemoveScriptEvents(item.ItemID);
308 }
261 } 309 }
262 310
263 /// <summary> 311 /// <summary>
@@ -271,7 +319,10 @@ namespace OpenSim.Region.Framework.Scenes
271// item.Name, item.ItemID, m_part.Name, m_part.UUID, m_part.ParentGroup.Scene.RegionInfo.RegionName); 319// item.Name, item.ItemID, m_part.Name, m_part.UUID, m_part.ParentGroup.Scene.RegionInfo.RegionName);
272 320
273 if (!m_part.ParentGroup.Scene.Permissions.CanRunScript(item.ItemID, m_part.UUID, item.OwnerID)) 321 if (!m_part.ParentGroup.Scene.Permissions.CanRunScript(item.ItemID, m_part.UUID, item.OwnerID))
322 {
323 StoreScriptError(item.ItemID, "no permission");
274 return; 324 return;
325 }
275 326
276 m_part.AddFlag(PrimFlags.Scripted); 327 m_part.AddFlag(PrimFlags.Scripted);
277 328
@@ -280,14 +331,13 @@ namespace OpenSim.Region.Framework.Scenes
280 if (stateSource == 2 && // Prim crossing 331 if (stateSource == 2 && // Prim crossing
281 m_part.ParentGroup.Scene.m_trustBinaries) 332 m_part.ParentGroup.Scene.m_trustBinaries)
282 { 333 {
283 lock (m_items) 334 m_items.LockItemsForWrite(true);
284 { 335 m_items[item.ItemID].PermsMask = 0;
285 m_items[item.ItemID].PermsMask = 0; 336 m_items[item.ItemID].PermsGranter = UUID.Zero;
286 m_items[item.ItemID].PermsGranter = UUID.Zero; 337 m_items.LockItemsForWrite(false);
287 }
288
289 m_part.ParentGroup.Scene.EventManager.TriggerRezScript( 338 m_part.ParentGroup.Scene.EventManager.TriggerRezScript(
290 m_part.LocalId, item.ItemID, String.Empty, startParam, postOnRez, engine, stateSource); 339 m_part.LocalId, item.ItemID, String.Empty, startParam, postOnRez, engine, stateSource);
340 StoreScriptErrors(item.ItemID, null);
291 m_part.ParentGroup.AddActiveScriptCount(1); 341 m_part.ParentGroup.AddActiveScriptCount(1);
292 m_part.ScheduleFullUpdate(); 342 m_part.ScheduleFullUpdate();
293 return; 343 return;
@@ -296,6 +346,8 @@ namespace OpenSim.Region.Framework.Scenes
296 AssetBase asset = m_part.ParentGroup.Scene.AssetService.Get(item.AssetID.ToString()); 346 AssetBase asset = m_part.ParentGroup.Scene.AssetService.Get(item.AssetID.ToString());
297 if (null == asset) 347 if (null == asset)
298 { 348 {
349 string msg = String.Format("asset ID {0} could not be found", item.AssetID);
350 StoreScriptError(item.ItemID, msg);
299 m_log.ErrorFormat( 351 m_log.ErrorFormat(
300 "[PRIM INVENTORY]: Couldn't start script {0}, {1} at {2} in {3} since asset ID {4} could not be found", 352 "[PRIM INVENTORY]: Couldn't start script {0}, {1} at {2} in {3} since asset ID {4} could not be found",
301 item.Name, item.ItemID, m_part.AbsolutePosition, 353 item.Name, item.ItemID, m_part.AbsolutePosition,
@@ -306,16 +358,21 @@ namespace OpenSim.Region.Framework.Scenes
306 if (m_part.ParentGroup.m_savedScriptState != null) 358 if (m_part.ParentGroup.m_savedScriptState != null)
307 item.OldItemID = RestoreSavedScriptState(item.LoadedItemID, item.OldItemID, item.ItemID); 359 item.OldItemID = RestoreSavedScriptState(item.LoadedItemID, item.OldItemID, item.ItemID);
308 360
309 lock (m_items) 361 m_items.LockItemsForWrite(true);
310 { 362
311 m_items[item.ItemID].OldItemID = item.OldItemID; 363 m_items[item.ItemID].OldItemID = item.OldItemID;
312 m_items[item.ItemID].PermsMask = 0; 364 m_items[item.ItemID].PermsMask = 0;
313 m_items[item.ItemID].PermsGranter = UUID.Zero; 365 m_items[item.ItemID].PermsGranter = UUID.Zero;
314 }
315 366
367 m_items.LockItemsForWrite(false);
368
316 string script = Utils.BytesToString(asset.Data); 369 string script = Utils.BytesToString(asset.Data);
317 m_part.ParentGroup.Scene.EventManager.TriggerRezScript( 370 m_part.ParentGroup.Scene.EventManager.TriggerRezScript(
318 m_part.LocalId, item.ItemID, script, startParam, postOnRez, engine, stateSource); 371 m_part.LocalId, item.ItemID, script, startParam, postOnRez, engine, stateSource);
372 StoreScriptErrors(item.ItemID, null);
373 if (!item.ScriptRunning)
374 m_part.ParentGroup.Scene.EventManager.TriggerStopScript(
375 m_part.LocalId, item.ItemID);
319 m_part.ParentGroup.AddActiveScriptCount(1); 376 m_part.ParentGroup.AddActiveScriptCount(1);
320 m_part.ScheduleFullUpdate(); 377 m_part.ScheduleFullUpdate();
321 } 378 }
@@ -386,20 +443,146 @@ namespace OpenSim.Region.Framework.Scenes
386 443
387 /// <summary> 444 /// <summary>
388 /// Start a script which is in this prim's inventory. 445 /// Start a script which is in this prim's inventory.
446 /// Some processing may occur in the background, but this routine returns asap.
389 /// </summary> 447 /// </summary>
390 /// <param name="itemId"> 448 /// <param name="itemId">
391 /// A <see cref="UUID"/> 449 /// A <see cref="UUID"/>
392 /// </param> 450 /// </param>
393 public void CreateScriptInstance(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource) 451 public void CreateScriptInstance(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource)
394 { 452 {
395 TaskInventoryItem item = GetInventoryItem(itemId); 453 lock (m_scriptErrors)
396 if (item != null) 454 {
397 CreateScriptInstance(item, startParam, postOnRez, engine, stateSource); 455 // Indicate to CreateScriptInstanceInternal() we don't want it to wait for completion
456 m_scriptErrors.Remove(itemId);
457 }
458 CreateScriptInstanceInternal(itemId, startParam, postOnRez, engine, stateSource);
459 }
460
461 private void CreateScriptInstanceInternal(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource)
462 {
463 m_items.LockItemsForRead(true);
464 if (m_items.ContainsKey(itemId))
465 {
466 if (m_items.ContainsKey(itemId))
467 {
468 m_items.LockItemsForRead(false);
469 CreateScriptInstance(m_items[itemId], startParam, postOnRez, engine, stateSource);
470 }
471 else
472 {
473 m_items.LockItemsForRead(false);
474 string msg = String.Format("couldn't be found for prim {0}, {1} at {2} in {3}", m_part.Name, m_part.UUID,
475 m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName);
476 StoreScriptError(itemId, msg);
477 m_log.ErrorFormat(
478 "[PRIM INVENTORY]: " +
479 "Couldn't start script with ID {0} since it {1}", itemId, msg);
480 }
481 }
398 else 482 else
483 {
484 m_items.LockItemsForRead(false);
485 string msg = String.Format("couldn't be found for prim {0}, {1}", m_part.Name, m_part.UUID);
486 StoreScriptError(itemId, msg);
399 m_log.ErrorFormat( 487 m_log.ErrorFormat(
400 "[PRIM INVENTORY]: Couldn't start script with ID {0} since it couldn't be found for prim {1}, {2} at {3} in {4}", 488 "[PRIM INVENTORY]: Couldn't start script with ID {0} since it couldn't be found for prim {1}, {2} at {3} in {4}",
401 itemId, m_part.Name, m_part.UUID, 489 itemId, m_part.Name, m_part.UUID,
402 m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName); 490 m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName);
491 }
492
493 }
494
495 /// <summary>
496 /// Start a script which is in this prim's inventory and return any compilation error messages.
497 /// </summary>
498 /// <param name="itemId">
499 /// A <see cref="UUID"/>
500 /// </param>
501 public ArrayList CreateScriptInstanceEr(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource)
502 {
503 ArrayList errors;
504
505 // Indicate to CreateScriptInstanceInternal() we want it to
506 // post any compilation/loading error messages
507 lock (m_scriptErrors)
508 {
509 m_scriptErrors[itemId] = null;
510 }
511
512 // Perform compilation/loading
513 CreateScriptInstanceInternal(itemId, startParam, postOnRez, engine, stateSource);
514
515 // Wait for and retrieve any errors
516 lock (m_scriptErrors)
517 {
518 while ((errors = m_scriptErrors[itemId]) == null)
519 {
520 if (!System.Threading.Monitor.Wait(m_scriptErrors, 15000))
521 {
522 m_log.ErrorFormat(
523 "[PRIM INVENTORY]: " +
524 "timedout waiting for script {0} errors", itemId);
525 errors = m_scriptErrors[itemId];
526 if (errors == null)
527 {
528 errors = new ArrayList(1);
529 errors.Add("timedout waiting for errors");
530 }
531 break;
532 }
533 }
534 m_scriptErrors.Remove(itemId);
535 }
536 return errors;
537 }
538
539 // Signal to CreateScriptInstanceEr() that compilation/loading is complete
540 private void StoreScriptErrors(UUID itemId, ArrayList errors)
541 {
542 lock (m_scriptErrors)
543 {
544 // If compilation/loading initiated via CreateScriptInstance(),
545 // it does not want the errors, so just get out
546 if (!m_scriptErrors.ContainsKey(itemId))
547 {
548 return;
549 }
550
551 // Initiated via CreateScriptInstanceEr(), if we know what the
552 // errors are, save them and wake CreateScriptInstanceEr().
553 if (errors != null)
554 {
555 m_scriptErrors[itemId] = errors;
556 System.Threading.Monitor.PulseAll(m_scriptErrors);
557 return;
558 }
559 }
560
561 // Initiated via CreateScriptInstanceEr() but we don't know what
562 // the errors are yet, so retrieve them from the script engine.
563 // This may involve some waiting internal to GetScriptErrors().
564 errors = GetScriptErrors(itemId);
565
566 // Get a default non-null value to indicate success.
567 if (errors == null)
568 {
569 errors = new ArrayList();
570 }
571
572 // Post to CreateScriptInstanceEr() and wake it up
573 lock (m_scriptErrors)
574 {
575 m_scriptErrors[itemId] = errors;
576 System.Threading.Monitor.PulseAll(m_scriptErrors);
577 }
578 }
579
580 // Like StoreScriptErrors(), but just posts a single string message
581 private void StoreScriptError(UUID itemId, string message)
582 {
583 ArrayList errors = new ArrayList(1);
584 errors.Add(message);
585 StoreScriptErrors(itemId, errors);
403 } 586 }
404 587
405 /// <summary> 588 /// <summary>
@@ -412,15 +595,7 @@ namespace OpenSim.Region.Framework.Scenes
412 /// </param> 595 /// </param>
413 public void RemoveScriptInstance(UUID itemId, bool sceneObjectBeingDeleted) 596 public void RemoveScriptInstance(UUID itemId, bool sceneObjectBeingDeleted)
414 { 597 {
415 bool scriptPresent = false; 598 if (m_items.ContainsKey(itemId))
416
417 lock (m_items)
418 {
419 if (m_items.ContainsKey(itemId))
420 scriptPresent = true;
421 }
422
423 if (scriptPresent)
424 { 599 {
425 if (!sceneObjectBeingDeleted) 600 if (!sceneObjectBeingDeleted)
426 m_part.RemoveScriptEvents(itemId); 601 m_part.RemoveScriptEvents(itemId);
@@ -445,14 +620,16 @@ namespace OpenSim.Region.Framework.Scenes
445 /// <returns></returns> 620 /// <returns></returns>
446 private bool InventoryContainsName(string name) 621 private bool InventoryContainsName(string name)
447 { 622 {
448 lock (m_items) 623 m_items.LockItemsForRead(true);
624 foreach (TaskInventoryItem item in m_items.Values)
449 { 625 {
450 foreach (TaskInventoryItem item in m_items.Values) 626 if (item.Name == name)
451 { 627 {
452 if (item.Name == name) 628 m_items.LockItemsForRead(false);
453 return true; 629 return true;
454 } 630 }
455 } 631 }
632 m_items.LockItemsForRead(false);
456 return false; 633 return false;
457 } 634 }
458 635
@@ -494,8 +671,9 @@ namespace OpenSim.Region.Framework.Scenes
494 /// <param name="item"></param> 671 /// <param name="item"></param>
495 public void AddInventoryItemExclusive(TaskInventoryItem item, bool allowedDrop) 672 public void AddInventoryItemExclusive(TaskInventoryItem item, bool allowedDrop)
496 { 673 {
497 List<TaskInventoryItem> il = GetInventoryItems(); 674 m_items.LockItemsForRead(true);
498 675 List<TaskInventoryItem> il = new List<TaskInventoryItem>(m_items.Values);
676 m_items.LockItemsForRead(false);
499 foreach (TaskInventoryItem i in il) 677 foreach (TaskInventoryItem i in il)
500 { 678 {
501 if (i.Name == item.Name) 679 if (i.Name == item.Name)
@@ -533,14 +711,14 @@ namespace OpenSim.Region.Framework.Scenes
533 item.Name = name; 711 item.Name = name;
534 item.GroupID = m_part.GroupID; 712 item.GroupID = m_part.GroupID;
535 713
536 lock (m_items) 714 m_items.LockItemsForWrite(true);
537 m_items.Add(item.ItemID, item); 715 m_items.Add(item.ItemID, item);
538 716 m_items.LockItemsForWrite(false);
539 if (allowedDrop) 717 if (allowedDrop)
540 m_part.TriggerScriptChangedEvent(Changed.ALLOWED_DROP); 718 m_part.TriggerScriptChangedEvent(Changed.ALLOWED_DROP);
541 else 719 else
542 m_part.TriggerScriptChangedEvent(Changed.INVENTORY); 720 m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
543 721
544 m_inventorySerial++; 722 m_inventorySerial++;
545 //m_inventorySerial += 2; 723 //m_inventorySerial += 2;
546 HasInventoryChanged = true; 724 HasInventoryChanged = true;
@@ -556,15 +734,15 @@ namespace OpenSim.Region.Framework.Scenes
556 /// <param name="items"></param> 734 /// <param name="items"></param>
557 public void RestoreInventoryItems(ICollection<TaskInventoryItem> items) 735 public void RestoreInventoryItems(ICollection<TaskInventoryItem> items)
558 { 736 {
559 lock (m_items) 737 m_items.LockItemsForWrite(true);
738 foreach (TaskInventoryItem item in items)
560 { 739 {
561 foreach (TaskInventoryItem item in items) 740 m_items.Add(item.ItemID, item);
562 { 741// m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
563 m_items.Add(item.ItemID, item);
564// m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
565 }
566 m_inventorySerial++;
567 } 742 }
743 m_items.LockItemsForWrite(false);
744
745 m_inventorySerial++;
568 } 746 }
569 747
570 /// <summary> 748 /// <summary>
@@ -575,10 +753,9 @@ namespace OpenSim.Region.Framework.Scenes
575 public TaskInventoryItem GetInventoryItem(UUID itemId) 753 public TaskInventoryItem GetInventoryItem(UUID itemId)
576 { 754 {
577 TaskInventoryItem item; 755 TaskInventoryItem item;
578 756 m_items.LockItemsForRead(true);
579 lock (m_items) 757 m_items.TryGetValue(itemId, out item);
580 m_items.TryGetValue(itemId, out item); 758 m_items.LockItemsForRead(false);
581
582 return item; 759 return item;
583 } 760 }
584 761
@@ -594,15 +771,16 @@ namespace OpenSim.Region.Framework.Scenes
594 { 771 {
595 List<TaskInventoryItem> items = new List<TaskInventoryItem>(); 772 List<TaskInventoryItem> items = new List<TaskInventoryItem>();
596 773
597 lock (m_items) 774 m_items.LockItemsForRead(true);
775
776 foreach (TaskInventoryItem item in m_items.Values)
598 { 777 {
599 foreach (TaskInventoryItem item in m_items.Values) 778 if (item.Name == name)
600 { 779 items.Add(item);
601 if (item.Name == name)
602 items.Add(item);
603 }
604 } 780 }
605 781
782 m_items.LockItemsForRead(false);
783
606 return items; 784 return items;
607 } 785 }
608 786
@@ -621,6 +799,10 @@ namespace OpenSim.Region.Framework.Scenes
621 string xmlData = Utils.BytesToString(rezAsset.Data); 799 string xmlData = Utils.BytesToString(rezAsset.Data);
622 SceneObjectGroup group = SceneObjectSerializer.FromOriginalXmlFormat(xmlData); 800 SceneObjectGroup group = SceneObjectSerializer.FromOriginalXmlFormat(xmlData);
623 801
802 group.RootPart.AttachPoint = group.RootPart.Shape.State;
803 group.RootPart.AttachOffset = group.AbsolutePosition;
804 group.RootPart.AttachRotation = group.GroupRotation;
805
624 group.ResetIDs(); 806 group.ResetIDs();
625 807
626 SceneObjectPart rootPart = group.GetPart(group.UUID); 808 SceneObjectPart rootPart = group.GetPart(group.UUID);
@@ -695,8 +877,9 @@ namespace OpenSim.Region.Framework.Scenes
695 877
696 public bool UpdateInventoryItem(TaskInventoryItem item, bool fireScriptEvents, bool considerChanged) 878 public bool UpdateInventoryItem(TaskInventoryItem item, bool fireScriptEvents, bool considerChanged)
697 { 879 {
698 TaskInventoryItem it = GetInventoryItem(item.ItemID); 880 m_items.LockItemsForWrite(true);
699 if (it != null) 881
882 if (m_items.ContainsKey(item.ItemID))
700 { 883 {
701// m_log.DebugFormat("[PRIM INVENTORY]: Updating item {0} in {1}", item.Name, m_part.Name); 884// m_log.DebugFormat("[PRIM INVENTORY]: Updating item {0} in {1}", item.Name, m_part.Name);
702 885
@@ -709,14 +892,10 @@ namespace OpenSim.Region.Framework.Scenes
709 item.GroupID = m_part.GroupID; 892 item.GroupID = m_part.GroupID;
710 893
711 if (item.AssetID == UUID.Zero) 894 if (item.AssetID == UUID.Zero)
712 item.AssetID = it.AssetID; 895 item.AssetID = m_items[item.ItemID].AssetID;
713 896
714 lock (m_items) 897 m_items[item.ItemID] = item;
715 { 898 m_inventorySerial++;
716 m_items[item.ItemID] = item;
717 m_inventorySerial++;
718 }
719
720 if (fireScriptEvents) 899 if (fireScriptEvents)
721 m_part.TriggerScriptChangedEvent(Changed.INVENTORY); 900 m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
722 901
@@ -725,7 +904,7 @@ namespace OpenSim.Region.Framework.Scenes
725 HasInventoryChanged = true; 904 HasInventoryChanged = true;
726 m_part.ParentGroup.HasGroupChanged = true; 905 m_part.ParentGroup.HasGroupChanged = true;
727 } 906 }
728 907 m_items.LockItemsForWrite(false);
729 return true; 908 return true;
730 } 909 }
731 else 910 else
@@ -736,8 +915,9 @@ namespace OpenSim.Region.Framework.Scenes
736 item.ItemID, m_part.Name, m_part.UUID, 915 item.ItemID, m_part.Name, m_part.UUID,
737 m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName); 916 m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName);
738 } 917 }
739 return false; 918 m_items.LockItemsForWrite(false);
740 919
920 return false;
741 } 921 }
742 922
743 /// <summary> 923 /// <summary>
@@ -748,43 +928,59 @@ namespace OpenSim.Region.Framework.Scenes
748 /// in this prim's inventory.</returns> 928 /// in this prim's inventory.</returns>
749 public int RemoveInventoryItem(UUID itemID) 929 public int RemoveInventoryItem(UUID itemID)
750 { 930 {
751 TaskInventoryItem item = GetInventoryItem(itemID); 931 m_items.LockItemsForRead(true);
752 if (item != null) 932
933 if (m_items.ContainsKey(itemID))
753 { 934 {
754 int type = m_items[itemID].InvType; 935 int type = m_items[itemID].InvType;
936 m_items.LockItemsForRead(false);
755 if (type == 10) // Script 937 if (type == 10) // Script
756 { 938 {
757 m_part.RemoveScriptEvents(itemID);
758 m_part.ParentGroup.Scene.EventManager.TriggerRemoveScript(m_part.LocalId, itemID); 939 m_part.ParentGroup.Scene.EventManager.TriggerRemoveScript(m_part.LocalId, itemID);
759 } 940 }
941 m_items.LockItemsForWrite(true);
760 m_items.Remove(itemID); 942 m_items.Remove(itemID);
943 m_items.LockItemsForWrite(false);
761 m_inventorySerial++; 944 m_inventorySerial++;
762 m_part.TriggerScriptChangedEvent(Changed.INVENTORY); 945 m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
763 946
764 HasInventoryChanged = true; 947 HasInventoryChanged = true;
765 m_part.ParentGroup.HasGroupChanged = true; 948 m_part.ParentGroup.HasGroupChanged = true;
766 949
767 if (!ContainsScripts()) 950 int scriptcount = 0;
951 m_items.LockItemsForRead(true);
952 foreach (TaskInventoryItem item in m_items.Values)
953 {
954 if (item.Type == 10)
955 {
956 scriptcount++;
957 }
958 }
959 m_items.LockItemsForRead(false);
960
961
962 if (scriptcount <= 0)
963 {
768 m_part.RemFlag(PrimFlags.Scripted); 964 m_part.RemFlag(PrimFlags.Scripted);
965 }
769 966
770 m_part.ScheduleFullUpdate(); 967 m_part.ScheduleFullUpdate();
771 968
772 return type; 969 return type;
773
774 } 970 }
775 else 971 else
776 { 972 {
973 m_items.LockItemsForRead(false);
777 m_log.ErrorFormat( 974 m_log.ErrorFormat(
778 "[PRIM INVENTORY]: " + 975 "[PRIM INVENTORY]: " +
779 "Tried to remove item ID {0} from prim {1}, {2} at {3} in {4} but the item does not exist in this inventory", 976 "Tried to remove item ID {0} from prim {1}, {2} but the item does not exist in this inventory",
780 itemID, m_part.Name, m_part.UUID, 977 itemID, m_part.Name, m_part.UUID);
781 m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName);
782 } 978 }
783 979
784 return -1; 980 return -1;
785 } 981 }
786 982
787 private bool CreateInventoryFile() 983 private bool CreateInventoryFileName()
788 { 984 {
789// m_log.DebugFormat( 985// m_log.DebugFormat(
790// "[PRIM INVENTORY]: Creating inventory file for {0} {1} {2}, serial {3}", 986// "[PRIM INVENTORY]: Creating inventory file for {0} {1} {2}, serial {3}",
@@ -793,116 +989,125 @@ namespace OpenSim.Region.Framework.Scenes
793 if (m_inventoryFileName == String.Empty || 989 if (m_inventoryFileName == String.Empty ||
794 m_inventoryFileNameSerial < m_inventorySerial) 990 m_inventoryFileNameSerial < m_inventorySerial)
795 { 991 {
796 // Something changed, we need to create a new file
797 m_inventoryFileName = "inventory_" + UUID.Random().ToString() + ".tmp"; 992 m_inventoryFileName = "inventory_" + UUID.Random().ToString() + ".tmp";
798 m_inventoryFileNameSerial = m_inventorySerial; 993 m_inventoryFileNameSerial = m_inventorySerial;
799 994
800 InventoryStringBuilder invString = new InventoryStringBuilder(m_part.UUID, UUID.Zero); 995 return true;
996 }
997
998 return false;
999 }
1000
1001 /// <summary>
1002 /// Serialize all the metadata for the items in this prim's inventory ready for sending to the client
1003 /// </summary>
1004 /// <param name="xferManager"></param>
1005 public void RequestInventoryFile(IClientAPI client, IXfer xferManager)
1006 {
1007 bool changed = CreateInventoryFileName();
1008
1009 bool includeAssets = false;
1010 if (m_part.ParentGroup.Scene.Permissions.CanEditObjectInventory(m_part.UUID, client.AgentId))
1011 includeAssets = true;
1012
1013 if (m_inventoryPrivileged != includeAssets)
1014 changed = true;
1015
1016 InventoryStringBuilder invString = new InventoryStringBuilder(m_part.UUID, UUID.Zero);
1017
1018 Items.LockItemsForRead(true);
1019
1020 if (m_inventorySerial == 0) // No inventory
1021 {
1022 client.SendTaskInventory(m_part.UUID, 0, new byte[0]);
1023 Items.LockItemsForRead(false);
1024 return;
1025 }
801 1026
802 lock (m_items) 1027 if (m_items.Count == 0) // No inventory
1028 {
1029 client.SendTaskInventory(m_part.UUID, 0, new byte[0]);
1030 Items.LockItemsForRead(false);
1031 return;
1032 }
1033
1034 if (!changed)
1035 {
1036 if (m_inventoryFileData.Length > 2)
803 { 1037 {
804 foreach (TaskInventoryItem item in m_items.Values) 1038 xferManager.AddNewFile(m_inventoryFileName,
805 { 1039 m_inventoryFileData);
806// m_log.DebugFormat( 1040 client.SendTaskInventory(m_part.UUID, (short)m_inventorySerial,
807// "[PRIM INVENTORY]: Adding item {0} {1} for serial {2} on prim {3} {4} {5}", 1041 Util.StringToBytes256(m_inventoryFileName));
808// item.Name, item.ItemID, m_inventorySerial, m_part.Name, m_part.UUID, m_part.LocalId);
809 1042
810 UUID ownerID = item.OwnerID; 1043 Items.LockItemsForRead(false);
811 uint everyoneMask = 0; 1044 return;
812 uint baseMask = item.BasePermissions; 1045 }
813 uint ownerMask = item.CurrentPermissions; 1046 }
814 uint groupMask = item.GroupPermissions;
815 1047
816 invString.AddItemStart(); 1048 m_inventoryPrivileged = includeAssets;
817 invString.AddNameValueLine("item_id", item.ItemID.ToString());
818 invString.AddNameValueLine("parent_id", m_part.UUID.ToString());
819 1049
820 invString.AddPermissionsStart(); 1050 foreach (TaskInventoryItem item in m_items.Values)
1051 {
1052 UUID ownerID = item.OwnerID;
1053 uint everyoneMask = 0;
1054 uint baseMask = item.BasePermissions;
1055 uint ownerMask = item.CurrentPermissions;
1056 uint groupMask = item.GroupPermissions;
821 1057
822 invString.AddNameValueLine("base_mask", Utils.UIntToHexString(baseMask)); 1058 invString.AddItemStart();
823 invString.AddNameValueLine("owner_mask", Utils.UIntToHexString(ownerMask)); 1059 invString.AddNameValueLine("item_id", item.ItemID.ToString());
824 invString.AddNameValueLine("group_mask", Utils.UIntToHexString(groupMask)); 1060 invString.AddNameValueLine("parent_id", m_part.UUID.ToString());
825 invString.AddNameValueLine("everyone_mask", Utils.UIntToHexString(everyoneMask));
826 invString.AddNameValueLine("next_owner_mask", Utils.UIntToHexString(item.NextPermissions));
827 1061
828 invString.AddNameValueLine("creator_id", item.CreatorID.ToString()); 1062 invString.AddPermissionsStart();
829 invString.AddNameValueLine("owner_id", ownerID.ToString());
830 1063
831 invString.AddNameValueLine("last_owner_id", item.LastOwnerID.ToString()); 1064 invString.AddNameValueLine("base_mask", Utils.UIntToHexString(baseMask));
1065 invString.AddNameValueLine("owner_mask", Utils.UIntToHexString(ownerMask));
1066 invString.AddNameValueLine("group_mask", Utils.UIntToHexString(groupMask));
1067 invString.AddNameValueLine("everyone_mask", Utils.UIntToHexString(everyoneMask));
1068 invString.AddNameValueLine("next_owner_mask", Utils.UIntToHexString(item.NextPermissions));
832 1069
833 invString.AddNameValueLine("group_id", item.GroupID.ToString()); 1070 invString.AddNameValueLine("creator_id", item.CreatorID.ToString());
834 invString.AddSectionEnd(); 1071 invString.AddNameValueLine("owner_id", ownerID.ToString());
835 1072
836 invString.AddNameValueLine("asset_id", item.AssetID.ToString()); 1073 invString.AddNameValueLine("last_owner_id", item.LastOwnerID.ToString());
837 invString.AddNameValueLine("type", Utils.AssetTypeToString((AssetType)item.Type));
838 invString.AddNameValueLine("inv_type", Utils.InventoryTypeToString((InventoryType)item.InvType));
839 invString.AddNameValueLine("flags", Utils.UIntToHexString(item.Flags));
840 1074
841 invString.AddSaleStart(); 1075 invString.AddNameValueLine("group_id", item.GroupID.ToString());
842 invString.AddNameValueLine("sale_type", "not"); 1076 invString.AddSectionEnd();
843 invString.AddNameValueLine("sale_price", "0");
844 invString.AddSectionEnd();
845 1077
846 invString.AddNameValueLine("name", item.Name + "|"); 1078 if (includeAssets)
847 invString.AddNameValueLine("desc", item.Description + "|"); 1079 invString.AddNameValueLine("asset_id", item.AssetID.ToString());
1080 else
1081 invString.AddNameValueLine("asset_id", UUID.Zero.ToString());
1082 invString.AddNameValueLine("type", Utils.AssetTypeToString((AssetType)item.Type));
1083 invString.AddNameValueLine("inv_type", Utils.InventoryTypeToString((InventoryType)item.InvType));
1084 invString.AddNameValueLine("flags", Utils.UIntToHexString(item.Flags));
848 1085
849 invString.AddNameValueLine("creation_date", item.CreationDate.ToString()); 1086 invString.AddSaleStart();
850 invString.AddSectionEnd(); 1087 invString.AddNameValueLine("sale_type", "not");
851 } 1088 invString.AddNameValueLine("sale_price", "0");
852 } 1089 invString.AddSectionEnd();
853 1090
854 m_inventoryFileData = Utils.StringToBytes(invString.BuildString); 1091 invString.AddNameValueLine("name", item.Name + "|");
1092 invString.AddNameValueLine("desc", item.Description + "|");
855 1093
856 return true; 1094 invString.AddNameValueLine("creation_date", item.CreationDate.ToString());
1095 invString.AddSectionEnd();
857 } 1096 }
858 1097
859 // No need to recreate, the existing file is fine 1098 Items.LockItemsForRead(false);
860 return false;
861 }
862 1099
863 /// <summary> 1100 m_inventoryFileData = Utils.StringToBytes(invString.BuildString);
864 /// Serialize all the metadata for the items in this prim's inventory ready for sending to the client
865 /// </summary>
866 /// <param name="xferManager"></param>
867 public void RequestInventoryFile(IClientAPI client, IXfer xferManager)
868 {
869 lock (m_items)
870 {
871 // Don't send a inventory xfer name if there are no items. Doing so causes viewer 3 to crash when rezzing
872 // a new script if any previous deletion has left the prim inventory empty.
873 if (m_items.Count == 0) // No inventory
874 {
875// m_log.DebugFormat(
876// "[PRIM INVENTORY]: Not sending inventory data for part {0} {1} {2} for {3} since no items",
877// m_part.Name, m_part.LocalId, m_part.UUID, client.Name);
878
879 client.SendTaskInventory(m_part.UUID, 0, new byte[0]);
880 return;
881 }
882 1101
883 CreateInventoryFile(); 1102 if (m_inventoryFileData.Length > 2)
884 1103 {
885 // In principle, we should only do the rest if the inventory changed; 1104 xferManager.AddNewFile(m_inventoryFileName, m_inventoryFileData);
886 // by sending m_inventorySerial to the client, it ought to know 1105 client.SendTaskInventory(m_part.UUID, (short)m_inventorySerial,
887 // that nothing changed and that it doesn't need to request the file. 1106 Util.StringToBytes256(m_inventoryFileName));
888 // Unfortunately, it doesn't look like the client optimizes this; 1107 return;
889 // the client seems to always come back and request the Xfer,
890 // no matter what value m_inventorySerial has.
891 // FIXME: Could probably be > 0 here rather than > 2
892 if (m_inventoryFileData.Length > 2)
893 {
894 // Add the file for Xfer
895 // m_log.DebugFormat(
896 // "[PRIM INVENTORY]: Adding inventory file {0} (length {1}) for transfer on {2} {3} {4}",
897 // m_inventoryFileName, m_inventoryFileData.Length, m_part.Name, m_part.UUID, m_part.LocalId);
898
899 xferManager.AddNewFile(m_inventoryFileName, m_inventoryFileData);
900 }
901
902 // Tell the client we're ready to Xfer the file
903 client.SendTaskInventory(m_part.UUID, (short)m_inventorySerial,
904 Util.StringToBytes256(m_inventoryFileName));
905 } 1108 }
1109
1110 client.SendTaskInventory(m_part.UUID, 0, new byte[0]);
906 } 1111 }
907 1112
908 /// <summary> 1113 /// <summary>
@@ -911,13 +1116,19 @@ namespace OpenSim.Region.Framework.Scenes
911 /// <param name="datastore"></param> 1116 /// <param name="datastore"></param>
912 public void ProcessInventoryBackup(ISimulationDataService datastore) 1117 public void ProcessInventoryBackup(ISimulationDataService datastore)
913 { 1118 {
914 if (HasInventoryChanged) 1119// Removed this because linking will cause an immediate delete of the new
915 { 1120// child prim from the database and the subsequent storing of the prim sees
916 HasInventoryChanged = false; 1121// the inventory of it as unchanged and doesn't store it at all. The overhead
917 List<TaskInventoryItem> items = GetInventoryItems(); 1122// of storing prim inventory needlessly is much less than the aggravation
918 datastore.StorePrimInventory(m_part.UUID, items); 1123// of prim inventory loss.
1124// if (HasInventoryChanged)
1125// {
1126 Items.LockItemsForRead(true);
1127 datastore.StorePrimInventory(m_part.UUID, Items.Values);
1128 Items.LockItemsForRead(false);
919 1129
920 } 1130 HasInventoryChanged = false;
1131// }
921 } 1132 }
922 1133
923 public class InventoryStringBuilder 1134 public class InventoryStringBuilder
@@ -983,82 +1194,63 @@ namespace OpenSim.Region.Framework.Scenes
983 { 1194 {
984 uint mask=0x7fffffff; 1195 uint mask=0x7fffffff;
985 1196
986 lock (m_items) 1197 foreach (TaskInventoryItem item in m_items.Values)
987 { 1198 {
988 foreach (TaskInventoryItem item in m_items.Values) 1199 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Copy) == 0)
1200 mask &= ~((uint)PermissionMask.Copy >> 13);
1201 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Transfer) == 0)
1202 mask &= ~((uint)PermissionMask.Transfer >> 13);
1203 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Modify) == 0)
1204 mask &= ~((uint)PermissionMask.Modify >> 13);
1205
1206 if (item.InvType == (int)InventoryType.Object)
989 { 1207 {
990 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Copy) == 0) 1208 if ((item.CurrentPermissions & ((uint)PermissionMask.Copy >> 13)) == 0)
991 mask &= ~((uint)PermissionMask.Copy >> 13); 1209 mask &= ~((uint)PermissionMask.Copy >> 13);
992 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Transfer) == 0) 1210 if ((item.CurrentPermissions & ((uint)PermissionMask.Transfer >> 13)) == 0)
993 mask &= ~((uint)PermissionMask.Transfer >> 13); 1211 mask &= ~((uint)PermissionMask.Transfer >> 13);
994 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Modify) == 0) 1212 if ((item.CurrentPermissions & ((uint)PermissionMask.Modify >> 13)) == 0)
995 mask &= ~((uint)PermissionMask.Modify >> 13); 1213 mask &= ~((uint)PermissionMask.Modify >> 13);
996
997 if (item.InvType != (int)InventoryType.Object)
998 {
999 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Copy) == 0)
1000 mask &= ~((uint)PermissionMask.Copy >> 13);
1001 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Transfer) == 0)
1002 mask &= ~((uint)PermissionMask.Transfer >> 13);
1003 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Modify) == 0)
1004 mask &= ~((uint)PermissionMask.Modify >> 13);
1005 }
1006 else
1007 {
1008 if ((item.CurrentPermissions & ((uint)PermissionMask.Copy >> 13)) == 0)
1009 mask &= ~((uint)PermissionMask.Copy >> 13);
1010 if ((item.CurrentPermissions & ((uint)PermissionMask.Transfer >> 13)) == 0)
1011 mask &= ~((uint)PermissionMask.Transfer >> 13);
1012 if ((item.CurrentPermissions & ((uint)PermissionMask.Modify >> 13)) == 0)
1013 mask &= ~((uint)PermissionMask.Modify >> 13);
1014 }
1015
1016 if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
1017 mask &= ~(uint)PermissionMask.Copy;
1018 if ((item.CurrentPermissions & (uint)PermissionMask.Transfer) == 0)
1019 mask &= ~(uint)PermissionMask.Transfer;
1020 if ((item.CurrentPermissions & (uint)PermissionMask.Modify) == 0)
1021 mask &= ~(uint)PermissionMask.Modify;
1022 } 1214 }
1215
1216 if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
1217 mask &= ~(uint)PermissionMask.Copy;
1218 if ((item.CurrentPermissions & (uint)PermissionMask.Transfer) == 0)
1219 mask &= ~(uint)PermissionMask.Transfer;
1220 if ((item.CurrentPermissions & (uint)PermissionMask.Modify) == 0)
1221 mask &= ~(uint)PermissionMask.Modify;
1023 } 1222 }
1024
1025 return mask; 1223 return mask;
1026 } 1224 }
1027 1225
1028 public void ApplyNextOwnerPermissions() 1226 public void ApplyNextOwnerPermissions()
1029 { 1227 {
1030 lock (m_items) 1228 foreach (TaskInventoryItem item in m_items.Values)
1031 { 1229 {
1032 foreach (TaskInventoryItem item in m_items.Values) 1230 if (item.InvType == (int)InventoryType.Object && (item.CurrentPermissions & 7) != 0)
1033 { 1231 {
1034 if (item.InvType == (int)InventoryType.Object && (item.CurrentPermissions & 7) != 0) 1232 if ((item.CurrentPermissions & ((uint)PermissionMask.Copy >> 13)) == 0)
1035 { 1233 item.CurrentPermissions &= ~(uint)PermissionMask.Copy;
1036 if ((item.CurrentPermissions & ((uint)PermissionMask.Copy >> 13)) == 0) 1234 if ((item.CurrentPermissions & ((uint)PermissionMask.Transfer >> 13)) == 0)
1037 item.CurrentPermissions &= ~(uint)PermissionMask.Copy; 1235 item.CurrentPermissions &= ~(uint)PermissionMask.Transfer;
1038 if ((item.CurrentPermissions & ((uint)PermissionMask.Transfer >> 13)) == 0) 1236 if ((item.CurrentPermissions & ((uint)PermissionMask.Modify >> 13)) == 0)
1039 item.CurrentPermissions &= ~(uint)PermissionMask.Transfer; 1237 item.CurrentPermissions &= ~(uint)PermissionMask.Modify;
1040 if ((item.CurrentPermissions & ((uint)PermissionMask.Modify >> 13)) == 0)
1041 item.CurrentPermissions &= ~(uint)PermissionMask.Modify;
1042 }
1043 item.CurrentPermissions &= item.NextPermissions;
1044 item.BasePermissions &= item.NextPermissions;
1045 item.EveryonePermissions &= item.NextPermissions;
1046 item.OwnerChanged = true;
1047 item.PermsMask = 0;
1048 item.PermsGranter = UUID.Zero;
1049 } 1238 }
1239 item.OwnerChanged = true;
1240 item.CurrentPermissions &= item.NextPermissions;
1241 item.BasePermissions &= item.NextPermissions;
1242 item.EveryonePermissions &= item.NextPermissions;
1243 item.PermsMask = 0;
1244 item.PermsGranter = UUID.Zero;
1050 } 1245 }
1051 } 1246 }
1052 1247
1053 public void ApplyGodPermissions(uint perms) 1248 public void ApplyGodPermissions(uint perms)
1054 { 1249 {
1055 lock (m_items) 1250 foreach (TaskInventoryItem item in m_items.Values)
1056 { 1251 {
1057 foreach (TaskInventoryItem item in m_items.Values) 1252 item.CurrentPermissions = perms;
1058 { 1253 item.BasePermissions = perms;
1059 item.CurrentPermissions = perms;
1060 item.BasePermissions = perms;
1061 }
1062 } 1254 }
1063 1255
1064 m_inventorySerial++; 1256 m_inventorySerial++;
@@ -1071,14 +1263,11 @@ namespace OpenSim.Region.Framework.Scenes
1071 /// <returns></returns> 1263 /// <returns></returns>
1072 public bool ContainsScripts() 1264 public bool ContainsScripts()
1073 { 1265 {
1074 lock (m_items) 1266 foreach (TaskInventoryItem item in m_items.Values)
1075 { 1267 {
1076 foreach (TaskInventoryItem item in m_items.Values) 1268 if (item.InvType == (int)InventoryType.LSL)
1077 { 1269 {
1078 if (item.InvType == (int)InventoryType.LSL) 1270 return true;
1079 {
1080 return true;
1081 }
1082 } 1271 }
1083 } 1272 }
1084 1273
@@ -1092,17 +1281,15 @@ namespace OpenSim.Region.Framework.Scenes
1092 public int ScriptCount() 1281 public int ScriptCount()
1093 { 1282 {
1094 int count = 0; 1283 int count = 0;
1095 lock (m_items) 1284 Items.LockItemsForRead(true);
1285 foreach (TaskInventoryItem item in m_items.Values)
1096 { 1286 {
1097 foreach (TaskInventoryItem item in m_items.Values) 1287 if (item.InvType == (int)InventoryType.LSL)
1098 { 1288 {
1099 if (item.InvType == (int)InventoryType.LSL) 1289 count++;
1100 {
1101 count++;
1102 }
1103 } 1290 }
1104 } 1291 }
1105 1292 Items.LockItemsForRead(false);
1106 return count; 1293 return count;
1107 } 1294 }
1108 /// <summary> 1295 /// <summary>
@@ -1138,11 +1325,8 @@ namespace OpenSim.Region.Framework.Scenes
1138 { 1325 {
1139 List<UUID> ret = new List<UUID>(); 1326 List<UUID> ret = new List<UUID>();
1140 1327
1141 lock (m_items) 1328 foreach (TaskInventoryItem item in m_items.Values)
1142 { 1329 ret.Add(item.ItemID);
1143 foreach (TaskInventoryItem item in m_items.Values)
1144 ret.Add(item.ItemID);
1145 }
1146 1330
1147 return ret; 1331 return ret;
1148 } 1332 }
@@ -1151,8 +1335,9 @@ namespace OpenSim.Region.Framework.Scenes
1151 { 1335 {
1152 List<TaskInventoryItem> ret = new List<TaskInventoryItem>(); 1336 List<TaskInventoryItem> ret = new List<TaskInventoryItem>();
1153 1337
1154 lock (m_items) 1338 Items.LockItemsForRead(true);
1155 ret = new List<TaskInventoryItem>(m_items.Values); 1339 ret = new List<TaskInventoryItem>(m_items.Values);
1340 Items.LockItemsForRead(false);
1156 1341
1157 return ret; 1342 return ret;
1158 } 1343 }
@@ -1161,18 +1346,24 @@ namespace OpenSim.Region.Framework.Scenes
1161 { 1346 {
1162 List<TaskInventoryItem> ret = new List<TaskInventoryItem>(); 1347 List<TaskInventoryItem> ret = new List<TaskInventoryItem>();
1163 1348
1164 lock (m_items) 1349 Items.LockItemsForRead(true);
1165 { 1350
1166 foreach (TaskInventoryItem item in m_items.Values) 1351 foreach (TaskInventoryItem item in m_items.Values)
1167 if (item.InvType == (int)type) 1352 if (item.InvType == (int)type)
1168 ret.Add(item); 1353 ret.Add(item);
1169 } 1354
1355 Items.LockItemsForRead(false);
1170 1356
1171 return ret; 1357 return ret;
1172 } 1358 }
1173 1359
1174 public Dictionary<UUID, string> GetScriptStates() 1360 public Dictionary<UUID, string> GetScriptStates()
1175 { 1361 {
1362 return GetScriptStates(false);
1363 }
1364
1365 public Dictionary<UUID, string> GetScriptStates(bool oldIDs)
1366 {
1176 Dictionary<UUID, string> ret = new Dictionary<UUID, string>(); 1367 Dictionary<UUID, string> ret = new Dictionary<UUID, string>();
1177 1368
1178 if (m_part.ParentGroup.Scene == null) // Group not in a scene 1369 if (m_part.ParentGroup.Scene == null) // Group not in a scene
@@ -1194,14 +1385,21 @@ namespace OpenSim.Region.Framework.Scenes
1194 string n = e.GetXMLState(item.ItemID); 1385 string n = e.GetXMLState(item.ItemID);
1195 if (n != String.Empty) 1386 if (n != String.Empty)
1196 { 1387 {
1197 if (!ret.ContainsKey(item.ItemID)) 1388 if (oldIDs)
1198 ret[item.ItemID] = n; 1389 {
1390 if (!ret.ContainsKey(item.OldItemID))
1391 ret[item.OldItemID] = n;
1392 }
1393 else
1394 {
1395 if (!ret.ContainsKey(item.ItemID))
1396 ret[item.ItemID] = n;
1397 }
1199 break; 1398 break;
1200 } 1399 }
1201 } 1400 }
1202 } 1401 }
1203 } 1402 }
1204
1205 return ret; 1403 return ret;
1206 } 1404 }
1207 1405
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index b737f91..99ad685 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -63,6 +63,7 @@ namespace OpenSim.Region.Framework.Scenes
63 63
64 struct ScriptControllers 64 struct ScriptControllers
65 { 65 {
66 public UUID objectID;
66 public UUID itemID; 67 public UUID itemID;
67 public ScriptControlled ignoreControls; 68 public ScriptControlled ignoreControls;
68 public ScriptControlled eventControls; 69 public ScriptControlled eventControls;
@@ -98,7 +99,7 @@ namespace OpenSim.Region.Framework.Scenes
98 /// rotation, prim cut, prim twist, prim taper, and prim shear. See mantis 99 /// rotation, prim cut, prim twist, prim taper, and prim shear. See mantis
99 /// issue #1716 100 /// issue #1716
100 /// </summary> 101 /// </summary>
101 public static readonly Vector3 SIT_TARGET_ADJUSTMENT = new Vector3(0.0f, 0.0f, 0.418f); 102 public static readonly Vector3 SIT_TARGET_ADJUSTMENT = new Vector3(0.0f, 0.0f, 0.4f);
102 103
103 /// <summary> 104 /// <summary>
104 /// Movement updates for agents in neighboring regions are sent directly to clients. 105 /// Movement updates for agents in neighboring regions are sent directly to clients.
@@ -175,6 +176,7 @@ namespace OpenSim.Region.Framework.Scenes
175// private int m_lastColCount = -1; //KF: Look for Collision chnages 176// private int m_lastColCount = -1; //KF: Look for Collision chnages
176// private int m_updateCount = 0; //KF: Update Anims for a while 177// private int m_updateCount = 0; //KF: Update Anims for a while
177// private static readonly int UPDATE_COUNT = 10; // how many frames to update for 178// private static readonly int UPDATE_COUNT = 10; // how many frames to update for
179 private List<uint> m_lastColliders = new List<uint>();
178 180
179 private TeleportFlags m_teleportFlags; 181 private TeleportFlags m_teleportFlags;
180 public TeleportFlags TeleportFlags 182 public TeleportFlags TeleportFlags
@@ -236,6 +238,13 @@ namespace OpenSim.Region.Framework.Scenes
236 //private int m_moveToPositionStateStatus; 238 //private int m_moveToPositionStateStatus;
237 //***************************************************** 239 //*****************************************************
238 240
241 private bool m_collisionEventFlag = false;
242 private object m_collisionEventLock = new Object();
243
244 private int m_movementAnimationUpdateCounter = 0;
245
246 private Vector3 m_prevSitOffset;
247
239 protected AvatarAppearance m_appearance; 248 protected AvatarAppearance m_appearance;
240 249
241 public AvatarAppearance Appearance 250 public AvatarAppearance Appearance
@@ -577,6 +586,13 @@ namespace OpenSim.Region.Framework.Scenes
577 /// </summary> 586 /// </summary>
578 public uint ParentID { get; set; } 587 public uint ParentID { get; set; }
579 588
589 public UUID ParentUUID
590 {
591 get { return m_parentUUID; }
592 set { m_parentUUID = value; }
593 }
594 private UUID m_parentUUID = UUID.Zero;
595
580 /// <summary> 596 /// <summary>
581 /// If the avatar is sitting, the prim that it's sitting on. If not sitting then null. 597 /// If the avatar is sitting, the prim that it's sitting on. If not sitting then null.
582 /// </summary> 598 /// </summary>
@@ -737,6 +753,33 @@ namespace OpenSim.Region.Framework.Scenes
737 Appearance = appearance; 753 Appearance = appearance;
738 } 754 }
739 755
756 private void RegionHeartbeatEnd(Scene scene)
757 {
758 if (IsChildAgent)
759 return;
760
761 m_movementAnimationUpdateCounter ++;
762 if (m_movementAnimationUpdateCounter >= 2)
763 {
764 m_movementAnimationUpdateCounter = 0;
765 if (Animator != null)
766 {
767 // If the parentID == 0 we are not sitting
768 // if !SitGournd then we are not sitting on the ground
769 // Fairly straightforward, now here comes the twist
770 // if ParentUUID is NOT UUID.Zero, we are looking to
771 // be sat on an object that isn't there yet. Should
772 // be treated as if sat.
773 if(ParentID == 0 && !SitGround && ParentUUID == UUID.Zero) // skip it if sitting
774 Animator.UpdateMovementAnimations();
775 }
776 else
777 {
778 m_scene.EventManager.OnRegionHeartbeatEnd -= RegionHeartbeatEnd;
779 }
780 }
781 }
782
740 public void RegisterToEvents() 783 public void RegisterToEvents()
741 { 784 {
742 ControllingClient.OnCompleteMovementToRegion += CompleteMovement; 785 ControllingClient.OnCompleteMovementToRegion += CompleteMovement;
@@ -806,10 +849,38 @@ namespace OpenSim.Region.Framework.Scenes
806 "[SCENE]: Upgrading child to root agent for {0} in {1}", 849 "[SCENE]: Upgrading child to root agent for {0} in {1}",
807 Name, m_scene.RegionInfo.RegionName); 850 Name, m_scene.RegionInfo.RegionName);
808 851
809 //m_log.DebugFormat("[SCENE]: known regions in {0}: {1}", Scene.RegionInfo.RegionName, KnownChildRegionHandles.Count);
810
811 bool wasChild = IsChildAgent; 852 bool wasChild = IsChildAgent;
812 IsChildAgent = false; 853
854 if (ParentUUID != UUID.Zero)
855 {
856 m_log.DebugFormat("[SCENE PRESENCE]: Sitting avatar back on prim {0}", ParentUUID);
857 SceneObjectPart part = m_scene.GetSceneObjectPart(ParentUUID);
858 if (part == null)
859 {
860 m_log.ErrorFormat("[SCENE PRESENCE]: Can't find prim {0} to sit on", ParentUUID);
861 }
862 else
863 {
864 part.ParentGroup.AddAvatar(UUID);
865 if (part.SitTargetPosition != Vector3.Zero)
866 part.SitTargetAvatar = UUID;
867 ParentPosition = part.GetWorldPosition();
868 ParentID = part.LocalId;
869 ParentPart = part;
870 m_pos = m_prevSitOffset;
871 pos = ParentPosition;
872 }
873 ParentUUID = UUID.Zero;
874
875 IsChildAgent = false;
876
877 Animator.TrySetMovementAnimation("SIT");
878 }
879 else
880 {
881 IsChildAgent = false;
882 }
883
813 884
814 IGroupsModule gm = m_scene.RequestModuleInterface<IGroupsModule>(); 885 IGroupsModule gm = m_scene.RequestModuleInterface<IGroupsModule>();
815 if (gm != null) 886 if (gm != null)
@@ -819,62 +890,72 @@ namespace OpenSim.Region.Framework.Scenes
819 890
820 m_scene.EventManager.TriggerSetRootAgentScene(m_uuid, m_scene); 891 m_scene.EventManager.TriggerSetRootAgentScene(m_uuid, m_scene);
821 892
822 // Moved this from SendInitialData to ensure that Appearance is initialized 893 if (ParentID == 0)
823 // before the inventory is processed in MakeRootAgent. This fixes a race condition
824 // related to the handling of attachments
825 //m_scene.GetAvatarAppearance(ControllingClient, out Appearance);
826 if (m_scene.TestBorderCross(pos, Cardinals.E))
827 { 894 {
828 Border crossedBorder = m_scene.GetCrossedBorder(pos, Cardinals.E); 895 // Moved this from SendInitialData to ensure that Appearance is initialized
829 pos.X = crossedBorder.BorderLine.Z - 1; 896 // before the inventory is processed in MakeRootAgent. This fixes a race condition
830 } 897 // related to the handling of attachments
898 //m_scene.GetAvatarAppearance(ControllingClient, out Appearance);
899 if (m_scene.TestBorderCross(pos, Cardinals.E))
900 {
901 Border crossedBorder = m_scene.GetCrossedBorder(pos, Cardinals.E);
902 pos.X = crossedBorder.BorderLine.Z - 1;
903 }
831 904
832 if (m_scene.TestBorderCross(pos, Cardinals.N)) 905 if (m_scene.TestBorderCross(pos, Cardinals.N))
833 { 906 {
834 Border crossedBorder = m_scene.GetCrossedBorder(pos, Cardinals.N); 907 Border crossedBorder = m_scene.GetCrossedBorder(pos, Cardinals.N);
835 pos.Y = crossedBorder.BorderLine.Z - 1; 908 pos.Y = crossedBorder.BorderLine.Z - 1;
836 } 909 }
837 910
838 CheckAndAdjustLandingPoint(ref pos); 911 CheckAndAdjustLandingPoint(ref pos);
839 912
840 if (pos.X < 0f || pos.Y < 0f || pos.Z < 0f) 913 if (pos.X < 0f || pos.Y < 0f || pos.Z < 0f)
841 { 914 {
842 m_log.WarnFormat( 915 m_log.WarnFormat(
843 "[SCENE PRESENCE]: MakeRootAgent() was given an illegal position of {0} for avatar {1}, {2}. Clamping", 916 "[SCENE PRESENCE]: MakeRootAgent() was given an illegal position of {0} for avatar {1}, {2}. Clamping",
844 pos, Name, UUID); 917 pos, Name, UUID);
845 918
846 if (pos.X < 0f) pos.X = 0f; 919 if (pos.X < 0f) pos.X = 0f;
847 if (pos.Y < 0f) pos.Y = 0f; 920 if (pos.Y < 0f) pos.Y = 0f;
848 if (pos.Z < 0f) pos.Z = 0f; 921 if (pos.Z < 0f) pos.Z = 0f;
849 } 922 }
850 923
851 float localAVHeight = 1.56f; 924 float localAVHeight = 1.56f;
852 if (Appearance.AvatarHeight > 0) 925 if (Appearance.AvatarHeight > 0)
853 localAVHeight = Appearance.AvatarHeight; 926 localAVHeight = Appearance.AvatarHeight;
854 927
855 float posZLimit = 0; 928 float posZLimit = 0;
856 929
857 if (pos.X < Constants.RegionSize && pos.Y < Constants.RegionSize) 930 if (pos.X < Constants.RegionSize && pos.Y < Constants.RegionSize)
858 posZLimit = (float)m_scene.Heightmap[(int)pos.X, (int)pos.Y]; 931 posZLimit = (float)m_scene.Heightmap[(int)pos.X, (int)pos.Y];
859 932
860 float newPosZ = posZLimit + localAVHeight / 2; 933 float newPosZ = posZLimit + localAVHeight / 2;
861 if (posZLimit >= (pos.Z - (localAVHeight / 2)) && !(Single.IsInfinity(newPosZ) || Single.IsNaN(newPosZ))) 934 if (posZLimit >= (pos.Z - (localAVHeight / 2)) && !(Single.IsInfinity(newPosZ) || Single.IsNaN(newPosZ)))
862 { 935 {
863 pos.Z = newPosZ; 936 pos.Z = newPosZ;
864 } 937 }
865 AbsolutePosition = pos; 938 AbsolutePosition = pos;
866 939
867 AddToPhysicalScene(isFlying); 940 if (m_teleportFlags == TeleportFlags.Default)
941 {
942 Vector3 vel = Velocity;
943 AddToPhysicalScene(isFlying);
944 if (PhysicsActor != null)
945 PhysicsActor.SetMomentum(vel);
946 }
947 else
948 AddToPhysicalScene(isFlying);
868 949
869 if (ForceFly) 950 if (ForceFly)
870 { 951 {
871 Flying = true; 952 Flying = true;
872 } 953 }
873 else if (FlyDisabled) 954 else if (FlyDisabled)
874 { 955 {
875 Flying = false; 956 Flying = false;
957 }
876 } 958 }
877
878 // Don't send an animation pack here, since on a region crossing this will sometimes cause a flying 959 // Don't send an animation pack here, since on a region crossing this will sometimes cause a flying
879 // avatar to return to the standing position in mid-air. On login it looks like this is being sent 960 // avatar to return to the standing position in mid-air. On login it looks like this is being sent
880 // elsewhere anyway 961 // elsewhere anyway
@@ -892,14 +973,19 @@ namespace OpenSim.Region.Framework.Scenes
892 { 973 {
893 m_log.DebugFormat("[SCENE PRESENCE]: Restarting scripts in attachments..."); 974 m_log.DebugFormat("[SCENE PRESENCE]: Restarting scripts in attachments...");
894 // Resume scripts 975 // Resume scripts
895 foreach (SceneObjectGroup sog in m_attachments) 976 Util.FireAndForget(delegate(object x) {
896 { 977 foreach (SceneObjectGroup sog in m_attachments)
897 sog.RootPart.ParentGroup.CreateScriptInstances(0, false, m_scene.DefaultScriptEngine, GetStateSource()); 978 {
898 sog.ResumeScripts(); 979 sog.ScheduleGroupForFullUpdate();
899 } 980 sog.RootPart.ParentGroup.CreateScriptInstances(0, false, m_scene.DefaultScriptEngine, GetStateSource());
981 sog.ResumeScripts();
982 }
983 });
900 } 984 }
901 } 985 }
902 986
987 SendAvatarDataToAllAgents();
988
903 // send the animations of the other presences to me 989 // send the animations of the other presences to me
904 m_scene.ForEachRootScenePresence(delegate(ScenePresence presence) 990 m_scene.ForEachRootScenePresence(delegate(ScenePresence presence)
905 { 991 {
@@ -910,9 +996,12 @@ namespace OpenSim.Region.Framework.Scenes
910 // If we don't reset the movement flag here, an avatar that crosses to a neighbouring sim and returns will 996 // If we don't reset the movement flag here, an avatar that crosses to a neighbouring sim and returns will
911 // stall on the border crossing since the existing child agent will still have the last movement 997 // stall on the border crossing since the existing child agent will still have the last movement
912 // recorded, which stops the input from being processed. 998 // recorded, which stops the input from being processed.
999
913 MovementFlag = 0; 1000 MovementFlag = 0;
914 1001
915 m_scene.EventManager.TriggerOnMakeRootAgent(this); 1002 m_scene.EventManager.TriggerOnMakeRootAgent(this);
1003
1004 m_scene.EventManager.OnRegionHeartbeatEnd += RegionHeartbeatEnd;
916 } 1005 }
917 1006
918 public int GetStateSource() 1007 public int GetStateSource()
@@ -940,12 +1029,16 @@ namespace OpenSim.Region.Framework.Scenes
940 /// </remarks> 1029 /// </remarks>
941 public void MakeChildAgent() 1030 public void MakeChildAgent()
942 { 1031 {
1032 m_scene.EventManager.OnRegionHeartbeatEnd -= RegionHeartbeatEnd;
1033
943 m_log.DebugFormat("[SCENE PRESENCE]: Making {0} a child agent in {1}", Name, Scene.RegionInfo.RegionName); 1034 m_log.DebugFormat("[SCENE PRESENCE]: Making {0} a child agent in {1}", Name, Scene.RegionInfo.RegionName);
944 1035
945 // Reset these so that teleporting in and walking out isn't seen 1036 // Reset these so that teleporting in and walking out isn't seen
946 // as teleporting back 1037 // as teleporting back
947 TeleportFlags = TeleportFlags.Default; 1038 TeleportFlags = TeleportFlags.Default;
948 1039
1040 MovementFlag = 0;
1041
949 // It looks like Animator is set to null somewhere, and MakeChild 1042 // It looks like Animator is set to null somewhere, and MakeChild
950 // is called after that. Probably in aborted teleports. 1043 // is called after that. Probably in aborted teleports.
951 if (Animator == null) 1044 if (Animator == null)
@@ -953,6 +1046,7 @@ namespace OpenSim.Region.Framework.Scenes
953 else 1046 else
954 Animator.ResetAnimations(); 1047 Animator.ResetAnimations();
955 1048
1049
956// m_log.DebugFormat( 1050// m_log.DebugFormat(
957// "[SCENE PRESENCE]: Downgrading root agent {0}, {1} to a child agent in {2}", 1051// "[SCENE PRESENCE]: Downgrading root agent {0}, {1} to a child agent in {2}",
958// Name, UUID, m_scene.RegionInfo.RegionName); 1052// Name, UUID, m_scene.RegionInfo.RegionName);
@@ -979,9 +1073,9 @@ namespace OpenSim.Region.Framework.Scenes
979 { 1073 {
980// PhysicsActor.OnRequestTerseUpdate -= SendTerseUpdateToAllClients; 1074// PhysicsActor.OnRequestTerseUpdate -= SendTerseUpdateToAllClients;
981 PhysicsActor.OnOutOfBounds -= OutOfBoundsCall; 1075 PhysicsActor.OnOutOfBounds -= OutOfBoundsCall;
982 m_scene.PhysicsScene.RemoveAvatar(PhysicsActor);
983 PhysicsActor.UnSubscribeEvents();
984 PhysicsActor.OnCollisionUpdate -= PhysicsCollisionUpdate; 1076 PhysicsActor.OnCollisionUpdate -= PhysicsCollisionUpdate;
1077 PhysicsActor.UnSubscribeEvents();
1078 m_scene.PhysicsScene.RemoveAvatar(PhysicsActor);
985 PhysicsActor = null; 1079 PhysicsActor = null;
986 } 1080 }
987// else 1081// else
@@ -998,7 +1092,7 @@ namespace OpenSim.Region.Framework.Scenes
998 /// <param name="pos"></param> 1092 /// <param name="pos"></param>
999 public void Teleport(Vector3 pos) 1093 public void Teleport(Vector3 pos)
1000 { 1094 {
1001 TeleportWithMomentum(pos, null); 1095 TeleportWithMomentum(pos, Vector3.Zero);
1002 } 1096 }
1003 1097
1004 public void TeleportWithMomentum(Vector3 pos, Vector3? v) 1098 public void TeleportWithMomentum(Vector3 pos, Vector3? v)
@@ -1022,6 +1116,41 @@ namespace OpenSim.Region.Framework.Scenes
1022 SendTerseUpdateToAllClients(); 1116 SendTerseUpdateToAllClients();
1023 } 1117 }
1024 1118
1119 public void avnLocalTeleport(Vector3 newpos, Vector3? newvel, bool rotateToVelXY)
1120 {
1121 CheckLandingPoint(ref newpos);
1122 AbsolutePosition = newpos;
1123
1124 if (newvel.HasValue)
1125 {
1126 if ((Vector3)newvel == Vector3.Zero)
1127 {
1128 if (PhysicsActor != null)
1129 PhysicsActor.SetMomentum(Vector3.Zero);
1130 m_velocity = Vector3.Zero;
1131 }
1132 else
1133 {
1134 if (PhysicsActor != null)
1135 PhysicsActor.SetMomentum((Vector3)newvel);
1136 m_velocity = (Vector3)newvel;
1137
1138 if (rotateToVelXY)
1139 {
1140 Vector3 lookAt = (Vector3)newvel;
1141 lookAt.Z = 0;
1142 lookAt.Normalize();
1143 ControllingClient.SendLocalTeleport(newpos, lookAt, (uint)TeleportFlags.ViaLocation);
1144 return;
1145 }
1146 }
1147 }
1148
1149 SendTerseUpdateToAllClients();
1150 }
1151
1152
1153
1025 public void StopFlying() 1154 public void StopFlying()
1026 { 1155 {
1027 ControllingClient.StopFlying(this); 1156 ControllingClient.StopFlying(this);
@@ -1331,8 +1460,18 @@ namespace OpenSim.Region.Framework.Scenes
1331 { 1460 {
1332 if (m_followCamAuto) 1461 if (m_followCamAuto)
1333 { 1462 {
1334 Vector3 posAdjusted = m_pos + HEAD_ADJUSTMENT; 1463 // Vector3 posAdjusted = m_pos + HEAD_ADJUSTMENT;
1335 m_scene.PhysicsScene.RaycastWorld(m_pos, Vector3.Normalize(CameraPosition - posAdjusted), Vector3.Distance(CameraPosition, posAdjusted) + 0.3f, RayCastCameraCallback); 1464 // m_scene.PhysicsScene.RaycastWorld(m_pos, Vector3.Normalize(CameraPosition - posAdjusted), Vector3.Distance(CameraPosition, posAdjusted) + 0.3f, RayCastCameraCallback);
1465
1466 Vector3 posAdjusted = AbsolutePosition + HEAD_ADJUSTMENT;
1467 Vector3 distTocam = CameraPosition - posAdjusted;
1468 float distTocamlen = distTocam.Length();
1469 if (distTocamlen > 0)
1470 {
1471 distTocam *= 1.0f / distTocamlen;
1472 m_scene.PhysicsScene.RaycastWorld(posAdjusted, distTocam, distTocamlen + 0.3f, RayCastCameraCallback);
1473 }
1474
1336 } 1475 }
1337 } 1476 }
1338 1477
@@ -1766,12 +1905,17 @@ namespace OpenSim.Region.Framework.Scenes
1766// m_log.DebugFormat("[SCENE PRESENCE]: StandUp() for {0}", Name); 1905// m_log.DebugFormat("[SCENE PRESENCE]: StandUp() for {0}", Name);
1767 1906
1768 SitGround = false; 1907 SitGround = false;
1908
1909/* move this down so avatar gets physical in the new position and not where it is siting
1769 if (PhysicsActor == null) 1910 if (PhysicsActor == null)
1770 AddToPhysicalScene(false); 1911 AddToPhysicalScene(false);
1912 */
1771 1913
1772 if (ParentID != 0) 1914 if (ParentID != 0)
1773 { 1915 {
1774 SceneObjectPart part = ParentPart; 1916 SceneObjectPart part = ParentPart;
1917 UnRegisterSeatControls(part.ParentGroup.UUID);
1918
1775 TaskInventoryDictionary taskIDict = part.TaskInventory; 1919 TaskInventoryDictionary taskIDict = part.TaskInventory;
1776 if (taskIDict != null) 1920 if (taskIDict != null)
1777 { 1921 {
@@ -1791,6 +1935,7 @@ namespace OpenSim.Region.Framework.Scenes
1791 if (part.SitTargetAvatar == UUID) 1935 if (part.SitTargetAvatar == UUID)
1792 part.SitTargetAvatar = UUID.Zero; 1936 part.SitTargetAvatar = UUID.Zero;
1793 1937
1938 part.ParentGroup.DeleteAvatar(UUID);
1794 ParentPosition = part.GetWorldPosition(); 1939 ParentPosition = part.GetWorldPosition();
1795 ControllingClient.SendClearFollowCamProperties(part.ParentUUID); 1940 ControllingClient.SendClearFollowCamProperties(part.ParentUUID);
1796 1941
@@ -1799,6 +1944,10 @@ namespace OpenSim.Region.Framework.Scenes
1799 1944
1800 ParentID = 0; 1945 ParentID = 0;
1801 ParentPart = null; 1946 ParentPart = null;
1947
1948 if (PhysicsActor == null)
1949 AddToPhysicalScene(false);
1950
1802 SendAvatarDataToAllAgents(); 1951 SendAvatarDataToAllAgents();
1803 m_requestedSitTargetID = 0; 1952 m_requestedSitTargetID = 0;
1804 1953
@@ -1806,6 +1955,9 @@ namespace OpenSim.Region.Framework.Scenes
1806 part.ParentGroup.TriggerScriptChangedEvent(Changed.LINK); 1955 part.ParentGroup.TriggerScriptChangedEvent(Changed.LINK);
1807 } 1956 }
1808 1957
1958 else if (PhysicsActor == null)
1959 AddToPhysicalScene(false);
1960
1809 Animator.TrySetMovementAnimation("STAND"); 1961 Animator.TrySetMovementAnimation("STAND");
1810 } 1962 }
1811 1963
@@ -1929,7 +2081,7 @@ namespace OpenSim.Region.Framework.Scenes
1929 forceMouselook = part.GetForceMouselook(); 2081 forceMouselook = part.GetForceMouselook();
1930 2082
1931 ControllingClient.SendSitResponse( 2083 ControllingClient.SendSitResponse(
1932 targetID, offset, sitOrientation, false, cameraAtOffset, cameraEyeOffset, forceMouselook); 2084 part.UUID, offset, sitOrientation, false, cameraAtOffset, cameraEyeOffset, forceMouselook);
1933 2085
1934 m_requestedSitTargetUUID = targetID; 2086 m_requestedSitTargetUUID = targetID;
1935 2087
@@ -2211,14 +2363,36 @@ namespace OpenSim.Region.Framework.Scenes
2211 2363
2212 //Quaternion result = (sitTargetOrient * vq) * nq; 2364 //Quaternion result = (sitTargetOrient * vq) * nq;
2213 2365
2214 m_pos = sitTargetPos + SIT_TARGET_ADJUSTMENT; 2366 double x, y, z, m;
2367
2368 Quaternion r = sitTargetOrient;
2369 m = r.X * r.X + r.Y * r.Y + r.Z * r.Z + r.W * r.W;
2370
2371 if (Math.Abs(1.0 - m) > 0.000001)
2372 {
2373 m = 1.0 / Math.Sqrt(m);
2374 r.X *= (float)m;
2375 r.Y *= (float)m;
2376 r.Z *= (float)m;
2377 r.W *= (float)m;
2378 }
2379
2380 x = 2 * (r.X * r.Z + r.Y * r.W);
2381 y = 2 * (-r.X * r.W + r.Y * r.Z);
2382 z = -r.X * r.X - r.Y * r.Y + r.Z * r.Z + r.W * r.W;
2383
2384 Vector3 up = new Vector3((float)x, (float)y, (float)z);
2385 Vector3 sitOffset = up * Appearance.AvatarHeight * 0.02638f;
2386 m_pos = sitTargetPos + sitOffset + SIT_TARGET_ADJUSTMENT;
2215 Rotation = sitTargetOrient; 2387 Rotation = sitTargetOrient;
2216 ParentPosition = part.AbsolutePosition; 2388 ParentPosition = part.AbsolutePosition;
2389 part.ParentGroup.AddAvatar(UUID);
2217 } 2390 }
2218 else 2391 else
2219 { 2392 {
2220 m_pos -= part.AbsolutePosition; 2393 m_pos -= part.AbsolutePosition;
2221 ParentPosition = part.AbsolutePosition; 2394 ParentPosition = part.AbsolutePosition;
2395 part.ParentGroup.AddAvatar(UUID);
2222 2396
2223// m_log.DebugFormat( 2397// m_log.DebugFormat(
2224// "[SCENE PRESENCE]: Sitting {0} at position {1} ({2} + {3}) on part {4} {5} without sit target", 2398// "[SCENE PRESENCE]: Sitting {0} at position {1} ({2} + {3}) on part {4} {5} without sit target",
@@ -2316,14 +2490,15 @@ namespace OpenSim.Region.Framework.Scenes
2316 direc.Z *= 2.6f; 2490 direc.Z *= 2.6f;
2317 2491
2318 // TODO: PreJump and jump happen too quickly. Many times prejump gets ignored. 2492 // TODO: PreJump and jump happen too quickly. Many times prejump gets ignored.
2319 Animator.TrySetMovementAnimation("PREJUMP"); 2493// Animator.TrySetMovementAnimation("PREJUMP");
2320 Animator.TrySetMovementAnimation("JUMP"); 2494// Animator.TrySetMovementAnimation("JUMP");
2321 } 2495 }
2322 } 2496 }
2323 } 2497 }
2324 2498
2325 // TODO: Add the force instead of only setting it to support multiple forces per frame? 2499 // TODO: Add the force instead of only setting it to support multiple forces per frame?
2326 m_forceToApply = direc; 2500 m_forceToApply = direc;
2501 Animator.UpdateMovementAnimations();
2327 } 2502 }
2328 2503
2329 #endregion 2504 #endregion
@@ -3058,6 +3233,9 @@ namespace OpenSim.Region.Framework.Scenes
3058 cAgent.AlwaysRun = SetAlwaysRun; 3233 cAgent.AlwaysRun = SetAlwaysRun;
3059 3234
3060 cAgent.Appearance = new AvatarAppearance(Appearance); 3235 cAgent.Appearance = new AvatarAppearance(Appearance);
3236
3237 cAgent.ParentPart = ParentUUID;
3238 cAgent.SitOffset = m_pos;
3061 3239
3062 lock (scriptedcontrols) 3240 lock (scriptedcontrols)
3063 { 3241 {
@@ -3066,7 +3244,7 @@ namespace OpenSim.Region.Framework.Scenes
3066 3244
3067 foreach (ScriptControllers c in scriptedcontrols.Values) 3245 foreach (ScriptControllers c in scriptedcontrols.Values)
3068 { 3246 {
3069 controls[i++] = new ControllerData(c.itemID, (uint)c.ignoreControls, (uint)c.eventControls); 3247 controls[i++] = new ControllerData(c.objectID, c.itemID, (uint)c.ignoreControls, (uint)c.eventControls);
3070 } 3248 }
3071 cAgent.Controllers = controls; 3249 cAgent.Controllers = controls;
3072 } 3250 }
@@ -3077,6 +3255,7 @@ namespace OpenSim.Region.Framework.Scenes
3077 cAgent.Anims = Animator.Animations.ToArray(); 3255 cAgent.Anims = Animator.Animations.ToArray();
3078 } 3256 }
3079 catch { } 3257 catch { }
3258 cAgent.DefaultAnim = Animator.Animations.DefaultAnimation;
3080 3259
3081 // Attachment objects 3260 // Attachment objects
3082 List<SceneObjectGroup> attachments = GetAttachments(); 3261 List<SceneObjectGroup> attachments = GetAttachments();
@@ -3117,6 +3296,8 @@ namespace OpenSim.Region.Framework.Scenes
3117 CameraAtAxis = cAgent.AtAxis; 3296 CameraAtAxis = cAgent.AtAxis;
3118 CameraLeftAxis = cAgent.LeftAxis; 3297 CameraLeftAxis = cAgent.LeftAxis;
3119 CameraUpAxis = cAgent.UpAxis; 3298 CameraUpAxis = cAgent.UpAxis;
3299 ParentUUID = cAgent.ParentPart;
3300 m_prevSitOffset = cAgent.SitOffset;
3120 3301
3121 // When we get to the point of re-computing neighbors everytime this 3302 // When we get to the point of re-computing neighbors everytime this
3122 // changes, then start using the agent's drawdistance rather than the 3303 // changes, then start using the agent's drawdistance rather than the
@@ -3154,6 +3335,7 @@ namespace OpenSim.Region.Framework.Scenes
3154 foreach (ControllerData c in cAgent.Controllers) 3335 foreach (ControllerData c in cAgent.Controllers)
3155 { 3336 {
3156 ScriptControllers sc = new ScriptControllers(); 3337 ScriptControllers sc = new ScriptControllers();
3338 sc.objectID = c.ObjectID;
3157 sc.itemID = c.ItemID; 3339 sc.itemID = c.ItemID;
3158 sc.ignoreControls = (ScriptControlled)c.IgnoreControls; 3340 sc.ignoreControls = (ScriptControlled)c.IgnoreControls;
3159 sc.eventControls = (ScriptControlled)c.EventControls; 3341 sc.eventControls = (ScriptControlled)c.EventControls;
@@ -3168,6 +3350,8 @@ namespace OpenSim.Region.Framework.Scenes
3168 // FIXME: Why is this null check necessary? Where are the cases where we get a null Anims object? 3350 // FIXME: Why is this null check necessary? Where are the cases where we get a null Anims object?
3169 if (cAgent.Anims != null) 3351 if (cAgent.Anims != null)
3170 Animator.Animations.FromArray(cAgent.Anims); 3352 Animator.Animations.FromArray(cAgent.Anims);
3353 if (cAgent.DefaultAnim != null)
3354 Animator.Animations.SetDefaultAnimation(cAgent.DefaultAnim.AnimID, cAgent.DefaultAnim.SequenceNum, UUID.Zero);
3171 3355
3172 if (cAgent.AttachmentObjects != null && cAgent.AttachmentObjects.Count > 0) 3356 if (cAgent.AttachmentObjects != null && cAgent.AttachmentObjects.Count > 0)
3173 { 3357 {
@@ -3270,18 +3454,6 @@ namespace OpenSim.Region.Framework.Scenes
3270 if (IsChildAgent) 3454 if (IsChildAgent)
3271 return; 3455 return;
3272 3456
3273 //if ((Math.Abs(Velocity.X) > 0.1e-9f) || (Math.Abs(Velocity.Y) > 0.1e-9f))
3274 // The Physics Scene will send updates every 500 ms grep: PhysicsActor.SubscribeEvents(
3275 // as of this comment the interval is set in AddToPhysicalScene
3276 if (Animator != null)
3277 {
3278// if (m_updateCount > 0)
3279// {
3280 Animator.UpdateMovementAnimations();
3281// m_updateCount--;
3282// }
3283 }
3284
3285 CollisionEventUpdate collisionData = (CollisionEventUpdate)e; 3457 CollisionEventUpdate collisionData = (CollisionEventUpdate)e;
3286 Dictionary<uint, ContactPoint> coldata = collisionData.m_objCollisionList; 3458 Dictionary<uint, ContactPoint> coldata = collisionData.m_objCollisionList;
3287 3459
@@ -3656,10 +3828,15 @@ namespace OpenSim.Region.Framework.Scenes
3656 3828
3657 public void RegisterControlEventsToScript(int controls, int accept, int pass_on, uint Obj_localID, UUID Script_item_UUID) 3829 public void RegisterControlEventsToScript(int controls, int accept, int pass_on, uint Obj_localID, UUID Script_item_UUID)
3658 { 3830 {
3831 SceneObjectPart p = m_scene.GetSceneObjectPart(Obj_localID);
3832 if (p == null)
3833 return;
3834
3659 ScriptControllers obj = new ScriptControllers(); 3835 ScriptControllers obj = new ScriptControllers();
3660 obj.ignoreControls = ScriptControlled.CONTROL_ZERO; 3836 obj.ignoreControls = ScriptControlled.CONTROL_ZERO;
3661 obj.eventControls = ScriptControlled.CONTROL_ZERO; 3837 obj.eventControls = ScriptControlled.CONTROL_ZERO;
3662 3838
3839 obj.objectID = p.ParentGroup.UUID;
3663 obj.itemID = Script_item_UUID; 3840 obj.itemID = Script_item_UUID;
3664 if (pass_on == 0 && accept == 0) 3841 if (pass_on == 0 && accept == 0)
3665 { 3842 {
@@ -3708,6 +3885,21 @@ namespace OpenSim.Region.Framework.Scenes
3708 ControllingClient.SendTakeControls(int.MaxValue, false, false); 3885 ControllingClient.SendTakeControls(int.MaxValue, false, false);
3709 } 3886 }
3710 3887
3888 private void UnRegisterSeatControls(UUID obj)
3889 {
3890 List<UUID> takers = new List<UUID>();
3891
3892 foreach (ScriptControllers c in scriptedcontrols.Values)
3893 {
3894 if (c.objectID == obj)
3895 takers.Add(c.itemID);
3896 }
3897 foreach (UUID t in takers)
3898 {
3899 UnRegisterControlEventsToScript(0, t);
3900 }
3901 }
3902
3711 public void UnRegisterControlEventsToScript(uint Obj_localID, UUID Script_item_UUID) 3903 public void UnRegisterControlEventsToScript(uint Obj_localID, UUID Script_item_UUID)
3712 { 3904 {
3713 ScriptControllers takecontrols; 3905 ScriptControllers takecontrols;
@@ -3962,6 +4154,12 @@ namespace OpenSim.Region.Framework.Scenes
3962 4154
3963 private void CheckAndAdjustLandingPoint(ref Vector3 pos) 4155 private void CheckAndAdjustLandingPoint(ref Vector3 pos)
3964 { 4156 {
4157 string reason;
4158
4159 // Honor bans
4160 if (!m_scene.TestLandRestrictions(UUID, out reason, ref pos.X, ref pos.Y))
4161 return;
4162
3965 SceneObjectGroup telehub = null; 4163 SceneObjectGroup telehub = null;
3966 if (m_scene.RegionInfo.RegionSettings.TelehubObject != UUID.Zero && (telehub = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject)) != null) 4164 if (m_scene.RegionInfo.RegionSettings.TelehubObject != UUID.Zero && (telehub = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject)) != null)
3967 { 4165 {
@@ -4001,11 +4199,173 @@ namespace OpenSim.Region.Framework.Scenes
4001 pos = land.LandData.UserLocation; 4199 pos = land.LandData.UserLocation;
4002 } 4200 }
4003 } 4201 }
4004 4202
4005 land.SendLandUpdateToClient(ControllingClient); 4203 land.SendLandUpdateToClient(ControllingClient);
4006 } 4204 }
4007 } 4205 }
4008 4206
4207 private void RaiseCollisionScriptEvents(Dictionary<uint, ContactPoint> coldata)
4208 {
4209 lock(m_collisionEventLock)
4210 {
4211 if (m_collisionEventFlag)
4212 return;
4213 m_collisionEventFlag = true;
4214 }
4215
4216 Util.FireAndForget(delegate(object x)
4217 {
4218 try
4219 {
4220 List<uint> thisHitColliders = new List<uint>();
4221 List<uint> endedColliders = new List<uint>();
4222 List<uint> startedColliders = new List<uint>();
4223
4224 foreach (uint localid in coldata.Keys)
4225 {
4226 thisHitColliders.Add(localid);
4227 if (!m_lastColliders.Contains(localid))
4228 {
4229 startedColliders.Add(localid);
4230 }
4231 //m_log.Debug("[SCENE PRESENCE]: Collided with:" + localid.ToString() + " at depth of: " + collissionswith[localid].ToString());
4232 }
4233
4234 // calculate things that ended colliding
4235 foreach (uint localID in m_lastColliders)
4236 {
4237 if (!thisHitColliders.Contains(localID))
4238 {
4239 endedColliders.Add(localID);
4240 }
4241 }
4242 //add the items that started colliding this time to the last colliders list.
4243 foreach (uint localID in startedColliders)
4244 {
4245 m_lastColliders.Add(localID);
4246 }
4247 // remove things that ended colliding from the last colliders list
4248 foreach (uint localID in endedColliders)
4249 {
4250 m_lastColliders.Remove(localID);
4251 }
4252
4253 // do event notification
4254 if (startedColliders.Count > 0)
4255 {
4256 ColliderArgs StartCollidingMessage = new ColliderArgs();
4257 List<DetectedObject> colliding = new List<DetectedObject>();
4258 foreach (uint localId in startedColliders)
4259 {
4260 if (localId == 0)
4261 continue;
4262
4263 SceneObjectPart obj = Scene.GetSceneObjectPart(localId);
4264 string data = "";
4265 if (obj != null)
4266 {
4267 DetectedObject detobj = new DetectedObject();
4268 detobj.keyUUID = obj.UUID;
4269 detobj.nameStr = obj.Name;
4270 detobj.ownerUUID = obj.OwnerID;
4271 detobj.posVector = obj.AbsolutePosition;
4272 detobj.rotQuat = obj.GetWorldRotation();
4273 detobj.velVector = obj.Velocity;
4274 detobj.colliderType = 0;
4275 detobj.groupUUID = obj.GroupID;
4276 colliding.Add(detobj);
4277 }
4278 }
4279
4280 if (colliding.Count > 0)
4281 {
4282 StartCollidingMessage.Colliders = colliding;
4283
4284 foreach (SceneObjectGroup att in GetAttachments())
4285 Scene.EventManager.TriggerScriptCollidingStart(att.LocalId, StartCollidingMessage);
4286 }
4287 }
4288
4289 if (endedColliders.Count > 0)
4290 {
4291 ColliderArgs EndCollidingMessage = new ColliderArgs();
4292 List<DetectedObject> colliding = new List<DetectedObject>();
4293 foreach (uint localId in endedColliders)
4294 {
4295 if (localId == 0)
4296 continue;
4297
4298 SceneObjectPart obj = Scene.GetSceneObjectPart(localId);
4299 string data = "";
4300 if (obj != null)
4301 {
4302 DetectedObject detobj = new DetectedObject();
4303 detobj.keyUUID = obj.UUID;
4304 detobj.nameStr = obj.Name;
4305 detobj.ownerUUID = obj.OwnerID;
4306 detobj.posVector = obj.AbsolutePosition;
4307 detobj.rotQuat = obj.GetWorldRotation();
4308 detobj.velVector = obj.Velocity;
4309 detobj.colliderType = 0;
4310 detobj.groupUUID = obj.GroupID;
4311 colliding.Add(detobj);
4312 }
4313 }
4314
4315 if (colliding.Count > 0)
4316 {
4317 EndCollidingMessage.Colliders = colliding;
4318
4319 foreach (SceneObjectGroup att in GetAttachments())
4320 Scene.EventManager.TriggerScriptCollidingEnd(att.LocalId, EndCollidingMessage);
4321 }
4322 }
4323
4324 if (thisHitColliders.Count > 0)
4325 {
4326 ColliderArgs CollidingMessage = new ColliderArgs();
4327 List<DetectedObject> colliding = new List<DetectedObject>();
4328 foreach (uint localId in thisHitColliders)
4329 {
4330 if (localId == 0)
4331 continue;
4332
4333 SceneObjectPart obj = Scene.GetSceneObjectPart(localId);
4334 string data = "";
4335 if (obj != null)
4336 {
4337 DetectedObject detobj = new DetectedObject();
4338 detobj.keyUUID = obj.UUID;
4339 detobj.nameStr = obj.Name;
4340 detobj.ownerUUID = obj.OwnerID;
4341 detobj.posVector = obj.AbsolutePosition;
4342 detobj.rotQuat = obj.GetWorldRotation();
4343 detobj.velVector = obj.Velocity;
4344 detobj.colliderType = 0;
4345 detobj.groupUUID = obj.GroupID;
4346 colliding.Add(detobj);
4347 }
4348 }
4349
4350 if (colliding.Count > 0)
4351 {
4352 CollidingMessage.Colliders = colliding;
4353
4354 lock (m_attachments)
4355 {
4356 foreach (SceneObjectGroup att in m_attachments)
4357 Scene.EventManager.TriggerScriptColliding(att.LocalId, CollidingMessage);
4358 }
4359 }
4360 }
4361 }
4362 finally
4363 {
4364 m_collisionEventFlag = false;
4365 }
4366 });
4367 }
4368
4009 private void TeleportFlagsDebug() { 4369 private void TeleportFlagsDebug() {
4010 4370
4011 // Some temporary debugging help to show all the TeleportFlags we have... 4371 // Some temporary debugging help to show all the TeleportFlags we have...
@@ -4030,6 +4390,5 @@ namespace OpenSim.Region.Framework.Scenes
4030 m_log.InfoFormat("[SCENE PRESENCE]: TELEPORT ******************"); 4390 m_log.InfoFormat("[SCENE PRESENCE]: TELEPORT ******************");
4031 4391
4032 } 4392 }
4033
4034 } 4393 }
4035} 4394}
diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs
index e6b88a3..1cd8189 100644
--- a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs
+++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs
@@ -244,6 +244,12 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
244 sr.Close(); 244 sr.Close();
245 } 245 }
246 246
247 XmlNodeList keymotion = doc.GetElementsByTagName("KeyframeMotion");
248 if (keymotion.Count > 0)
249 sceneObject.RootPart.KeyframeMotion = KeyframeMotion.FromData(sceneObject, Convert.FromBase64String(keymotion[0].InnerText));
250 else
251 sceneObject.RootPart.KeyframeMotion = null;
252
247 // Script state may, or may not, exist. Not having any, is NOT 253 // Script state may, or may not, exist. Not having any, is NOT
248 // ever a problem. 254 // ever a problem.
249 sceneObject.LoadScriptState(doc); 255 sceneObject.LoadScriptState(doc);
@@ -347,6 +353,21 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
347 m_SOPXmlProcessors.Add("PayPrice2", ProcessPayPrice2); 353 m_SOPXmlProcessors.Add("PayPrice2", ProcessPayPrice2);
348 m_SOPXmlProcessors.Add("PayPrice3", ProcessPayPrice3); 354 m_SOPXmlProcessors.Add("PayPrice3", ProcessPayPrice3);
349 m_SOPXmlProcessors.Add("PayPrice4", ProcessPayPrice4); 355 m_SOPXmlProcessors.Add("PayPrice4", ProcessPayPrice4);
356
357 m_SOPXmlProcessors.Add("Buoyancy", ProcessBuoyancy);
358 m_SOPXmlProcessors.Add("Force", ProcessForce);
359 m_SOPXmlProcessors.Add("Torque", ProcessTorque);
360 m_SOPXmlProcessors.Add("VolumeDetectActive", ProcessVolumeDetectActive);
361
362
363 m_SOPXmlProcessors.Add("Vehicle", ProcessVehicle);
364
365 m_SOPXmlProcessors.Add("PhysicsShapeType", ProcessPhysicsShapeType);
366 m_SOPXmlProcessors.Add("Density", ProcessDensity);
367 m_SOPXmlProcessors.Add("Friction", ProcessFriction);
368 m_SOPXmlProcessors.Add("Bounce", ProcessBounce);
369 m_SOPXmlProcessors.Add("GravityModifier", ProcessGravityModifier);
370
350 #endregion 371 #endregion
351 372
352 #region TaskInventoryXmlProcessors initialization 373 #region TaskInventoryXmlProcessors initialization
@@ -374,7 +395,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
374 m_TaskInventoryXmlProcessors.Add("PermsMask", ProcessTIPermsMask); 395 m_TaskInventoryXmlProcessors.Add("PermsMask", ProcessTIPermsMask);
375 m_TaskInventoryXmlProcessors.Add("Type", ProcessTIType); 396 m_TaskInventoryXmlProcessors.Add("Type", ProcessTIType);
376 m_TaskInventoryXmlProcessors.Add("OwnerChanged", ProcessTIOwnerChanged); 397 m_TaskInventoryXmlProcessors.Add("OwnerChanged", ProcessTIOwnerChanged);
377 398
378 #endregion 399 #endregion
379 400
380 #region ShapeXmlProcessors initialization 401 #region ShapeXmlProcessors initialization
@@ -569,6 +590,49 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
569 obj.ClickAction = (byte)reader.ReadElementContentAsInt("ClickAction", String.Empty); 590 obj.ClickAction = (byte)reader.ReadElementContentAsInt("ClickAction", String.Empty);
570 } 591 }
571 592
593 private static void ProcessPhysicsShapeType(SceneObjectPart obj, XmlTextReader reader)
594 {
595 obj.PhysicsShapeType = (byte)reader.ReadElementContentAsInt("PhysicsShapeType", String.Empty);
596 }
597
598 private static void ProcessDensity(SceneObjectPart obj, XmlTextReader reader)
599 {
600 obj.Density = reader.ReadElementContentAsFloat("Density", String.Empty);
601 }
602
603 private static void ProcessFriction(SceneObjectPart obj, XmlTextReader reader)
604 {
605 obj.Friction = reader.ReadElementContentAsFloat("Friction", String.Empty);
606 }
607
608 private static void ProcessBounce(SceneObjectPart obj, XmlTextReader reader)
609 {
610 obj.Bounciness = reader.ReadElementContentAsFloat("Bounce", String.Empty);
611 }
612
613 private static void ProcessGravityModifier(SceneObjectPart obj, XmlTextReader reader)
614 {
615 obj.GravityModifier = reader.ReadElementContentAsFloat("GravityModifier", String.Empty);
616 }
617
618 private static void ProcessVehicle(SceneObjectPart obj, XmlTextReader reader)
619 {
620 bool errors = false;
621 SOPVehicle _vehicle = new SOPVehicle();
622
623 _vehicle.FromXml2(reader, out errors);
624
625 if (errors)
626 {
627 obj.sopVehicle = null;
628 m_log.DebugFormat(
629 "[SceneObjectSerializer]: Parsing Vehicle for object part {0} {1} encountered errors. Please see earlier log entries.",
630 obj.Name, obj.UUID);
631 }
632 else
633 obj.sopVehicle = _vehicle;
634 }
635
572 private static void ProcessShape(SceneObjectPart obj, XmlTextReader reader) 636 private static void ProcessShape(SceneObjectPart obj, XmlTextReader reader)
573 { 637 {
574 List<string> errorNodeNames; 638 List<string> errorNodeNames;
@@ -733,6 +797,25 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
733 obj.PayPrice[4] = (int)reader.ReadElementContentAsInt("PayPrice4", String.Empty); 797 obj.PayPrice[4] = (int)reader.ReadElementContentAsInt("PayPrice4", String.Empty);
734 } 798 }
735 799
800 private static void ProcessBuoyancy(SceneObjectPart obj, XmlTextReader reader)
801 {
802 obj.Buoyancy = (float)reader.ReadElementContentAsFloat("Buoyancy", String.Empty);
803 }
804
805 private static void ProcessForce(SceneObjectPart obj, XmlTextReader reader)
806 {
807 obj.Force = Util.ReadVector(reader, "Force");
808 }
809 private static void ProcessTorque(SceneObjectPart obj, XmlTextReader reader)
810 {
811 obj.Torque = Util.ReadVector(reader, "Torque");
812 }
813
814 private static void ProcessVolumeDetectActive(SceneObjectPart obj, XmlTextReader reader)
815 {
816 obj.VolumeDetectActive = Util.ReadBoolean(reader);
817 }
818
736 #endregion 819 #endregion
737 820
738 #region TaskInventoryXmlProcessors 821 #region TaskInventoryXmlProcessors
@@ -1120,6 +1203,16 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
1120 }); 1203 });
1121 1204
1122 writer.WriteEndElement(); 1205 writer.WriteEndElement();
1206
1207 if (sog.RootPart.KeyframeMotion != null)
1208 {
1209 Byte[] data = sog.RootPart.KeyframeMotion.Serialize();
1210
1211 writer.WriteStartElement(String.Empty, "KeyframeMotion", String.Empty);
1212 writer.WriteBase64(data, 0, data.Length);
1213 writer.WriteEndElement();
1214 }
1215
1123 writer.WriteEndElement(); 1216 writer.WriteEndElement();
1124 } 1217 }
1125 1218
@@ -1218,6 +1311,27 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
1218 writer.WriteElementString("PayPrice3", sop.PayPrice[3].ToString()); 1311 writer.WriteElementString("PayPrice3", sop.PayPrice[3].ToString());
1219 writer.WriteElementString("PayPrice4", sop.PayPrice[4].ToString()); 1312 writer.WriteElementString("PayPrice4", sop.PayPrice[4].ToString());
1220 1313
1314 writer.WriteElementString("Buoyancy", sop.Buoyancy.ToString());
1315
1316 WriteVector(writer, "Force", sop.Force);
1317 WriteVector(writer, "Torque", sop.Torque);
1318
1319 writer.WriteElementString("VolumeDetectActive", sop.VolumeDetectActive.ToString().ToLower());
1320
1321 if (sop.sopVehicle != null)
1322 sop.sopVehicle.ToXml2(writer);
1323
1324 if(sop.PhysicsShapeType != sop.DefaultPhysicsShapeType())
1325 writer.WriteElementString("PhysicsShapeType", sop.PhysicsShapeType.ToString().ToLower());
1326 if (sop.Density != 1000.0f)
1327 writer.WriteElementString("Density", sop.Density.ToString().ToLower());
1328 if (sop.Friction != 0.6f)
1329 writer.WriteElementString("Friction", sop.Friction.ToString().ToLower());
1330 if (sop.Bounciness != 0.5f)
1331 writer.WriteElementString("Bounce", sop.Bounciness.ToString().ToLower());
1332 if (sop.GravityModifier != 1.0f)
1333 writer.WriteElementString("GravityModifier", sop.GravityModifier.ToString().ToLower());
1334
1221 writer.WriteEndElement(); 1335 writer.WriteEndElement();
1222 } 1336 }
1223 1337
@@ -1487,12 +1601,6 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
1487 { 1601 {
1488 TaskInventoryDictionary tinv = new TaskInventoryDictionary(); 1602 TaskInventoryDictionary tinv = new TaskInventoryDictionary();
1489 1603
1490 if (reader.IsEmptyElement)
1491 {
1492 reader.Read();
1493 return tinv;
1494 }
1495
1496 reader.ReadStartElement(name, String.Empty); 1604 reader.ReadStartElement(name, String.Empty);
1497 1605
1498 while (reader.Name == "TaskInventoryItem") 1606 while (reader.Name == "TaskInventoryItem")
diff --git a/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs b/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs
index 5c56264..94f1b15 100644
--- a/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs
+++ b/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs
@@ -75,7 +75,20 @@ namespace OpenSim.Region.Framework.Scenes
75 OutPacketsPerSecond = 18, 75 OutPacketsPerSecond = 18,
76 PendingDownloads = 19, 76 PendingDownloads = 19,
77 PendingUploads = 20, 77 PendingUploads = 20,
78 VirtualSizeKB = 21,
79 ResidentSizeKB = 22,
80 PendingLocalUploads = 23,
78 UnAckedBytes = 24, 81 UnAckedBytes = 24,
82 PhysicsPinnedTasks = 25,
83 PhysicsLODTasks = 26,
84 PhysicsStepMS = 27,
85 PhysicsShapeMS = 28,
86 PhysicsOtherMS = 29,
87 PhysicsMemory = 30,
88 ScriptEPS = 31,
89 SimSpareTime = 32,
90 SimSleepTime = 33,
91 IOPumpTime = 34
79 } 92 }
80 93
81 /// <summary> 94 /// <summary>
@@ -123,7 +136,7 @@ namespace OpenSim.Region.Framework.Scenes
123 136
124 // saved last reported value so there is something available for llGetRegionFPS 137 // saved last reported value so there is something available for llGetRegionFPS
125 private float lastReportedSimFPS = 0; 138 private float lastReportedSimFPS = 0;
126 private float[] lastReportedSimStats = new float[21]; 139 private float[] lastReportedSimStats = new float[23];
127 private float m_pfps = 0; 140 private float m_pfps = 0;
128 141
129 /// <summary> 142 /// <summary>
@@ -142,6 +155,8 @@ namespace OpenSim.Region.Framework.Scenes
142 private int m_physicsMS = 0; 155 private int m_physicsMS = 0;
143 private int m_imageMS = 0; 156 private int m_imageMS = 0;
144 private int m_otherMS = 0; 157 private int m_otherMS = 0;
158 private int m_sleeptimeMS = 0;
159
145 160
146//Ckrinke: (3-21-08) Comment out to remove a compiler warning. Bring back into play when needed. 161//Ckrinke: (3-21-08) Comment out to remove a compiler warning. Bring back into play when needed.
147//Ckrinke private int m_scriptMS = 0; 162//Ckrinke private int m_scriptMS = 0;
@@ -200,7 +215,7 @@ namespace OpenSim.Region.Framework.Scenes
200 215
201 private void statsHeartBeat(object sender, EventArgs e) 216 private void statsHeartBeat(object sender, EventArgs e)
202 { 217 {
203 SimStatsPacket.StatBlock[] sb = new SimStatsPacket.StatBlock[21]; 218 SimStatsPacket.StatBlock[] sb = new SimStatsPacket.StatBlock[23];
204 SimStatsPacket.RegionBlock rb = new SimStatsPacket.RegionBlock(); 219 SimStatsPacket.RegionBlock rb = new SimStatsPacket.RegionBlock();
205 220
206 // Know what's not thread safe in Mono... modifying timers. 221 // Know what's not thread safe in Mono... modifying timers.
@@ -238,18 +253,38 @@ namespace OpenSim.Region.Framework.Scenes
238 physfps = 0; 253 physfps = 0;
239 254
240#endregion 255#endregion
256 float factor = 1 / statsUpdateFactor;
257 if (reportedFPS <= 0)
258 reportedFPS = 1;
259
260 float perframe = 1.0f / (float)reportedFPS;
261
262 float TotalFrameTime = m_frameMS * perframe;
263
264 float targetframetime = 1100.0f / (float)m_nominalReportedFps;
265
266 float sparetime;
267 if (TotalFrameTime > targetframetime )
268 sparetime = 0;
269 else
270 {
271 sparetime = m_frameMS - m_physicsMS - m_agentMS;
272 sparetime *= perframe;
273 if (sparetime < 0)
274 sparetime = 0;
275 else if (sparetime > TotalFrameTime)
276 sparetime = TotalFrameTime;
277 }
241 278
242 //Our time dilation is 0.91 when we're running a full speed, 279 // other MS is actually simulation time
243 // therefore to make sure we get an appropriate range, 280 // m_otherMS = m_frameMS - m_physicsMS - m_imageMS - m_netMS - m_agentMS;
244 // we have to factor in our error. (0.10f * statsUpdateFactor) 281 // m_imageMS m_netMS are not included in m_frameMS
245 // multiplies the fix for the error times the amount of times it'll occur a second
246 // / 10 divides the value by the number of times the sim heartbeat runs (10fps)
247 // Then we divide the whole amount by the amount of seconds pass in between stats updates.
248 282
249 // 'statsUpdateFactor' is how often stats packets are sent in seconds. Used below to change 283 m_otherMS = m_frameMS - m_physicsMS - m_agentMS - m_sleeptimeMS;
250 // values to X-per-second values. 284 if (m_otherMS < 0)
285 m_otherMS = 0;
251 286
252 for (int i = 0; i < 21; i++) 287 for (int i = 0; i < 23; i++)
253 { 288 {
254 sb[i] = new SimStatsPacket.StatBlock(); 289 sb[i] = new SimStatsPacket.StatBlock();
255 } 290 }
@@ -279,19 +314,25 @@ namespace OpenSim.Region.Framework.Scenes
279 sb[7].StatValue = m_activePrim; 314 sb[7].StatValue = m_activePrim;
280 315
281 sb[8].StatID = (uint)Stats.FrameMS; 316 sb[8].StatID = (uint)Stats.FrameMS;
282 sb[8].StatValue = m_frameMS / statsUpdateFactor; 317 // sb[8].StatValue = m_frameMS / statsUpdateFactor;
318 sb[8].StatValue = TotalFrameTime;
283 319
284 sb[9].StatID = (uint)Stats.NetMS; 320 sb[9].StatID = (uint)Stats.NetMS;
285 sb[9].StatValue = m_netMS / statsUpdateFactor; 321 // sb[9].StatValue = m_netMS / statsUpdateFactor;
322 sb[9].StatValue = m_netMS * perframe;
286 323
287 sb[10].StatID = (uint)Stats.PhysicsMS; 324 sb[10].StatID = (uint)Stats.PhysicsMS;
288 sb[10].StatValue = m_physicsMS / statsUpdateFactor; 325 // sb[10].StatValue = m_physicsMS / statsUpdateFactor;
326 sb[10].StatValue = m_physicsMS * perframe;
289 327
290 sb[11].StatID = (uint)Stats.ImageMS ; 328 sb[11].StatID = (uint)Stats.ImageMS ;
291 sb[11].StatValue = m_imageMS / statsUpdateFactor; 329 // sb[11].StatValue = m_imageMS / statsUpdateFactor;
330 sb[11].StatValue = m_imageMS * perframe;
292 331
293 sb[12].StatID = (uint)Stats.OtherMS; 332 sb[12].StatID = (uint)Stats.OtherMS;
294 sb[12].StatValue = m_otherMS / statsUpdateFactor; 333 // sb[12].StatValue = m_otherMS / statsUpdateFactor;
334 sb[12].StatValue = m_otherMS * perframe;
335
295 336
296 sb[13].StatID = (uint)Stats.InPacketsPerSecond; 337 sb[13].StatID = (uint)Stats.InPacketsPerSecond;
297 sb[13].StatValue = (m_inPacketsPerSecond / statsUpdateFactor); 338 sb[13].StatValue = (m_inPacketsPerSecond / statsUpdateFactor);
@@ -303,7 +344,8 @@ namespace OpenSim.Region.Framework.Scenes
303 sb[15].StatValue = m_unAckedBytes; 344 sb[15].StatValue = m_unAckedBytes;
304 345
305 sb[16].StatID = (uint)Stats.AgentMS; 346 sb[16].StatID = (uint)Stats.AgentMS;
306 sb[16].StatValue = m_agentMS / statsUpdateFactor; 347// sb[16].StatValue = m_agentMS / statsUpdateFactor;
348 sb[16].StatValue = m_agentMS * perframe;
307 349
308 sb[17].StatID = (uint)Stats.PendingDownloads; 350 sb[17].StatID = (uint)Stats.PendingDownloads;
309 sb[17].StatValue = m_pendingDownloads; 351 sb[17].StatValue = m_pendingDownloads;
@@ -316,8 +358,14 @@ namespace OpenSim.Region.Framework.Scenes
316 358
317 sb[20].StatID = (uint)Stats.ScriptLinesPerSecond; 359 sb[20].StatID = (uint)Stats.ScriptLinesPerSecond;
318 sb[20].StatValue = m_scriptLinesPerSecond / statsUpdateFactor; 360 sb[20].StatValue = m_scriptLinesPerSecond / statsUpdateFactor;
319 361
320 for (int i = 0; i < 21; i++) 362 sb[21].StatID = (uint)Stats.SimSpareTime;
363 sb[21].StatValue = sparetime;
364
365 sb[22].StatID = (uint)Stats.SimSleepTime;
366 sb[22].StatValue = m_sleeptimeMS * perframe;
367
368 for (int i = 0; i < 23; i++)
321 { 369 {
322 lastReportedSimStats[i] = sb[i].StatValue; 370 lastReportedSimStats[i] = sb[i].StatValue;
323 } 371 }
@@ -358,6 +406,7 @@ namespace OpenSim.Region.Framework.Scenes
358 m_physicsMS = 0; 406 m_physicsMS = 0;
359 m_imageMS = 0; 407 m_imageMS = 0;
360 m_otherMS = 0; 408 m_otherMS = 0;
409 m_sleeptimeMS = 0;
361 410
362//Ckrinke This variable is not used, so comment to remove compiler warning until it is used. 411//Ckrinke This variable is not used, so comment to remove compiler warning until it is used.
363//Ckrinke m_scriptMS = 0; 412//Ckrinke m_scriptMS = 0;
@@ -484,6 +533,11 @@ namespace OpenSim.Region.Framework.Scenes
484 m_otherMS += ms; 533 m_otherMS += ms;
485 } 534 }
486 535
536 public void addSleepMS(int ms)
537 {
538 m_sleeptimeMS += ms;
539 }
540
487 public void AddPendingDownloads(int count) 541 public void AddPendingDownloads(int count)
488 { 542 {
489 m_pendingDownloads += count; 543 m_pendingDownloads += count;
diff --git a/OpenSim/Region/Framework/Scenes/UndoState.cs b/OpenSim/Region/Framework/Scenes/UndoState.cs
index 860172c..7bbf1bd 100644
--- a/OpenSim/Region/Framework/Scenes/UndoState.cs
+++ b/OpenSim/Region/Framework/Scenes/UndoState.cs
@@ -27,202 +27,307 @@
27 27
28using System; 28using System;
29using System.Reflection; 29using System.Reflection;
30using System.Collections.Generic;
30using log4net; 31using log4net;
31using OpenMetaverse; 32using OpenMetaverse;
33using OpenSim.Framework;
32using OpenSim.Region.Framework.Interfaces; 34using OpenSim.Region.Framework.Interfaces;
33 35
34namespace OpenSim.Region.Framework.Scenes 36namespace OpenSim.Region.Framework.Scenes
35{ 37{
36 public class UndoState 38 public class UndoState
37 { 39 {
38// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 40 const int UNDOEXPIRESECONDS = 300; // undo expire time (nice to have it came from a ini later)
39
40 public Vector3 Position = Vector3.Zero;
41 public Vector3 Scale = Vector3.Zero;
42 public Quaternion Rotation = Quaternion.Identity;
43
44 /// <summary>
45 /// Is this undo state for an entire group?
46 /// </summary>
47 public bool ForGroup;
48 41
42 public ObjectChangeData data;
43 public DateTime creationtime;
49 /// <summary> 44 /// <summary>
50 /// Constructor. 45 /// Constructor.
51 /// </summary> 46 /// </summary>
52 /// <param name="part"></param> 47 /// <param name="part"></param>
53 /// <param name="forGroup">True if the undo is for an entire group</param> 48 /// <param name="change">bit field with what is changed</param>
54 public UndoState(SceneObjectPart part, bool forGroup) 49 ///
50 public UndoState(SceneObjectPart part, ObjectChangeType change)
55 { 51 {
56 if (part.ParentID == 0) 52 data = new ObjectChangeData();
57 { 53 data.change = change;
58 ForGroup = forGroup; 54 creationtime = DateTime.UtcNow;
59
60// if (ForGroup)
61 Position = part.ParentGroup.AbsolutePosition;
62// else
63// Position = part.OffsetPosition;
64
65// m_log.DebugFormat(
66// "[UNDO STATE]: Storing undo position {0} for root part", Position);
67 55
68 Rotation = part.RotationOffset; 56 if (part.ParentGroup.RootPart == part)
69 57 {
70// m_log.DebugFormat( 58 if ((change & ObjectChangeType.Position) != 0)
71// "[UNDO STATE]: Storing undo rotation {0} for root part", Rotation); 59 data.position = part.ParentGroup.AbsolutePosition;
72 60 if ((change & ObjectChangeType.Rotation) != 0)
73 Scale = part.Shape.Scale; 61 data.rotation = part.RotationOffset;
74 62 if ((change & ObjectChangeType.Scale) != 0)
75// m_log.DebugFormat( 63 data.scale = part.Shape.Scale;
76// "[UNDO STATE]: Storing undo scale {0} for root part", Scale);
77 } 64 }
78 else 65 else
79 { 66 {
80 Position = part.OffsetPosition; 67 if ((change & ObjectChangeType.Position) != 0)
81// m_log.DebugFormat( 68 data.position = part.OffsetPosition;
82// "[UNDO STATE]: Storing undo position {0} for child part", Position); 69 if ((change & ObjectChangeType.Rotation) != 0)
70 data.rotation = part.RotationOffset;
71 if ((change & ObjectChangeType.Scale) != 0)
72 data.scale = part.Shape.Scale;
73 }
74 }
75 /// <summary>
76 /// check if undo or redo is too old
77 /// </summary>
83 78
84 Rotation = part.RotationOffset; 79 public bool checkExpire()
85// m_log.DebugFormat( 80 {
86// "[UNDO STATE]: Storing undo rotation {0} for child part", Rotation); 81 TimeSpan t = DateTime.UtcNow - creationtime;
82 if (t.Seconds > UNDOEXPIRESECONDS)
83 return true;
84 return false;
85 }
87 86
88 Scale = part.Shape.Scale; 87 /// <summary>
89// m_log.DebugFormat( 88 /// updates undo or redo creation time to now
90// "[UNDO STATE]: Storing undo scale {0} for child part", Scale); 89 /// </summary>
91 } 90 public void updateExpire()
91 {
92 creationtime = DateTime.UtcNow;
92 } 93 }
93 94
94 /// <summary> 95 /// <summary>
95 /// Compare the relevant state in the given part to this state. 96 /// Compare the relevant state in the given part to this state.
96 /// </summary> 97 /// </summary>
97 /// <param name="part"></param> 98 /// <param name="part"></param>
98 /// <returns>true if both the part's position, rotation and scale match those in this undo state. False otherwise.</returns> 99 /// <returns>true what fiels and related data are equal, False otherwise.</returns>
99 public bool Compare(SceneObjectPart part) 100 ///
101 public bool Compare(SceneObjectPart part, ObjectChangeType change)
100 { 102 {
103 if (data.change != change) // if diferent targets, then they are diferent
104 return false;
105
101 if (part != null) 106 if (part != null)
102 { 107 {
103 if (part.ParentID == 0) 108 if (part.ParentID == 0)
104 return 109 {
105 Position == part.ParentGroup.AbsolutePosition 110 if ((change & ObjectChangeType.Position) != 0 && data.position != part.ParentGroup.AbsolutePosition)
106 && Rotation == part.RotationOffset 111 return false;
107 && Scale == part.Shape.Scale; 112 }
108 else 113 else
109 return 114 {
110 Position == part.OffsetPosition 115 if ((change & ObjectChangeType.Position) != 0 && data.position != part.OffsetPosition)
111 && Rotation == part.RotationOffset 116 return false;
112 && Scale == part.Shape.Scale; 117 }
113 } 118
119 if ((change & ObjectChangeType.Rotation) != 0 && data.rotation != part.RotationOffset)
120 return false;
121 if ((change & ObjectChangeType.Rotation) != 0 && data.scale == part.Shape.Scale)
122 return false;
123 return true;
114 124
125 }
115 return false; 126 return false;
116 } 127 }
117 128
118 public void PlaybackState(SceneObjectPart part) 129 /// <summary>
130 /// executes the undo or redo to a part or its group
131 /// </summary>
132 /// <param name="part"></param>
133 ///
134
135 public void PlayState(SceneObjectPart part)
119 { 136 {
120 part.Undoing = true; 137 part.Undoing = true;
121 138
122 if (part.ParentID == 0) 139 SceneObjectGroup grp = part.ParentGroup;
123 {
124// m_log.DebugFormat(
125// "[UNDO STATE]: Undoing position to {0} for root part {1} {2}",
126// Position, part.Name, part.LocalId);
127 140
128 if (Position != Vector3.Zero) 141 if (grp != null)
129 { 142 {
130 if (ForGroup) 143 grp.doChangeObject(part, data);
131 part.ParentGroup.AbsolutePosition = Position; 144 }
132 else 145 part.Undoing = false;
133 part.ParentGroup.UpdateRootPosition(Position); 146 }
134 } 147 }
135 148
136// m_log.DebugFormat( 149 public class UndoRedoState
137// "[UNDO STATE]: Undoing rotation {0} to {1} for root part {2} {3}", 150 {
138// part.RotationOffset, Rotation, part.Name, part.LocalId); 151 int size;
152 public LinkedList<UndoState> m_redo = new LinkedList<UndoState>();
153 public LinkedList<UndoState> m_undo = new LinkedList<UndoState>();
139 154
140 if (ForGroup) 155 /// <summary>
141 part.UpdateRotation(Rotation); 156 /// creates a new UndoRedoState with default states memory size
142 else 157 /// </summary>
143 part.ParentGroup.UpdateRootRotation(Rotation);
144 158
145 if (Scale != Vector3.Zero) 159 public UndoRedoState()
146 { 160 {
147// m_log.DebugFormat( 161 size = 5;
148// "[UNDO STATE]: Undoing scale {0} to {1} for root part {2} {3}", 162 }
149// part.Shape.Scale, Scale, part.Name, part.LocalId);
150 163
151 if (ForGroup) 164 /// <summary>
152 part.ParentGroup.GroupResize(Scale); 165 /// creates a new UndoRedoState with states memory having indicated size
153 else 166 /// </summary>
154 part.Resize(Scale); 167 /// <param name="size"></param>
155 }
156 168
157 part.ParentGroup.ScheduleGroupForTerseUpdate(); 169 public UndoRedoState(int _size)
158 } 170 {
171 if (_size < 3)
172 size = 3;
159 else 173 else
160 { 174 size = _size;
161 // Note: Updating these properties on sop automatically schedules an update if needed 175 }
162 if (Position != Vector3.Zero)
163 {
164// m_log.DebugFormat(
165// "[UNDO STATE]: Undoing position {0} to {1} for child part {2} {3}",
166// part.OffsetPosition, Position, part.Name, part.LocalId);
167 176
168 part.OffsetPosition = Position; 177 /// <summary>
169 } 178 /// returns number of undo entries in memory
179 /// </summary>
170 180
171// m_log.DebugFormat( 181 public int Count
172// "[UNDO STATE]: Undoing rotation {0} to {1} for child part {2} {3}", 182 {
173// part.RotationOffset, Rotation, part.Name, part.LocalId); 183 get { return m_undo.Count; }
184 }
174 185
175 part.UpdateRotation(Rotation); 186 /// <summary>
187 /// clears all undo and redo entries
188 /// </summary>
176 189
177 if (Scale != Vector3.Zero) 190 public void Clear()
191 {
192 m_undo.Clear();
193 m_redo.Clear();
194 }
195
196 /// <summary>
197 /// adds a new state undo to part or its group, with changes indicated by what bits
198 /// </summary>
199 /// <param name="part"></param>
200 /// <param name="change">bit field with what is changed</param>
201
202 public void StoreUndo(SceneObjectPart part, ObjectChangeType change)
203 {
204 lock (m_undo)
205 {
206 UndoState last;
207
208 if (m_redo.Count > 0) // last code seems to clear redo on every new undo
178 { 209 {
179// m_log.DebugFormat( 210 m_redo.Clear();
180// "[UNDO STATE]: Undoing scale {0} to {1} for child part {2} {3}", 211 }
181// part.Shape.Scale, Scale, part.Name, part.LocalId);
182 212
183 part.Resize(Scale); 213 if (m_undo.Count > 0)
214 {
215 // check expired entry
216 last = m_undo.First.Value;
217 if (last != null && last.checkExpire())
218 m_undo.Clear();
219 else
220 {
221 // see if we actually have a change
222 if (last != null)
223 {
224 if (last.Compare(part, change))
225 return;
226 }
227 }
184 } 228 }
185 }
186 229
187 part.Undoing = false; 230 // limite size
231 while (m_undo.Count >= size)
232 m_undo.RemoveLast();
233
234 UndoState nUndo = new UndoState(part, change);
235 m_undo.AddFirst(nUndo);
236 }
188 } 237 }
189 238
190 public void PlayfwdState(SceneObjectPart part) 239 /// <summary>
191 { 240 /// executes last state undo to part or its group
192 part.Undoing = true; 241 /// current state is pushed into redo
242 /// </summary>
243 /// <param name="part"></param>
193 244
194 if (part.ParentID == 0) 245 public void Undo(SceneObjectPart part)
246 {
247 lock (m_undo)
195 { 248 {
196 if (Position != Vector3.Zero) 249 UndoState nUndo;
197 part.ParentGroup.AbsolutePosition = Position;
198
199 if (Rotation != Quaternion.Identity)
200 part.UpdateRotation(Rotation);
201 250
202 if (Scale != Vector3.Zero) 251 // expire redo
252 if (m_redo.Count > 0)
203 { 253 {
204 if (ForGroup) 254 nUndo = m_redo.First.Value;
205 part.ParentGroup.GroupResize(Scale); 255 if (nUndo != null && nUndo.checkExpire())
206 else 256 m_redo.Clear();
207 part.Resize(Scale);
208 } 257 }
209 258
210 part.ParentGroup.ScheduleGroupForTerseUpdate(); 259 if (m_undo.Count > 0)
260 {
261 UndoState goback = m_undo.First.Value;
262 // check expired
263 if (goback != null && goback.checkExpire())
264 {
265 m_undo.Clear();
266 return;
267 }
268
269 if (goback != null)
270 {
271 m_undo.RemoveFirst();
272
273 // redo limite size
274 while (m_redo.Count >= size)
275 m_redo.RemoveLast();
276
277 nUndo = new UndoState(part, goback.data.change); // new value in part should it be full goback copy?
278 m_redo.AddFirst(nUndo);
279
280 goback.PlayState(part);
281 }
282 }
211 } 283 }
212 else 284 }
285
286 /// <summary>
287 /// executes last state redo to part or its group
288 /// current state is pushed into undo
289 /// </summary>
290 /// <param name="part"></param>
291
292 public void Redo(SceneObjectPart part)
293 {
294 lock (m_undo)
213 { 295 {
214 // Note: Updating these properties on sop automatically schedules an update if needed 296 UndoState nUndo;
215 if (Position != Vector3.Zero)
216 part.OffsetPosition = Position;
217 297
218 if (Rotation != Quaternion.Identity) 298 // expire undo
219 part.UpdateRotation(Rotation); 299 if (m_undo.Count > 0)
300 {
301 nUndo = m_undo.First.Value;
302 if (nUndo != null && nUndo.checkExpire())
303 m_undo.Clear();
304 }
220 305
221 if (Scale != Vector3.Zero) 306 if (m_redo.Count > 0)
222 part.Resize(Scale); 307 {
308 UndoState gofwd = m_redo.First.Value;
309 // check expired
310 if (gofwd != null && gofwd.checkExpire())
311 {
312 m_redo.Clear();
313 return;
314 }
315
316 if (gofwd != null)
317 {
318 m_redo.RemoveFirst();
319
320 // limite undo size
321 while (m_undo.Count >= size)
322 m_undo.RemoveLast();
323
324 nUndo = new UndoState(part, gofwd.data.change); // new value in part should it be full gofwd copy?
325 m_undo.AddFirst(nUndo);
326
327 gofwd.PlayState(part);
328 }
329 }
223 } 330 }
224
225 part.Undoing = false;
226 } 331 }
227 } 332 }
228 333
@@ -247,4 +352,4 @@ namespace OpenSim.Region.Framework.Scenes
247 m_terrainModule.UndoTerrain(m_terrainChannel); 352 m_terrainModule.UndoTerrain(m_terrainChannel);
248 } 353 }
249 } 354 }
250} \ No newline at end of file 355}
diff --git a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs
index efb68a2..411e421 100644
--- a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs
+++ b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs
@@ -87,10 +87,6 @@ namespace OpenSim.Region.Framework.Scenes
87 /// <param name="assetUuids">The assets gathered</param> 87 /// <param name="assetUuids">The assets gathered</param>
88 public void GatherAssetUuids(UUID assetUuid, AssetType assetType, IDictionary<UUID, AssetType> assetUuids) 88 public void GatherAssetUuids(UUID assetUuid, AssetType assetType, IDictionary<UUID, AssetType> assetUuids)
89 { 89 {
90 // avoid infinite loops
91 if (assetUuids.ContainsKey(assetUuid))
92 return;
93
94 try 90 try
95 { 91 {
96 assetUuids[assetUuid] = assetType; 92 assetUuids[assetUuid] = assetType;