aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
diff options
context:
space:
mode:
authorTom2011-09-04 07:54:17 -0700
committerTom2011-09-04 07:54:17 -0700
commitaf59352c4c6b1b49151c009058d867f5ccca3010 (patch)
tree2ba47f225516771cacc02979cd2c651037207bff /OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
parentI fucked up the merge for SOG, so reverting back to OpenSim Core's version... (diff)
downloadopensim-SC-af59352c4c6b1b49151c009058d867f5ccca3010.zip
opensim-SC-af59352c4c6b1b49151c009058d867f5ccca3010.tar.gz
opensim-SC-af59352c4c6b1b49151c009058d867f5ccca3010.tar.bz2
opensim-SC-af59352c4c6b1b49151c009058d867f5ccca3010.tar.xz
Change of tactic. Reverting this to the careminster version, then i'll selectively merge the changes made to core.
Diffstat (limited to 'OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs')
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs1752
1 files changed, 1117 insertions, 635 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 5762717..6c47645 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;
@@ -105,8 +106,29 @@ namespace OpenSim.Region.Framework.Scenes
105 /// since the group's last persistent backup 106 /// since the group's last persistent backup
106 /// </summary> 107 /// </summary>
107 private bool m_hasGroupChanged = false; 108 private bool m_hasGroupChanged = false;
108 private long timeFirstChanged; 109 private long timeFirstChanged = 0;
109 private long timeLastChanged; 110 private long timeLastChanged = 0;
111 private long m_maxPersistTime = 0;
112 private long m_minPersistTime = 0;
113 private Random m_rand;
114 private bool m_suspendUpdates;
115 private List<ScenePresence> m_linkedAvatars = new List<ScenePresence>();
116
117 public bool areUpdatesSuspended
118 {
119 get
120 {
121 return m_suspendUpdates;
122 }
123 set
124 {
125 m_suspendUpdates = value;
126 if (!value)
127 {
128 QueueForUpdateCheck();
129 }
130 }
131 }
110 132
111 public bool HasGroupChanged 133 public bool HasGroupChanged
112 { 134 {
@@ -114,24 +136,54 @@ namespace OpenSim.Region.Framework.Scenes
114 { 136 {
115 if (value) 137 if (value)
116 { 138 {
139 if (m_isBackedUp)
140 {
141 m_scene.SceneGraph.FireChangeBackup(this);
142 }
117 timeLastChanged = DateTime.Now.Ticks; 143 timeLastChanged = DateTime.Now.Ticks;
118 if (!m_hasGroupChanged) 144 if (!m_hasGroupChanged)
119 timeFirstChanged = DateTime.Now.Ticks; 145 timeFirstChanged = DateTime.Now.Ticks;
146 if (m_rootPart != null && m_rootPart.UUID != null && m_scene != null)
147 {
148 if (m_rand == null)
149 {
150 byte[] val = new byte[16];
151 m_rootPart.UUID.ToBytes(val, 0);
152 m_rand = new Random(BitConverter.ToInt32(val, 0));
153 }
154
155 if (m_scene.GetRootAgentCount() == 0)
156 {
157 //If the region is empty, this change has been made by an automated process
158 //and thus we delay the persist time by a random amount between 1.5 and 2.5.
159
160 float factor = 1.5f + (float)(m_rand.NextDouble());
161 m_maxPersistTime = (long)((float)m_scene.m_persistAfter * factor);
162 m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * factor);
163 }
164 else
165 {
166 //If the region is not empty, we want to obey the minimum and maximum persist times
167 //but add a random factor so we stagger the object persistance a little
168 m_maxPersistTime = (long)((float)m_scene.m_persistAfter * (1.0d - (m_rand.NextDouble() / 5.0d))); //Multiply by 1.0-1.5
169 m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * (1.0d + (m_rand.NextDouble() / 2.0d))); //Multiply by 0.8-1.0
170 }
171 }
120 } 172 }
121 m_hasGroupChanged = value; 173 m_hasGroupChanged = value;
122 174
123 // m_log.DebugFormat( 175// m_log.DebugFormat(
124 // "[SCENE OBJECT GROUP]: HasGroupChanged set to {0} for {1} {2}", m_hasGroupChanged, Name, LocalId); 176// "[SCENE OBJECT GROUP]: HasGroupChanged set to {0} for {1} {2}", m_hasGroupChanged, Name, LocalId);
125 } 177 }
126 178
127 get { return m_hasGroupChanged; } 179 get { return m_hasGroupChanged; }
128 } 180 }
129 181
130 /// <summary> 182 /// <summary>
131 /// Has the group changed due to an unlink operation? We record this in order to optimize deletion, since 183 /// 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. 184 /// an unlinked group currently has to be persisted to the database before we can perform an unlink operation.
133 /// </summary> 185 /// </summary>
134 public bool HasGroupChangedDueToDelink { get; private set; } 186 public bool HasGroupChangedDueToDelink { get; set; }
135 187
136 private bool isTimeToPersist() 188 private bool isTimeToPersist()
137 { 189 {
@@ -141,94 +193,43 @@ namespace OpenSim.Region.Framework.Scenes
141 return false; 193 return false;
142 if (m_scene.ShuttingDown) 194 if (m_scene.ShuttingDown)
143 return true; 195 return true;
196
197 if (m_minPersistTime == 0 || m_maxPersistTime == 0)
198 {
199 m_maxPersistTime = m_scene.m_persistAfter;
200 m_minPersistTime = m_scene.m_dontPersistBefore;
201 }
202
144 long currentTime = DateTime.Now.Ticks; 203 long currentTime = DateTime.Now.Ticks;
145 if (currentTime - timeLastChanged > m_scene.m_dontPersistBefore || currentTime - timeFirstChanged > m_scene.m_persistAfter) 204
205 if (timeLastChanged == 0) timeLastChanged = currentTime;
206 if (timeFirstChanged == 0) timeFirstChanged = currentTime;
207
208 if (currentTime - timeLastChanged > m_minPersistTime || currentTime - timeFirstChanged > m_maxPersistTime)
146 return true; 209 return true;
147 return false; 210 return false;
148 } 211 }
149 212
150 /// <summary> 213 /// <value>
151 /// Is this scene object acting as an attachment? 214 /// Is this scene object acting as an attachment?
152 /// </summary> 215 ///
153 public bool IsAttachment { get; set; } 216 /// We return false if the group has already been deleted.
154 217 ///
155 /// <summary> 218 /// TODO: At the moment set must be done on the part itself. There may be a case for doing it here since I
156 /// The avatar to which this scene object is attached. 219 /// presume either all or no parts in a linkset can be part of an attachment (in which
157 /// </summary> 220 /// case the value would get proprogated down into all the descendent parts).
158 /// <remarks> 221 /// </value>
159 /// If we're not attached to an avatar then this is UUID.Zero 222 public bool IsAttachment
160 /// </remarks>
161 public UUID AttachedAvatar { get; set; }
162
163 /// <summary>
164 /// Attachment point of this scene object to an avatar.
165 /// </summary>
166 /// <remarks>
167 /// 0 if we're not attached to anything
168 /// </remarks>
169 public uint AttachmentPoint
170 { 223 {
171 get 224 get
172 { 225 {
173 return m_rootPart.Shape.State; 226 if (!IsDeleted)
174 } 227 return m_rootPart.IsAttachment;
175 228
176 set 229 return false;
177 {
178 IsAttachment = value != 0;
179 m_rootPart.Shape.State = (byte)value;
180 } 230 }
181 } 231 }
182 232
183 public void ClearPartAttachmentData()
184 {
185 AttachmentPoint = 0;
186
187 // Even though we don't use child part state parameters for attachments any more, we still need to set
188 // these to zero since having them non-zero in rezzed scene objects will crash some clients. Even if
189 // we store them correctly, scene objects that we receive from elsewhere might not.
190 foreach (SceneObjectPart part in Parts)
191 part.Shape.State = 0;
192 }
193
194 /// <summary>
195 /// Is this scene object phantom?
196 /// </summary>
197 /// <remarks>
198 /// Updating must currently take place through UpdatePrimFlags()
199 /// </remarks>
200 public bool IsPhantom
201 {
202 get { return (RootPart.Flags & PrimFlags.Phantom) != 0; }
203 }
204
205 /// <summary>
206 /// Does this scene object use physics?
207 /// </summary>
208 /// <remarks>
209 /// Updating must currently take place through UpdatePrimFlags()
210 /// </remarks>
211 public bool UsesPhysics
212 {
213 get { return (RootPart.Flags & PrimFlags.TemporaryOnRez) != 0; }
214 }
215
216 /// <summary>
217 /// Is this scene object temporary?
218 /// </summary>
219 /// <remarks>
220 /// Updating must currently take place through UpdatePrimFlags()
221 /// </remarks>
222 public bool IsTemporary
223 {
224 get { return (RootPart.Flags & PrimFlags.TemporaryOnRez) != 0; }
225 }
226
227 public bool IsVolumeDetect
228 {
229 get { return RootPart.VolumeDetectActive; }
230 }
231
232 public float scriptScore; 233 public float scriptScore;
233 234
234 private Vector3 lastPhysGroupPos; 235 private Vector3 lastPhysGroupPos;
@@ -247,10 +248,10 @@ namespace OpenSim.Region.Framework.Scenes
247 248
248 private bool m_scriptListens_atTarget; 249 private bool m_scriptListens_atTarget;
249 private bool m_scriptListens_notAtTarget; 250 private bool m_scriptListens_notAtTarget;
250
251 private bool m_scriptListens_atRotTarget; 251 private bool m_scriptListens_atRotTarget;
252 private bool m_scriptListens_notAtRotTarget; 252 private bool m_scriptListens_notAtRotTarget;
253 253
254 public bool m_dupeInProgress = false;
254 internal Dictionary<UUID, string> m_savedScriptState; 255 internal Dictionary<UUID, string> m_savedScriptState;
255 256
256 #region Properties 257 #region Properties
@@ -260,7 +261,11 @@ namespace OpenSim.Region.Framework.Scenes
260 /// </summary> 261 /// </summary>
261 public override string Name 262 public override string Name
262 { 263 {
263 get { return RootPart.Name; } 264 get {
265 if (RootPart == null)
266 return String.Empty;
267 return RootPart.Name;
268 }
264 set { RootPart.Name = value; } 269 set { RootPart.Name = value; }
265 } 270 }
266 271
@@ -286,7 +291,13 @@ namespace OpenSim.Region.Framework.Scenes
286 public virtual Quaternion Rotation 291 public virtual Quaternion Rotation
287 { 292 {
288 get { return m_rotation; } 293 get { return m_rotation; }
289 set { m_rotation = value; } 294 set {
295 foreach(SceneObjectPart p in m_parts.GetArray())
296 {
297 p.StoreUndoState(UndoType.STATE_GROUP_ROTATION);
298 }
299 m_rotation = value;
300 }
290 } 301 }
291 302
292 public Quaternion GroupRotation 303 public Quaternion GroupRotation
@@ -294,38 +305,6 @@ namespace OpenSim.Region.Framework.Scenes
294 get { return m_rootPart.RotationOffset; } 305 get { return m_rootPart.RotationOffset; }
295 } 306 }
296 307
297 public Vector3 GroupScale
298 {
299 get
300 {
301 Vector3 minScale = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionSize);
302 Vector3 maxScale = Vector3.Zero;
303 Vector3 finalScale = new Vector3(0.5f, 0.5f, 0.5f);
304
305 SceneObjectPart[] parts = m_parts.GetArray();
306 for (int i = 0; i < parts.Length; i++)
307 {
308 SceneObjectPart part = parts[i];
309 Vector3 partscale = part.Scale;
310 Vector3 partoffset = part.OffsetPosition;
311
312 minScale.X = (partscale.X + partoffset.X < minScale.X) ? partscale.X + partoffset.X : minScale.X;
313 minScale.Y = (partscale.Y + partoffset.Y < minScale.Y) ? partscale.Y + partoffset.Y : minScale.Y;
314 minScale.Z = (partscale.Z + partoffset.Z < minScale.Z) ? partscale.Z + partoffset.Z : minScale.Z;
315
316 maxScale.X = (partscale.X + partoffset.X > maxScale.X) ? partscale.X + partoffset.X : maxScale.X;
317 maxScale.Y = (partscale.Y + partoffset.Y > maxScale.Y) ? partscale.Y + partoffset.Y : maxScale.Y;
318 maxScale.Z = (partscale.Z + partoffset.Z > maxScale.Z) ? partscale.Z + partoffset.Z : maxScale.Z;
319 }
320
321 finalScale.X = (minScale.X > maxScale.X) ? minScale.X : maxScale.X;
322 finalScale.Y = (minScale.Y > maxScale.Y) ? minScale.Y : maxScale.Y;
323 finalScale.Z = (minScale.Z > maxScale.Z) ? minScale.Z : maxScale.Z;
324
325 return finalScale;
326 }
327 }
328
329 public UUID GroupID 308 public UUID GroupID
330 { 309 {
331 get { return m_rootPart.GroupID; } 310 get { return m_rootPart.GroupID; }
@@ -365,19 +344,17 @@ namespace OpenSim.Region.Framework.Scenes
365 /// <summary> 344 /// <summary>
366 /// Check both the attachment property and the relevant properties of the underlying root part. 345 /// Check both the attachment property and the relevant properties of the underlying root part.
367 /// </summary> 346 /// </summary>
368 /// <remarks>
369 /// This is necessary in some cases, particularly when a scene object has just crossed into a region and doesn't 347 /// This is necessary in some cases, particularly when a scene object has just crossed into a region and doesn't
370 /// have the IsAttachment property yet checked. 348 /// have the IsAttachment property yet checked.
371 /// 349 ///
372 /// FIXME: However, this should be fixed so that this property 350 /// FIXME: However, this should be fixed so that this property
373 /// propertly reflects the underlying status. 351 /// propertly reflects the underlying status.
374 /// </remarks>
375 /// <returns></returns> 352 /// <returns></returns>
376 public bool IsAttachmentCheckFull() 353 public bool IsAttachmentCheckFull()
377 { 354 {
378 return (IsAttachment || (m_rootPart.Shape.PCode == 9 && m_rootPart.Shape.State != 0)); 355 return (IsAttachment || (m_rootPart.Shape.PCode == 9 && m_rootPart.Shape.State != 0));
379 } 356 }
380 357
381 /// <summary> 358 /// <summary>
382 /// The absolute position of this scene object in the scene 359 /// The absolute position of this scene object in the scene
383 /// </summary> 360 /// </summary>
@@ -391,30 +368,55 @@ namespace OpenSim.Region.Framework.Scenes
391 if (Scene != null) 368 if (Scene != null)
392 { 369 {
393 if ((Scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E) || Scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W) 370 if ((Scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E) || Scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W)
394 || Scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N) || Scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S)) 371 || Scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N) || Scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S))
395 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims)) 372 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims))
396 { 373 {
397 m_scene.CrossPrimGroupIntoNewRegion(val, this, true); 374 m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
398 } 375 }
399 } 376 }
400 377
378 foreach (SceneObjectPart part in m_parts.GetArray())
379 {
380 part.IgnoreUndoUpdate = true;
381 }
401 if (RootPart.GetStatusSandbox()) 382 if (RootPart.GetStatusSandbox())
402 { 383 {
403 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) 384 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10)
404 { 385 {
405 RootPart.ScriptSetPhysicsStatus(false); 386 RootPart.ScriptSetPhysicsStatus(false);
406 387
407 if (Scene != null) 388 if (Scene != null)
408 Scene.SimChat(Utils.StringToBytes("Hit Sandbox Limit"), 389 Scene.SimChat(Utils.StringToBytes("Hit Sandbox Limit"),
409 ChatTypeEnum.DebugChannel, 0x7FFFFFFF, RootPart.AbsolutePosition, Name, UUID, false); 390 ChatTypeEnum.DebugChannel, 0x7FFFFFFF, RootPart.AbsolutePosition, Name, UUID, false);
410 391
411 return; 392 return;
412 } 393 }
413 } 394 }
414
415 SceneObjectPart[] parts = m_parts.GetArray(); 395 SceneObjectPart[] parts = m_parts.GetArray();
416 for (int i = 0; i < parts.Length; i++) 396 foreach (SceneObjectPart part in parts)
417 parts[i].GroupPosition = val; 397 {
398 part.IgnoreUndoUpdate = false;
399 part.StoreUndoState(UndoType.STATE_GROUP_POSITION);
400 part.GroupPosition = val;
401 if (!m_dupeInProgress)
402 {
403 part.TriggerScriptChangedEvent(Changed.POSITION);
404 }
405 }
406 if (!m_dupeInProgress)
407 {
408 foreach (ScenePresence av in m_linkedAvatars)
409 {
410 SceneObjectPart p;
411 if (m_parts.TryGetValue(av.LinkedPrim, out p))
412 {
413 Vector3 offset = p.GetWorldPosition() - av.ParentPosition;
414 av.AbsolutePosition += offset;
415 av.ParentPosition = p.GetWorldPosition(); //ParentPosition gets cleared by AbsolutePosition
416 av.SendAvatarDataToAllAgents();
417 }
418 }
419 }
418 420
419 //if (m_rootPart.PhysActor != null) 421 //if (m_rootPart.PhysActor != null)
420 //{ 422 //{
@@ -423,7 +425,7 @@ namespace OpenSim.Region.Framework.Scenes
423 //m_rootPart.GroupPosition.Z); 425 //m_rootPart.GroupPosition.Z);
424 //m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor); 426 //m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor);
425 //} 427 //}
426 428
427 if (Scene != null) 429 if (Scene != null)
428 Scene.EventManager.TriggerParcelPrimCountTainted(); 430 Scene.EventManager.TriggerParcelPrimCountTainted();
429 } 431 }
@@ -438,7 +440,7 @@ namespace OpenSim.Region.Framework.Scenes
438 public override UUID UUID 440 public override UUID UUID
439 { 441 {
440 get { return m_rootPart.UUID; } 442 get { return m_rootPart.UUID; }
441 set 443 set
442 { 444 {
443 lock (m_parts.SyncRoot) 445 lock (m_parts.SyncRoot)
444 { 446 {
@@ -469,10 +471,9 @@ namespace OpenSim.Region.Framework.Scenes
469 471
470 public string Text 472 public string Text
471 { 473 {
472 get 474 get {
473 {
474 string returnstr = m_rootPart.Text; 475 string returnstr = m_rootPart.Text;
475 if (returnstr.Length > 255) 476 if (returnstr.Length > 255)
476 { 477 {
477 returnstr = returnstr.Substring(0, 255); 478 returnstr = returnstr.Substring(0, 255);
478 } 479 }
@@ -485,7 +486,7 @@ namespace OpenSim.Region.Framework.Scenes
485 { 486 {
486 get { return true; } 487 get { return true; }
487 } 488 }
488 489
489 private bool m_passCollision; 490 private bool m_passCollision;
490 public bool PassCollision 491 public bool PassCollision
491 { 492 {
@@ -562,10 +563,10 @@ namespace OpenSim.Region.Framework.Scenes
562 563
563 #endregion 564 #endregion
564 565
565 // ~SceneObjectGroup() 566// ~SceneObjectGroup()
566 // { 567// {
567 // m_log.DebugFormat("[SCENE OBJECT GROUP]: Destructor called for {0}, local id {1}", Name, LocalId); 568// m_log.DebugFormat("[SCENE OBJECT GROUP]: Destructor called for {0}, local id {1}", Name, LocalId);
568 // } 569// }
569 570
570 #region Constructors 571 #region Constructors
571 572
@@ -574,6 +575,7 @@ namespace OpenSim.Region.Framework.Scenes
574 /// </summary> 575 /// </summary>
575 public SceneObjectGroup() 576 public SceneObjectGroup()
576 { 577 {
578
577 } 579 }
578 580
579 /// <summary> 581 /// <summary>
@@ -617,7 +619,7 @@ namespace OpenSim.Region.Framework.Scenes
617 if (itemid != UUID.Zero) 619 if (itemid != UUID.Zero)
618 m_savedScriptState[itemid] = node.InnerXml; 620 m_savedScriptState[itemid] = node.InnerXml;
619 } 621 }
620 } 622 }
621 } 623 }
622 } 624 }
623 625
@@ -638,6 +640,9 @@ namespace OpenSim.Region.Framework.Scenes
638 /// </summary> 640 /// </summary>
639 public virtual void AttachToBackup() 641 public virtual void AttachToBackup()
640 { 642 {
643 if (IsAttachment) return;
644 m_scene.SceneGraph.FireAttachToBackup(this);
645
641 if (InSceneBackup) 646 if (InSceneBackup)
642 { 647 {
643 //m_log.DebugFormat( 648 //m_log.DebugFormat(
@@ -645,11 +650,11 @@ namespace OpenSim.Region.Framework.Scenes
645 650
646 if (!m_isBackedUp) 651 if (!m_isBackedUp)
647 m_scene.EventManager.OnBackup += ProcessBackup; 652 m_scene.EventManager.OnBackup += ProcessBackup;
648 653
649 m_isBackedUp = true; 654 m_isBackedUp = true;
650 } 655 }
651 } 656 }
652 657
653 /// <summary> 658 /// <summary>
654 /// Attach this object to a scene. It will also now appear to agents. 659 /// Attach this object to a scene. It will also now appear to agents.
655 /// </summary> 660 /// </summary>
@@ -677,14 +682,45 @@ namespace OpenSim.Region.Framework.Scenes
677 part.ParentID = m_rootPart.LocalId; 682 part.ParentID = m_rootPart.LocalId;
678 //m_log.DebugFormat("[SCENE]: Given local id {0} to part {1}, linknum {2}, parent {3} {4}", part.LocalId, part.UUID, part.LinkNum, part.ParentID, part.ParentUUID); 683 //m_log.DebugFormat("[SCENE]: Given local id {0} to part {1}, linknum {2}, parent {3} {4}", part.LocalId, part.UUID, part.LinkNum, part.ParentID, part.ParentUUID);
679 } 684 }
680 685
681 ApplyPhysics(m_scene.m_physicalPrim); 686 ApplyPhysics(m_scene.m_physicalPrim);
682 687
688 if (RootPart.PhysActor != null)
689 RootPart.Buoyancy = RootPart.Buoyancy;
690
683 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled 691 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled
684 // for the same object with very different properties. The caller must schedule the update. 692 // for the same object with very different properties. The caller must schedule the update.
685 //ScheduleGroupForFullUpdate(); 693 //ScheduleGroupForFullUpdate();
686 } 694 }
687 695
696 public Vector3 GroupScale()
697 {
698 Vector3 minScale = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionSize);
699 Vector3 maxScale = Vector3.Zero;
700 Vector3 finalScale = new Vector3(0.5f, 0.5f, 0.5f);
701
702 SceneObjectPart[] parts = m_parts.GetArray();
703 for (int i = 0; i < parts.Length; i++)
704 {
705 SceneObjectPart part = parts[i];
706 Vector3 partscale = part.Scale;
707 Vector3 partoffset = part.OffsetPosition;
708
709 minScale.X = (partscale.X + partoffset.X < minScale.X) ? partscale.X + partoffset.X : minScale.X;
710 minScale.Y = (partscale.Y + partoffset.Y < minScale.Y) ? partscale.Y + partoffset.Y : minScale.Y;
711 minScale.Z = (partscale.Z + partoffset.Z < minScale.Z) ? partscale.Z + partoffset.Z : minScale.Z;
712
713 maxScale.X = (partscale.X + partoffset.X > maxScale.X) ? partscale.X + partoffset.X : maxScale.X;
714 maxScale.Y = (partscale.Y + partoffset.Y > maxScale.Y) ? partscale.Y + partoffset.Y : maxScale.Y;
715 maxScale.Z = (partscale.Z + partoffset.Z > maxScale.Z) ? partscale.Z + partoffset.Z : maxScale.Z;
716 }
717
718 finalScale.X = (minScale.X > maxScale.X) ? minScale.X : maxScale.X;
719 finalScale.Y = (minScale.Y > maxScale.Y) ? minScale.Y : maxScale.Y;
720 finalScale.Z = (minScale.Z > maxScale.Z) ? minScale.Z : maxScale.Z;
721 return finalScale;
722
723 }
688 public EntityIntersection TestIntersection(Ray hRay, bool frontFacesOnly, bool faceCenters) 724 public EntityIntersection TestIntersection(Ray hRay, bool frontFacesOnly, bool faceCenters)
689 { 725 {
690 // We got a request from the inner_scene to raytrace along the Ray hRay 726 // We got a request from the inner_scene to raytrace along the Ray hRay
@@ -725,9 +761,9 @@ namespace OpenSim.Region.Framework.Scenes
725 result.normal = inter.normal; 761 result.normal = inter.normal;
726 result.distance = inter.distance; 762 result.distance = inter.distance;
727 } 763 }
764
728 } 765 }
729 } 766 }
730
731 return result; 767 return result;
732 } 768 }
733 769
@@ -747,17 +783,19 @@ namespace OpenSim.Region.Framework.Scenes
747 minZ = 8192f; 783 minZ = 8192f;
748 784
749 SceneObjectPart[] parts = m_parts.GetArray(); 785 SceneObjectPart[] parts = m_parts.GetArray();
750 for (int i = 0; i < parts.Length; i++) 786 foreach (SceneObjectPart part in parts)
751 { 787 {
752 SceneObjectPart part = parts[i];
753
754 Vector3 worldPos = part.GetWorldPosition(); 788 Vector3 worldPos = part.GetWorldPosition();
755 Vector3 offset = worldPos - AbsolutePosition; 789 Vector3 offset = worldPos - AbsolutePosition;
756 Quaternion worldRot; 790 Quaternion worldRot;
757 if (part.ParentID == 0) 791 if (part.ParentID == 0)
792 {
758 worldRot = part.RotationOffset; 793 worldRot = part.RotationOffset;
794 }
759 else 795 else
796 {
760 worldRot = part.GetWorldRotation(); 797 worldRot = part.GetWorldRotation();
798 }
761 799
762 Vector3 frontTopLeft; 800 Vector3 frontTopLeft;
763 Vector3 frontTopRight; 801 Vector3 frontTopRight;
@@ -769,6 +807,8 @@ namespace OpenSim.Region.Framework.Scenes
769 Vector3 backBottomLeft; 807 Vector3 backBottomLeft;
770 Vector3 backBottomRight; 808 Vector3 backBottomRight;
771 809
810 // Vector3[] corners = new Vector3[8];
811
772 Vector3 orig = Vector3.Zero; 812 Vector3 orig = Vector3.Zero;
773 813
774 frontTopLeft.X = orig.X - (part.Scale.X / 2); 814 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -803,6 +843,38 @@ namespace OpenSim.Region.Framework.Scenes
803 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 843 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
804 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 844 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
805 845
846
847
848 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
849 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
850 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
851 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
852 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
853 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
854 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
855 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
856
857 //for (int i = 0; i < 8; i++)
858 //{
859 // corners[i] = corners[i] * worldRot;
860 // corners[i] += offset;
861
862 // if (corners[i].X > maxX)
863 // maxX = corners[i].X;
864 // if (corners[i].X < minX)
865 // minX = corners[i].X;
866
867 // if (corners[i].Y > maxY)
868 // maxY = corners[i].Y;
869 // if (corners[i].Y < minY)
870 // minY = corners[i].Y;
871
872 // if (corners[i].Z > maxZ)
873 // maxZ = corners[i].Y;
874 // if (corners[i].Z < minZ)
875 // minZ = corners[i].Z;
876 //}
877
806 frontTopLeft = frontTopLeft * worldRot; 878 frontTopLeft = frontTopLeft * worldRot;
807 frontTopRight = frontTopRight * worldRot; 879 frontTopRight = frontTopRight * worldRot;
808 frontBottomLeft = frontBottomLeft * worldRot; 880 frontBottomLeft = frontBottomLeft * worldRot;
@@ -824,6 +896,15 @@ namespace OpenSim.Region.Framework.Scenes
824 backTopLeft += offset; 896 backTopLeft += offset;
825 backTopRight += offset; 897 backTopRight += offset;
826 898
899 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
900 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
901 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
902 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
903 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
904 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
905 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
906 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
907
827 if (frontTopRight.X > maxX) 908 if (frontTopRight.X > maxX)
828 maxX = frontTopRight.X; 909 maxX = frontTopRight.X;
829 if (frontTopLeft.X > maxX) 910 if (frontTopLeft.X > maxX)
@@ -961,7 +1042,7 @@ namespace OpenSim.Region.Framework.Scenes
961 offsetHeight *= -1; 1042 offsetHeight *= -1;
962 } 1043 }
963 1044
964 // m_log.InfoFormat("BoundingBox is {0} , {1} , {2} ", boundingBox.X, boundingBox.Y, boundingBox.Z); 1045 // m_log.InfoFormat("BoundingBox is {0} , {1} , {2} ", boundingBox.X, boundingBox.Y, boundingBox.Z);
965 return boundingBox; 1046 return boundingBox;
966 } 1047 }
967 1048
@@ -969,15 +1050,20 @@ namespace OpenSim.Region.Framework.Scenes
969 1050
970 public void SaveScriptedState(XmlTextWriter writer) 1051 public void SaveScriptedState(XmlTextWriter writer)
971 { 1052 {
1053 SaveScriptedState(writer, false);
1054 }
1055
1056 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1057 {
972 XmlDocument doc = new XmlDocument(); 1058 XmlDocument doc = new XmlDocument();
973 Dictionary<UUID, string> states = new Dictionary<UUID, string>(); 1059 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
974 1060
975 SceneObjectPart[] parts = m_parts.GetArray(); 1061 SceneObjectPart[] parts = m_parts.GetArray();
976 for (int i = 0; i < parts.Length; i++) 1062 for (int i = 0; i < parts.Length; i++)
977 { 1063 {
978 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1064 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
979 foreach (KeyValuePair<UUID, string> kvp in pstates) 1065 foreach (KeyValuePair<UUID, string> kvp in pstates)
980 states.Add(kvp.Key, kvp.Value); 1066 states[kvp.Key] = kvp.Value;
981 } 1067 }
982 1068
983 if (states.Count > 0) 1069 if (states.Count > 0)
@@ -997,6 +1083,187 @@ namespace OpenSim.Region.Framework.Scenes
997 } 1083 }
998 1084
999 /// <summary> 1085 /// <summary>
1086 /// Add the avatar to this linkset (avatar is sat).
1087 /// </summary>
1088 /// <param name="agentID"></param>
1089 public void AddAvatar(UUID agentID)
1090 {
1091 ScenePresence presence;
1092 if (m_scene.TryGetScenePresence(agentID, out presence))
1093 {
1094 if (!m_linkedAvatars.Contains(presence))
1095 {
1096 m_linkedAvatars.Add(presence);
1097 }
1098 }
1099 }
1100
1101 /// <summary>
1102 /// Delete the avatar from this linkset (avatar is unsat).
1103 /// </summary>
1104 /// <param name="agentID"></param>
1105 public void DeleteAvatar(UUID agentID)
1106 {
1107 ScenePresence presence;
1108 if (m_scene.TryGetScenePresence(agentID, out presence))
1109 {
1110 if (m_linkedAvatars.Contains(presence))
1111 {
1112 m_linkedAvatars.Remove(presence);
1113 }
1114 }
1115 }
1116
1117 /// <summary>
1118 /// Returns the list of linked presences (avatars sat on this group)
1119 /// </summary>
1120 /// <param name="agentID"></param>
1121 public List<ScenePresence> GetLinkedAvatars()
1122 {
1123 return m_linkedAvatars;
1124 }
1125
1126 /// <summary>
1127 /// Attach this scene object to the given avatar.
1128 /// </summary>
1129 /// <param name="agentID"></param>
1130 /// <param name="attachmentpoint"></param>
1131 /// <param name="AttachOffset"></param>
1132 public void AttachToAgent(UUID agentID, uint attachmentpoint, Vector3 AttachOffset, bool silent)
1133 {
1134 ScenePresence avatar = m_scene.GetScenePresence(agentID);
1135 if (avatar != null)
1136 {
1137 // don't attach attachments to child agents
1138 if (avatar.IsChildAgent) return;
1139
1140// m_log.DebugFormat("[SOG]: Adding attachment {0} to avatar {1}", Name, avatar.Name);
1141
1142 DetachFromBackup();
1143
1144 // Remove from database and parcel prim count
1145 m_scene.DeleteFromStorage(UUID);
1146 m_scene.EventManager.TriggerParcelPrimCountTainted();
1147
1148 m_rootPart.AttachedAvatar = agentID;
1149
1150 //Anakin Lohner bug #3839
1151 lock (m_parts)
1152 {
1153 foreach (SceneObjectPart p in m_parts.GetArray())
1154 {
1155 p.AttachedAvatar = agentID;
1156 }
1157 }
1158
1159 if (m_rootPart.PhysActor != null)
1160 {
1161 m_scene.PhysicsScene.RemovePrim(m_rootPart.PhysActor);
1162 m_rootPart.PhysActor = null;
1163 }
1164
1165 AbsolutePosition = AttachOffset;
1166 m_rootPart.AttachedPos = AttachOffset;
1167 m_rootPart.IsAttachment = true;
1168
1169 m_rootPart.SetParentLocalId(avatar.LocalId);
1170 SetAttachmentPoint(Convert.ToByte(attachmentpoint));
1171
1172 avatar.AddAttachment(this);
1173
1174 if (!silent)
1175 {
1176 // Killing it here will cause the client to deselect it
1177 // It then reappears on the avatar, deselected
1178 // through the full update below
1179 //
1180 if (IsSelected)
1181 {
1182 m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1183 }
1184
1185 IsSelected = false; // fudge....
1186 ScheduleGroupForFullUpdate();
1187 }
1188 }
1189 else
1190 {
1191 m_log.WarnFormat(
1192 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1193 UUID, agentID, Scene.RegionInfo.RegionName);
1194 }
1195 }
1196
1197 public byte GetAttachmentPoint()
1198 {
1199 return m_rootPart.Shape.State;
1200 }
1201
1202 public void ClearPartAttachmentData()
1203 {
1204 SetAttachmentPoint((Byte)0);
1205 }
1206
1207 public void DetachToGround()
1208 {
1209 ScenePresence avatar = m_scene.GetScenePresence(m_rootPart.AttachedAvatar);
1210 if (avatar == null)
1211 return;
1212
1213 avatar.RemoveAttachment(this);
1214
1215 Vector3 detachedpos = new Vector3(127f,127f,127f);
1216 if (avatar == null)
1217 return;
1218
1219 detachedpos = avatar.AbsolutePosition;
1220 RootPart.FromItemID = UUID.Zero;
1221
1222 AbsolutePosition = detachedpos;
1223 m_rootPart.AttachedAvatar = UUID.Zero;
1224
1225 SceneObjectPart[] parts = m_parts.GetArray();
1226 for (int i = 0; i < parts.Length; i++)
1227 parts[i].AttachedAvatar = UUID.Zero;
1228
1229 m_rootPart.SetParentLocalId(0);
1230 SetAttachmentPoint((byte)0);
1231 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, m_scene.m_physicalPrim);
1232 HasGroupChanged = true;
1233 RootPart.Rezzed = DateTime.Now;
1234 RootPart.RemFlag(PrimFlags.TemporaryOnRez);
1235 AttachToBackup();
1236 m_scene.EventManager.TriggerParcelPrimCountTainted();
1237 m_rootPart.ScheduleFullUpdate();
1238 m_rootPart.ClearUndoState();
1239 }
1240
1241 public void DetachToInventoryPrep()
1242 {
1243 ScenePresence avatar = m_scene.GetScenePresence(m_rootPart.AttachedAvatar);
1244 //Vector3 detachedpos = new Vector3(127f, 127f, 127f);
1245 if (avatar != null)
1246 {
1247 //detachedpos = avatar.AbsolutePosition;
1248 avatar.RemoveAttachment(this);
1249 }
1250
1251 m_rootPart.AttachedAvatar = UUID.Zero;
1252
1253 SceneObjectPart[] parts = m_parts.GetArray();
1254 for (int i = 0; i < parts.Length; i++)
1255 parts[i].AttachedAvatar = UUID.Zero;
1256
1257 m_rootPart.SetParentLocalId(0);
1258 //m_rootPart.SetAttachmentPoint((byte)0);
1259 m_rootPart.IsAttachment = false;
1260 AbsolutePosition = m_rootPart.AttachedPos;
1261 //m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_scene.m_physicalPrim);
1262 //AttachToBackup();
1263 //m_rootPart.ScheduleFullUpdate();
1264 }
1265
1266 /// <summary>
1000 /// 1267 ///
1001 /// </summary> 1268 /// </summary>
1002 /// <param name="part"></param> 1269 /// <param name="part"></param>
@@ -1027,7 +1294,7 @@ namespace OpenSim.Region.Framework.Scenes
1027 { 1294 {
1028 m_scene = scene; 1295 m_scene = scene;
1029 } 1296 }
1030 1297
1031 /// <summary> 1298 /// <summary>
1032 /// Set a part to act as the root part for this scene object 1299 /// Set a part to act as the root part for this scene object
1033 /// </summary> 1300 /// </summary>
@@ -1042,7 +1309,7 @@ namespace OpenSim.Region.Framework.Scenes
1042 if (!IsAttachment) 1309 if (!IsAttachment)
1043 part.ParentID = 0; 1310 part.ParentID = 0;
1044 part.LinkNum = 0; 1311 part.LinkNum = 0;
1045 1312
1046 m_parts.Add(m_rootPart.UUID, m_rootPart); 1313 m_parts.Add(m_rootPart.UUID, m_rootPart);
1047 } 1314 }
1048 1315
@@ -1053,8 +1320,11 @@ namespace OpenSim.Region.Framework.Scenes
1053 public void AddPart(SceneObjectPart part) 1320 public void AddPart(SceneObjectPart part)
1054 { 1321 {
1055 part.SetParent(this); 1322 part.SetParent(this);
1056 part.LinkNum = m_parts.Add(part.UUID, part); 1323 m_parts.Add(part.UUID, part);
1057 if (part.LinkNum == 2) 1324
1325 part.LinkNum = m_parts.Count;
1326
1327 if (part.LinkNum == 2 && RootPart != null)
1058 RootPart.LinkNum = 1; 1328 RootPart.LinkNum = 1;
1059 } 1329 }
1060 1330
@@ -1090,19 +1360,19 @@ namespace OpenSim.Region.Framework.Scenes
1090 // justincc: I don't believe this hack is needed any longer, especially since the physics 1360 // justincc: I don't believe this hack is needed any longer, especially since the physics
1091 // parts of set AbsolutePosition were already commented out. By changing HasGroupChanged to false 1361 // parts of set AbsolutePosition were already commented out. By changing HasGroupChanged to false
1092 // this method was preventing proper reload of scene objects. 1362 // this method was preventing proper reload of scene objects.
1093 1363
1094 // dahlia: I had to uncomment it, without it meshing was failing on some prims and objects 1364 // dahlia: I had to uncomment it, without it meshing was failing on some prims and objects
1095 // at region startup 1365 // at region startup
1096 1366
1097 // teravus: After this was removed from the linking algorithm, Linked prims no longer collided 1367 // teravus: After this was removed from the linking algorithm, Linked prims no longer collided
1098 // properly when non-physical if they havn't been moved. This breaks ALL builds. 1368 // properly when non-physical if they havn't been moved. This breaks ALL builds.
1099 // see: http://opensimulator.org/mantis/view.php?id=3108 1369 // see: http://opensimulator.org/mantis/view.php?id=3108
1100 1370
1101 // Here's the deal, this is ABSOLUTELY CRITICAL so the physics scene gets the update about the 1371 // Here's the deal, this is ABSOLUTELY CRITICAL so the physics scene gets the update about the
1102 // position of linkset prims. IF YOU CHANGE THIS, YOU MUST TEST colliding with just linked and 1372 // position of linkset prims. IF YOU CHANGE THIS, YOU MUST TEST colliding with just linked and
1103 // unmoved prims! As soon as you move a Prim/group, it will collide properly because Absolute 1373 // unmoved prims! As soon as you move a Prim/group, it will collide properly because Absolute
1104 // Position has been set! 1374 // Position has been set!
1105 1375
1106 public void ResetChildPrimPhysicsPositions() 1376 public void ResetChildPrimPhysicsPositions()
1107 { 1377 {
1108 AbsolutePosition = AbsolutePosition; // could someone in the know please explain how this works? 1378 AbsolutePosition = AbsolutePosition; // could someone in the know please explain how this works?
@@ -1137,11 +1407,7 @@ namespace OpenSim.Region.Framework.Scenes
1137 1407
1138 public virtual void OnGrabPart(SceneObjectPart part, Vector3 offsetPos, IClientAPI remoteClient) 1408 public virtual void OnGrabPart(SceneObjectPart part, Vector3 offsetPos, IClientAPI remoteClient)
1139 { 1409 {
1140 // m_log.DebugFormat( 1410 part.StoreUndoState(UndoType.STATE_PRIM_ALL);
1141 // "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}",
1142 // remoteClient.Name, part.Name, part.LocalId, offsetPos);
1143
1144 part.StoreUndoState();
1145 part.OnGrab(offsetPos, remoteClient); 1411 part.OnGrab(offsetPos, remoteClient);
1146 } 1412 }
1147 1413
@@ -1161,6 +1427,11 @@ namespace OpenSim.Region.Framework.Scenes
1161 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1427 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1162 public void DeleteGroupFromScene(bool silent) 1428 public void DeleteGroupFromScene(bool silent)
1163 { 1429 {
1430 // We need to keep track of this state in case this group is still queued for backup.
1431 m_isDeleted = true;
1432
1433 DetachFromBackup();
1434
1164 SceneObjectPart[] parts = m_parts.GetArray(); 1435 SceneObjectPart[] parts = m_parts.GetArray();
1165 for (int i = 0; i < parts.Length; i++) 1436 for (int i = 0; i < parts.Length; i++)
1166 { 1437 {
@@ -1172,13 +1443,11 @@ namespace OpenSim.Region.Framework.Scenes
1172 avatar.StandUp(); 1443 avatar.StandUp();
1173 1444
1174 if (!silent) 1445 if (!silent)
1175 {
1176 part.UpdateFlag = 0; 1446 part.UpdateFlag = 0;
1177 if (part == m_rootPart)
1178 avatar.ControllingClient.SendKillObject(m_regionHandle, part.LocalId);
1179 }
1180 }); 1447 });
1181 } 1448 }
1449
1450
1182 } 1451 }
1183 1452
1184 public void AddScriptLPS(int count) 1453 public void AddScriptLPS(int count)
@@ -1238,10 +1507,10 @@ namespace OpenSim.Region.Framework.Scenes
1238 1507
1239 public void SetText(string text, Vector3 color, double alpha) 1508 public void SetText(string text, Vector3 color, double alpha)
1240 { 1509 {
1241 Color = Color.FromArgb(0xff - (int)(alpha * 0xff), 1510 Color = Color.FromArgb(0xff - (int) (alpha * 0xff),
1242 (int)(color.X * 0xff), 1511 (int) (color.X * 0xff),
1243 (int)(color.Y * 0xff), 1512 (int) (color.Y * 0xff),
1244 (int)(color.Z * 0xff)); 1513 (int) (color.Z * 0xff));
1245 Text = text; 1514 Text = text;
1246 1515
1247 HasGroupChanged = true; 1516 HasGroupChanged = true;
@@ -1256,7 +1525,7 @@ namespace OpenSim.Region.Framework.Scenes
1256 { 1525 {
1257 // Apply physics to the root prim 1526 // Apply physics to the root prim
1258 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, m_physicalPrim); 1527 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, m_physicalPrim);
1259 1528
1260 // Apply physics to child prims 1529 // Apply physics to child prims
1261 SceneObjectPart[] parts = m_parts.GetArray(); 1530 SceneObjectPart[] parts = m_parts.GetArray();
1262 if (parts.Length > 1) 1531 if (parts.Length > 1)
@@ -1275,7 +1544,12 @@ namespace OpenSim.Region.Framework.Scenes
1275 1544
1276 public void SetOwnerId(UUID userId) 1545 public void SetOwnerId(UUID userId)
1277 { 1546 {
1278 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1547 ForEachPart(delegate(SceneObjectPart part)
1548 {
1549
1550 part.OwnerID = userId;
1551
1552 });
1279 } 1553 }
1280 1554
1281 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1555 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1295,23 +1569,29 @@ namespace OpenSim.Region.Framework.Scenes
1295 { 1569 {
1296 if (!m_isBackedUp) 1570 if (!m_isBackedUp)
1297 { 1571 {
1298 // m_log.DebugFormat( 1572// m_log.DebugFormat(
1299 // "[WATER WARS]: Ignoring backup of {0} {1} since object is not marked to be backed up", Name, UUID); 1573// "[WATER WARS]: Ignoring backup of {0} {1} since object is not marked to be backed up", Name, UUID);
1300 return; 1574 return;
1301 } 1575 }
1302 1576
1303 if (IsDeleted || UUID == UUID.Zero) 1577 if (IsDeleted || UUID == UUID.Zero)
1304 { 1578 {
1305 // m_log.DebugFormat( 1579// m_log.DebugFormat(
1306 // "[WATER WARS]: Ignoring backup of {0} {1} since object is marked as already deleted", Name, UUID); 1580// "[WATER WARS]: Ignoring backup of {0} {1} since object is marked as already deleted", Name, UUID);
1307 return; 1581 return;
1308 } 1582 }
1309 1583
1584 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
1585 return;
1586
1310 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 1587 // Since this is the top of the section of call stack for backing up a particular scene object, don't let
1311 // any exception propogate upwards. 1588 // any exception propogate upwards.
1312 try 1589 try
1313 { 1590 {
1314 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 1591 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
1592 m_scene.LoginsDisabled || // We're starting up or doing maintenance, don't mess with things
1593 m_scene.LoadingPrims) // Land may not be valid yet
1594
1315 { 1595 {
1316 ILandObject parcel = m_scene.LandChannel.GetLandObject( 1596 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1317 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 1597 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1328,7 +1608,7 @@ namespace OpenSim.Region.Framework.Scenes
1328 { 1608 {
1329 DetachFromBackup(); 1609 DetachFromBackup();
1330 m_log.DebugFormat( 1610 m_log.DebugFormat(
1331 "[SCENE OBJECT GROUP]: Returning object {0} due to parcel autoreturn", 1611 "[SCENE OBJECT GROUP]: Returning object {0} due to parcel autoreturn",
1332 RootPart.UUID); 1612 RootPart.UUID);
1333 m_scene.AddReturn(OwnerID, Name, AbsolutePosition, "parcel autoreturn"); 1613 m_scene.AddReturn(OwnerID, Name, AbsolutePosition, "parcel autoreturn");
1334 m_scene.DeRezObjects(null, new List<uint>() { RootPart.LocalId }, UUID.Zero, 1614 m_scene.DeRezObjects(null, new List<uint>() { RootPart.LocalId }, UUID.Zero,
@@ -1338,6 +1618,7 @@ namespace OpenSim.Region.Framework.Scenes
1338 } 1618 }
1339 } 1619 }
1340 } 1620 }
1621
1341 } 1622 }
1342 1623
1343 if (m_scene.UseBackup && HasGroupChanged) 1624 if (m_scene.UseBackup && HasGroupChanged)
@@ -1345,9 +1626,23 @@ namespace OpenSim.Region.Framework.Scenes
1345 // don't backup while it's selected or you're asking for changes mid stream. 1626 // don't backup while it's selected or you're asking for changes mid stream.
1346 if (isTimeToPersist() || forcedBackup) 1627 if (isTimeToPersist() || forcedBackup)
1347 { 1628 {
1348 // m_log.DebugFormat( 1629 if (m_rootPart.PhysActor != null &&
1349 // "[SCENE]: Storing {0}, {1} in {2}", 1630 (!m_rootPart.PhysActor.IsPhysical))
1350 // Name, UUID, m_scene.RegionInfo.RegionName); 1631 {
1632 // Possible ghost prim
1633 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
1634 {
1635 foreach (SceneObjectPart part in m_parts.GetArray())
1636 {
1637 // Re-set physics actor positions and
1638 // orientations
1639 part.GroupPosition = m_rootPart.GroupPosition;
1640 }
1641 }
1642 }
1643// m_log.DebugFormat(
1644// "[SCENE]: Storing {0}, {1} in {2}",
1645// Name, UUID, m_scene.RegionInfo.RegionName);
1351 1646
1352 SceneObjectGroup backup_group = Copy(false); 1647 SceneObjectGroup backup_group = Copy(false);
1353 backup_group.RootPart.Velocity = RootPart.Velocity; 1648 backup_group.RootPart.Velocity = RootPart.Velocity;
@@ -1360,25 +1655,25 @@ namespace OpenSim.Region.Framework.Scenes
1360 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this); 1655 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this);
1361 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID); 1656 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID);
1362 1657
1363 backup_group.ForEachPart(delegate(SceneObjectPart part) 1658 backup_group.ForEachPart(delegate(SceneObjectPart part)
1364 { 1659 {
1365 part.Inventory.ProcessInventoryBackup(datastore); 1660 part.Inventory.ProcessInventoryBackup(datastore);
1366 }); 1661 });
1367 1662
1368 backup_group = null; 1663 backup_group = null;
1369 } 1664 }
1370 // else 1665// else
1371 // { 1666// {
1372 // m_log.DebugFormat( 1667// m_log.DebugFormat(
1373 // "[SCENE]: Did not update persistence of object {0} {1}, selected = {2}", 1668// "[SCENE]: Did not update persistence of object {0} {1}, selected = {2}",
1374 // Name, UUID, IsSelected); 1669// Name, UUID, IsSelected);
1375 // } 1670// }
1376 } 1671 }
1377 } 1672 }
1378 catch (Exception e) 1673 catch (Exception e)
1379 { 1674 {
1380 m_log.ErrorFormat( 1675 m_log.ErrorFormat(
1381 "[SCENE]: Storing of {0}, {1} in {2} failed with exception {3}{4}", 1676 "[SCENE]: Storing of {0}, {1} in {2} failed with exception {3}{4}",
1382 Name, UUID, m_scene.RegionInfo.RegionName, e.Message, e.StackTrace); 1677 Name, UUID, m_scene.RegionInfo.RegionName, e.Message, e.StackTrace);
1383 } 1678 }
1384 } 1679 }
@@ -1408,86 +1703,91 @@ namespace OpenSim.Region.Framework.Scenes
1408 /// <returns></returns> 1703 /// <returns></returns>
1409 public SceneObjectGroup Copy(bool userExposed) 1704 public SceneObjectGroup Copy(bool userExposed)
1410 { 1705 {
1411 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 1706 SceneObjectGroup dupe;
1412 dupe.m_isBackedUp = false; 1707 try
1413 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 1708 {
1709 m_dupeInProgress = true;
1710 dupe = (SceneObjectGroup)MemberwiseClone();
1711 dupe.m_isBackedUp = false;
1712 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
1414 1713
1415 // Warning, The following code related to previousAttachmentStatus is needed so that clones of 1714 // Warning, The following code related to previousAttachmentStatus is needed so that clones of
1416 // attachments do not bordercross while they're being duplicated. This is hacktastic! 1715 // attachments do not bordercross while they're being duplicated. This is hacktastic!
1417 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region! 1716 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
1418 // unless IsAttachment is true!, so to prevent border crossing, we save it's attachment state 1717 // unless IsAttachment is true!, so to prevent border crossing, we save it's attachment state
1419 // (which should be false anyway) set it as an Attachment and then set it's Absolute Position, 1718 // (which should be false anyway) set it as an Attachment and then set it's Absolute Position,
1420 // then restore it's attachment state 1719 // then restore it's attachment state
1421 1720
1422 // This is only necessary when userExposed is false! 1721 // This is only necessary when userExposed is false!
1423 1722
1424 bool previousAttachmentStatus = dupe.IsAttachment; 1723 bool previousAttachmentStatus = dupe.RootPart.IsAttachment;
1425 1724
1426 if (!userExposed) 1725 if (!userExposed)
1427 dupe.IsAttachment = true; 1726 dupe.RootPart.IsAttachment = true;
1428 1727
1429 dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z); 1728 dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z);
1430 1729
1431 if (!userExposed) 1730 if (!userExposed)
1432 { 1731 {
1433 dupe.IsAttachment = previousAttachmentStatus; 1732 dupe.RootPart.IsAttachment = previousAttachmentStatus;
1434 } 1733 }
1435 1734
1436 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed); 1735 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed);
1437 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum; 1736 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum;
1438 1737
1439 if (userExposed) 1738 if (userExposed)
1440 dupe.m_rootPart.TrimPermissions(); 1739 dupe.m_rootPart.TrimPermissions();
1441 1740
1442 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 1741 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1443 1742
1444 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) 1743 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1445 { 1744 {
1446 return p1.LinkNum.CompareTo(p2.LinkNum); 1745 return p1.LinkNum.CompareTo(p2.LinkNum);
1447 } 1746 }
1448 ); 1747 );
1449 1748
1450 foreach (SceneObjectPart part in partList) 1749 foreach (SceneObjectPart part in partList)
1451 {
1452 SceneObjectPart newPart;
1453 if (part.UUID != m_rootPart.UUID)
1454 {
1455 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1456 newPart.LinkNum = part.LinkNum;
1457 }
1458 else
1459 { 1750 {
1460 newPart = dupe.m_rootPart; 1751 if (part.UUID != m_rootPart.UUID)
1461 } 1752 {
1753 SceneObjectPart newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1462 1754
1463 // Need to duplicate the physics actor as well 1755 newPart.LinkNum = part.LinkNum;
1464 if (part.PhysActor != null && userExposed) 1756 }
1465 {
1466 PrimitiveBaseShape pbs = newPart.Shape;
1467 1757
1468 newPart.PhysActor 1758 // Need to duplicate the physics actor as well
1469 = m_scene.PhysicsScene.AddPrimShape( 1759 if (part.PhysActor != null && userExposed)
1470 string.Format("{0}/{1}", newPart.Name, newPart.UUID), 1760 {
1471 pbs, 1761 PrimitiveBaseShape pbs = part.Shape;
1472 newPart.AbsolutePosition, 1762
1473 newPart.Scale, 1763 part.PhysActor
1474 newPart.RotationOffset, 1764 = m_scene.PhysicsScene.AddPrimShape(
1475 part.PhysActor.IsPhysical, 1765 string.Format("{0}/{1}", part.Name, part.UUID),
1476 newPart.LocalId); 1766 pbs,
1767 part.AbsolutePosition,
1768 part.Scale,
1769 part.RotationOffset,
1770 part.PhysActor.IsPhysical,
1771 m_localId);
1772 part.PhysActor.SetMaterial((int)part.Material);
1773
1774 part.PhysActor.LocalID = part.LocalId;
1775 part.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1776 }
1777 }
1778 if (userExposed)
1779 {
1780 dupe.UpdateParentIDs();
1781 dupe.HasGroupChanged = true;
1782 dupe.AttachToBackup();
1477 1783
1478 newPart.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true); 1784 ScheduleGroupForFullUpdate();
1479 } 1785 }
1480 } 1786 }
1481 1787 finally
1482 if (userExposed)
1483 { 1788 {
1484 dupe.UpdateParentIDs(); 1789 m_dupeInProgress = false;
1485 dupe.HasGroupChanged = true;
1486 dupe.AttachToBackup();
1487
1488 ScheduleGroupForFullUpdate();
1489 } 1790 }
1490
1491 return dupe; 1791 return dupe;
1492 } 1792 }
1493 1793
@@ -1502,24 +1802,36 @@ namespace OpenSim.Region.Framework.Scenes
1502 SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed)); 1802 SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed));
1503 } 1803 }
1504 1804
1505 public void ScriptSetPhysicsStatus(bool usePhysics) 1805 public void ScriptSetPhysicsStatus(bool UsePhysics)
1506 { 1806 {
1507 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect); 1807 bool IsTemporary = ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0);
1808 bool IsPhantom = ((RootPart.Flags & PrimFlags.Phantom) != 0);
1809 bool IsVolumeDetect = RootPart.VolumeDetectActive;
1810 UpdatePrimFlags(RootPart.LocalId, UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
1508 } 1811 }
1509 1812
1510 public void ScriptSetTemporaryStatus(bool makeTemporary) 1813 public void ScriptSetTemporaryStatus(bool TemporaryStatus)
1511 { 1814 {
1512 UpdatePrimFlags(RootPart.LocalId, UsesPhysics, makeTemporary, IsPhantom, IsVolumeDetect); 1815 bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0);
1816 bool IsPhantom = ((RootPart.Flags & PrimFlags.Phantom) != 0);
1817 bool IsVolumeDetect = RootPart.VolumeDetectActive;
1818 UpdatePrimFlags(RootPart.LocalId, UsePhysics, TemporaryStatus, IsPhantom, IsVolumeDetect);
1513 } 1819 }
1514 1820
1515 public void ScriptSetPhantomStatus(bool makePhantom) 1821 public void ScriptSetPhantomStatus(bool PhantomStatus)
1516 { 1822 {
1517 UpdatePrimFlags(RootPart.LocalId, UsesPhysics, IsTemporary, makePhantom, IsVolumeDetect); 1823 bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0);
1824 bool IsTemporary = ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0);
1825 bool IsVolumeDetect = RootPart.VolumeDetectActive;
1826 UpdatePrimFlags(RootPart.LocalId, UsePhysics, IsTemporary, PhantomStatus, IsVolumeDetect);
1518 } 1827 }
1519 1828
1520 public void ScriptSetVolumeDetect(bool makeVolumeDetect) 1829 public void ScriptSetVolumeDetect(bool VDStatus)
1521 { 1830 {
1522 UpdatePrimFlags(RootPart.LocalId, UsesPhysics, IsTemporary, IsPhantom, makeVolumeDetect); 1831 bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0);
1832 bool IsTemporary = ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0);
1833 bool IsPhantom = ((RootPart.Flags & PrimFlags.Phantom) != 0);
1834 UpdatePrimFlags(RootPart.LocalId, UsePhysics, IsTemporary, IsPhantom, VDStatus);
1523 1835
1524 /* 1836 /*
1525 ScriptSetPhantomStatus(false); // What ever it was before, now it's not phantom anymore 1837 ScriptSetPhantomStatus(false); // What ever it was before, now it's not phantom anymore
@@ -1537,93 +1849,182 @@ namespace OpenSim.Region.Framework.Scenes
1537 1849
1538 public void applyImpulse(Vector3 impulse) 1850 public void applyImpulse(Vector3 impulse)
1539 { 1851 {
1540 if (IsAttachment) 1852 // We check if rootpart is null here because scripts don't delete if you delete the host.
1853 // This means that unfortunately, we can pass a null physics actor to Simulate!
1854 // Make sure we don't do that!
1855 SceneObjectPart rootpart = m_rootPart;
1856 if (rootpart != null)
1541 { 1857 {
1542 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar); 1858 if (IsAttachment)
1543 if (avatar != null)
1544 { 1859 {
1545 avatar.PushForce(impulse); 1860 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
1861 if (avatar != null)
1862 {
1863 avatar.PushForce(impulse);
1864 }
1546 } 1865 }
1547 } 1866 else
1548 else
1549 {
1550 if (RootPart.PhysActor != null)
1551 { 1867 {
1552 RootPart.PhysActor.AddForce(impulse, true); 1868 if (rootpart.PhysActor != null)
1553 m_scene.PhysicsScene.AddPhysicsActorTaint(RootPart.PhysActor); 1869 {
1870 rootpart.PhysActor.AddForce(impulse, true);
1871 m_scene.PhysicsScene.AddPhysicsActorTaint(rootpart.PhysActor);
1872 }
1554 } 1873 }
1555 } 1874 }
1556 } 1875 }
1557 1876
1558 public void applyAngularImpulse(Vector3 impulse) 1877 public void applyAngularImpulse(Vector3 impulse)
1559 { 1878 {
1560 if (RootPart.PhysActor != null) 1879 // We check if rootpart is null here because scripts don't delete if you delete the host.
1880 // This means that unfortunately, we can pass a null physics actor to Simulate!
1881 // Make sure we don't do that!
1882 SceneObjectPart rootpart = m_rootPart;
1883 if (rootpart != null)
1561 { 1884 {
1562 if (!IsAttachment) 1885 if (rootpart.PhysActor != null)
1563 { 1886 {
1564 RootPart.PhysActor.AddAngularForce(impulse, true); 1887 if (!IsAttachment)
1565 m_scene.PhysicsScene.AddPhysicsActorTaint(RootPart.PhysActor); 1888 {
1889 rootpart.PhysActor.AddAngularForce(impulse, true);
1890 m_scene.PhysicsScene.AddPhysicsActorTaint(rootpart.PhysActor);
1891 }
1566 } 1892 }
1567 } 1893 }
1568 } 1894 }
1569 1895
1570 public void setAngularImpulse(Vector3 impulse) 1896 public void setAngularImpulse(Vector3 impulse)
1571 { 1897 {
1572 if (RootPart.PhysActor != null) 1898 // We check if rootpart is null here because scripts don't delete if you delete the host.
1899 // This means that unfortunately, we can pass a null physics actor to Simulate!
1900 // Make sure we don't do that!
1901 SceneObjectPart rootpart = m_rootPart;
1902 if (rootpart != null)
1573 { 1903 {
1574 if (!IsAttachment) 1904 if (rootpart.PhysActor != null)
1575 { 1905 {
1576 RootPart.PhysActor.Torque = impulse; 1906 if (!IsAttachment)
1577 m_scene.PhysicsScene.AddPhysicsActorTaint(RootPart.PhysActor); 1907 {
1908 rootpart.PhysActor.Torque = impulse;
1909 m_scene.PhysicsScene.AddPhysicsActorTaint(rootpart.PhysActor);
1910 }
1578 } 1911 }
1579 } 1912 }
1580 } 1913 }
1581 1914
1582 public Vector3 GetTorque() 1915 public Vector3 GetTorque()
1583 { 1916 {
1584 if (RootPart.PhysActor != null) 1917 // We check if rootpart is null here because scripts don't delete if you delete the host.
1918 // This means that unfortunately, we can pass a null physics actor to Simulate!
1919 // Make sure we don't do that!
1920 SceneObjectPart rootpart = m_rootPart;
1921 if (rootpart != null)
1585 { 1922 {
1586 if (!IsAttachment) 1923 if (rootpart.PhysActor != null)
1587 { 1924 {
1588 Vector3 torque = RootPart.PhysActor.Torque; 1925 if (!IsAttachment)
1589 return torque; 1926 {
1927 Vector3 torque = rootpart.PhysActor.Torque;
1928 return torque;
1929 }
1590 } 1930 }
1591 } 1931 }
1592
1593 return Vector3.Zero; 1932 return Vector3.Zero;
1594 } 1933 }
1595 1934
1935 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1596 public void moveToTarget(Vector3 target, float tau) 1936 public void moveToTarget(Vector3 target, float tau)
1597 { 1937 {
1598 if (IsAttachment) 1938 SceneObjectPart rootpart = m_rootPart;
1939 if (rootpart != null)
1599 { 1940 {
1600 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar); 1941 if (IsAttachment)
1601 if (avatar != null)
1602 { 1942 {
1603 avatar.MoveToTarget(target, false); 1943 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
1944 if (avatar != null)
1945 {
1946 List<string> coords = new List<string>();
1947 uint regionX = 0;
1948 uint regionY = 0;
1949 Utils.LongToUInts(Scene.RegionInfo.RegionHandle, out regionX, out regionY);
1950 target.X += regionX;
1951 target.Y += regionY;
1952 coords.Add(target.X.ToString());
1953 coords.Add(target.Y.ToString());
1954 coords.Add(target.Z.ToString());
1955 avatar.DoMoveToPosition(avatar, "", coords);
1956 }
1604 } 1957 }
1605 } 1958 else
1606 else
1607 {
1608 if (RootPart.PhysActor != null)
1609 { 1959 {
1610 RootPart.PhysActor.PIDTarget = target; 1960 if (rootpart.PhysActor != null)
1611 RootPart.PhysActor.PIDTau = tau; 1961 {
1612 RootPart.PhysActor.PIDActive = true; 1962 rootpart.PhysActor.PIDTarget = target;
1963 rootpart.PhysActor.PIDTau = tau;
1964 rootpart.PhysActor.PIDActive = true;
1965 }
1613 } 1966 }
1614 } 1967 }
1615 } 1968 }
1616 1969
1617 public void stopMoveToTarget() 1970 public void stopMoveToTarget()
1618 { 1971 {
1619 if (RootPart.PhysActor != null) 1972 SceneObjectPart rootpart = m_rootPart;
1620 RootPart.PhysActor.PIDActive = false; 1973 if (rootpart != null)
1974 {
1975 if (IsAttachment)
1976 {
1977 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
1978 if (avatar != null) avatar.StopMoveToPosition();
1979 }
1980 else
1981 {
1982 if (rootpart.PhysActor != null)
1983 {
1984 rootpart.PhysActor.PIDActive = false;
1985 }
1986 }
1987 }
1988 }
1989
1990 public void rotLookAt(Quaternion target, float strength, float damping)
1991 {
1992 SceneObjectPart rootpart = m_rootPart;
1993 if (rootpart != null)
1994 {
1995 if (IsAttachment)
1996 {
1997 /*
1998 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
1999 if (avatar != null)
2000 {
2001 Rotate the Av?
2002 } */
2003 }
2004 else
2005 {
2006 if (rootpart.PhysActor != null)
2007 { // APID must be implemented in your physics system for this to function.
2008 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2009 rootpart.PhysActor.APIDStrength = strength;
2010 rootpart.PhysActor.APIDDamping = damping;
2011 rootpart.PhysActor.APIDActive = true;
2012 }
2013 }
2014 }
1621 } 2015 }
1622 2016
1623 public void stopLookAt() 2017 public void stopLookAt()
1624 { 2018 {
1625 if (RootPart.PhysActor != null) 2019 SceneObjectPart rootpart = m_rootPart;
1626 RootPart.PhysActor.APIDActive = false; 2020 if (rootpart != null)
2021 {
2022 if (rootpart.PhysActor != null)
2023 { // APID must be implemented in your physics system for this to function.
2024 rootpart.PhysActor.APIDActive = false;
2025 }
2026 }
2027
1627 } 2028 }
1628 2029
1629 /// <summary> 2030 /// <summary>
@@ -1634,18 +2035,22 @@ namespace OpenSim.Region.Framework.Scenes
1634 /// <param name="tau">Number of seconds over which to reach target</param> 2035 /// <param name="tau">Number of seconds over which to reach target</param>
1635 public void SetHoverHeight(float height, PIDHoverType hoverType, float tau) 2036 public void SetHoverHeight(float height, PIDHoverType hoverType, float tau)
1636 { 2037 {
1637 if (RootPart.PhysActor != null) 2038 SceneObjectPart rootpart = m_rootPart;
2039 if (rootpart != null)
1638 { 2040 {
1639 if (height != 0f) 2041 if (rootpart.PhysActor != null)
1640 { 2042 {
1641 RootPart.PhysActor.PIDHoverHeight = height; 2043 if (height != 0f)
1642 RootPart.PhysActor.PIDHoverType = hoverType; 2044 {
1643 RootPart.PhysActor.PIDTau = tau; 2045 rootpart.PhysActor.PIDHoverHeight = height;
1644 RootPart.PhysActor.PIDHoverActive = true; 2046 rootpart.PhysActor.PIDHoverType = hoverType;
1645 } 2047 rootpart.PhysActor.PIDTau = tau;
1646 else 2048 rootpart.PhysActor.PIDHoverActive = true;
1647 { 2049 }
1648 RootPart.PhysActor.PIDHoverActive = false; 2050 else
2051 {
2052 rootpart.PhysActor.PIDHoverActive = false;
2053 }
1649 } 2054 }
1650 } 2055 }
1651 } 2056 }
@@ -1681,6 +2086,8 @@ namespace OpenSim.Region.Framework.Scenes
1681 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2086 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1682 { 2087 {
1683 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2088 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2089 newPart.SetParent(this);
2090
1684 AddPart(newPart); 2091 AddPart(newPart);
1685 2092
1686 SetPartAsNonRoot(newPart); 2093 SetPartAsNonRoot(newPart);
@@ -1714,11 +2121,11 @@ namespace OpenSim.Region.Framework.Scenes
1714 public void ServiceObjectPropertiesFamilyRequest(IClientAPI remoteClient, UUID AgentID, uint RequestFlags) 2121 public void ServiceObjectPropertiesFamilyRequest(IClientAPI remoteClient, UUID AgentID, uint RequestFlags)
1715 { 2122 {
1716 remoteClient.SendObjectPropertiesFamilyData(RootPart, RequestFlags); 2123 remoteClient.SendObjectPropertiesFamilyData(RootPart, RequestFlags);
1717 2124
1718 // remoteClient.SendObjectPropertiesFamilyData(RequestFlags, RootPart.UUID, RootPart.OwnerID, RootPart.GroupID, RootPart.BaseMask, 2125// remoteClient.SendObjectPropertiesFamilyData(RequestFlags, RootPart.UUID, RootPart.OwnerID, RootPart.GroupID, RootPart.BaseMask,
1719 // RootPart.OwnerMask, RootPart.GroupMask, RootPart.EveryoneMask, RootPart.NextOwnerMask, 2126// RootPart.OwnerMask, RootPart.GroupMask, RootPart.EveryoneMask, RootPart.NextOwnerMask,
1720 // RootPart.OwnershipCost, RootPart.ObjectSaleType, RootPart.SalePrice, RootPart.Category, 2127// RootPart.OwnershipCost, RootPart.ObjectSaleType, RootPart.SalePrice, RootPart.Category,
1721 // RootPart.CreatorID, RootPart.Name, RootPart.Description); 2128// RootPart.CreatorID, RootPart.Name, RootPart.Description);
1722 } 2129 }
1723 2130
1724 public void SetPartOwner(SceneObjectPart part, UUID cAgentID, UUID cGroupID) 2131 public void SetPartOwner(SceneObjectPart part, UUID cAgentID, UUID cGroupID)
@@ -1738,7 +2145,7 @@ namespace OpenSim.Region.Framework.Scenes
1738 // an object has been deleted from a scene before update was processed. 2145 // an object has been deleted from a scene before update was processed.
1739 // A more fundamental overhaul of the update mechanism is required to eliminate all 2146 // A more fundamental overhaul of the update mechanism is required to eliminate all
1740 // the race conditions. 2147 // the race conditions.
1741 if (IsDeleted) 2148 if (m_isDeleted)
1742 return; 2149 return;
1743 2150
1744 // Even temporary objects take part in physics (e.g. temp-on-rez bullets) 2151 // Even temporary objects take part in physics (e.g. temp-on-rez bullets)
@@ -1771,8 +2178,8 @@ namespace OpenSim.Region.Framework.Scenes
1771 2178
1772 public void ScheduleFullUpdateToAvatar(ScenePresence presence) 2179 public void ScheduleFullUpdateToAvatar(ScenePresence presence)
1773 { 2180 {
1774 // m_log.DebugFormat("[SOG]: Scheduling full update for {0} {1} just to avatar {2}", Name, UUID, presence.Name); 2181// m_log.DebugFormat("[SOG]: Scheduling full update for {0} {1} just to avatar {2}", Name, UUID, presence.Name);
1775 2182
1776 RootPart.AddFullUpdateToAvatar(presence); 2183 RootPart.AddFullUpdateToAvatar(presence);
1777 2184
1778 SceneObjectPart[] parts = m_parts.GetArray(); 2185 SceneObjectPart[] parts = m_parts.GetArray();
@@ -1786,7 +2193,7 @@ namespace OpenSim.Region.Framework.Scenes
1786 2193
1787 public void ScheduleTerseUpdateToAvatar(ScenePresence presence) 2194 public void ScheduleTerseUpdateToAvatar(ScenePresence presence)
1788 { 2195 {
1789 // m_log.DebugFormat("[SOG]: Scheduling terse update for {0} {1} just to avatar {2}", Name, UUID, presence.Name); 2196// m_log.DebugFormat("[SOG]: Scheduling terse update for {0} {1} just to avatar {2}", Name, UUID, presence.Name);
1790 2197
1791 SceneObjectPart[] parts = m_parts.GetArray(); 2198 SceneObjectPart[] parts = m_parts.GetArray();
1792 for (int i = 0; i < parts.Length; i++) 2199 for (int i = 0; i < parts.Length; i++)
@@ -1798,9 +2205,9 @@ namespace OpenSim.Region.Framework.Scenes
1798 /// </summary> 2205 /// </summary>
1799 public void ScheduleGroupForFullUpdate() 2206 public void ScheduleGroupForFullUpdate()
1800 { 2207 {
1801 // if (IsAttachment) 2208// if (IsAttachment)
1802 // m_log.DebugFormat("[SOG]: Scheduling full update for {0} {1}", Name, LocalId); 2209// m_log.DebugFormat("[SOG]: Scheduling full update for {0} {1}", Name, LocalId);
1803 2210
1804 checkAtTargets(); 2211 checkAtTargets();
1805 RootPart.ScheduleFullUpdate(); 2212 RootPart.ScheduleFullUpdate();
1806 2213
@@ -1818,7 +2225,7 @@ namespace OpenSim.Region.Framework.Scenes
1818 /// </summary> 2225 /// </summary>
1819 public void ScheduleGroupForTerseUpdate() 2226 public void ScheduleGroupForTerseUpdate()
1820 { 2227 {
1821 // m_log.DebugFormat("[SOG]: Scheduling terse update for {0} {1}", Name, UUID); 2228// m_log.DebugFormat("[SOG]: Scheduling terse update for {0} {1}", Name, UUID);
1822 2229
1823 SceneObjectPart[] parts = m_parts.GetArray(); 2230 SceneObjectPart[] parts = m_parts.GetArray();
1824 for (int i = 0; i < parts.Length; i++) 2231 for (int i = 0; i < parts.Length; i++)
@@ -1829,12 +2236,12 @@ namespace OpenSim.Region.Framework.Scenes
1829 /// Immediately send a full update for this scene object. 2236 /// Immediately send a full update for this scene object.
1830 /// </summary> 2237 /// </summary>
1831 public void SendGroupFullUpdate() 2238 public void SendGroupFullUpdate()
1832 { 2239 {
1833 if (IsDeleted) 2240 if (IsDeleted)
1834 return; 2241 return;
1835 2242
1836 // m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2243// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1837 2244
1838 RootPart.SendFullUpdateToAllClients(); 2245 RootPart.SendFullUpdateToAllClients();
1839 2246
1840 SceneObjectPart[] parts = m_parts.GetArray(); 2247 SceneObjectPart[] parts = m_parts.GetArray();
@@ -1864,7 +2271,7 @@ namespace OpenSim.Region.Framework.Scenes
1864 { 2271 {
1865 if (m_scene == null) // Need to check here as it's null during object creation 2272 if (m_scene == null) // Need to check here as it's null during object creation
1866 return; 2273 return;
1867 2274
1868 m_scene.SceneGraph.AddToUpdateList(this); 2275 m_scene.SceneGraph.AddToUpdateList(this);
1869 } 2276 }
1870 2277
@@ -1980,9 +2387,9 @@ namespace OpenSim.Region.Framework.Scenes
1980 // objectGroup.RootPart.SendScheduledUpdates(); 2387 // objectGroup.RootPart.SendScheduledUpdates();
1981 //} 2388 //}
1982 2389
1983 // m_log.DebugFormat( 2390// m_log.DebugFormat(
1984 // "[SCENE OBJECT GROUP]: Linking group with root part {0}, {1} to group with root part {2}, {3}", 2391// "[SCENE OBJECT GROUP]: Linking group with root part {0}, {1} to group with root part {2}, {3}",
1985 // objectGroup.RootPart.Name, objectGroup.RootPart.UUID, RootPart.Name, RootPart.UUID); 2392// objectGroup.RootPart.Name, objectGroup.RootPart.UUID, RootPart.Name, RootPart.UUID);
1986 2393
1987 SceneObjectPart linkPart = objectGroup.m_rootPart; 2394 SceneObjectPart linkPart = objectGroup.m_rootPart;
1988 2395
@@ -2022,12 +2429,15 @@ namespace OpenSim.Region.Framework.Scenes
2022 part.LinkNum += objectGroup.PrimCount; 2429 part.LinkNum += objectGroup.PrimCount;
2023 } 2430 }
2024 } 2431 }
2432 }
2025 2433
2026 linkPart.LinkNum = 2; 2434 linkPart.LinkNum = 2;
2027 2435
2028 linkPart.SetParent(this); 2436 linkPart.SetParent(this);
2029 linkPart.CreateSelected = true; 2437 linkPart.CreateSelected = true;
2030 2438
2439 lock (m_parts.SyncRoot)
2440 {
2031 //if (linkPart.PhysActor != null) 2441 //if (linkPart.PhysActor != null)
2032 //{ 2442 //{
2033 // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor); 2443 // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor);
@@ -2048,12 +2458,12 @@ namespace OpenSim.Region.Framework.Scenes
2048 } 2458 }
2049 2459
2050 m_scene.UnlinkSceneObject(objectGroup, true); 2460 m_scene.UnlinkSceneObject(objectGroup, true);
2051 objectGroup.IsDeleted = true; 2461 objectGroup.m_isDeleted = true;
2052 2462
2053 objectGroup.m_parts.Clear(); 2463 objectGroup.m_parts.Clear();
2054 2464
2055 // Can't do this yet since backup still makes use of the root part without any synchronization 2465 // Can't do this yet since backup still makes use of the root part without any synchronization
2056 // objectGroup.m_rootPart = null; 2466// objectGroup.m_rootPart = null;
2057 2467
2058 AttachToBackup(); 2468 AttachToBackup();
2059 2469
@@ -2111,10 +2521,10 @@ namespace OpenSim.Region.Framework.Scenes
2111 /// <returns>The object group of the newly delinked prim.</returns> 2521 /// <returns>The object group of the newly delinked prim.</returns>
2112 public SceneObjectGroup DelinkFromGroup(SceneObjectPart linkPart, bool sendEvents) 2522 public SceneObjectGroup DelinkFromGroup(SceneObjectPart linkPart, bool sendEvents)
2113 { 2523 {
2114 // m_log.DebugFormat( 2524// m_log.DebugFormat(
2115 // "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", 2525// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
2116 // linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); 2526// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
2117 2527
2118 linkPart.ClearUndoState(); 2528 linkPart.ClearUndoState();
2119 2529
2120 Quaternion worldRot = linkPart.GetWorldRotation(); 2530 Quaternion worldRot = linkPart.GetWorldRotation();
@@ -2185,9 +2595,11 @@ namespace OpenSim.Region.Framework.Scenes
2185 /// <param name="objectGroup"></param> 2595 /// <param name="objectGroup"></param>
2186 public virtual void DetachFromBackup() 2596 public virtual void DetachFromBackup()
2187 { 2597 {
2188 if (m_isBackedUp && Scene != null) 2598 m_scene.SceneGraph.FireDetachFromBackup(this);
2189 m_scene.EventManager.OnBackup -= ProcessBackup;
2190 2599
2600 if (m_isBackedUp)
2601 m_scene.EventManager.OnBackup -= ProcessBackup;
2602
2191 m_isBackedUp = false; 2603 m_isBackedUp = false;
2192 } 2604 }
2193 2605
@@ -2203,7 +2615,8 @@ namespace OpenSim.Region.Framework.Scenes
2203 2615
2204 axPos *= parentRot; 2616 axPos *= parentRot;
2205 part.OffsetPosition = axPos; 2617 part.OffsetPosition = axPos;
2206 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 2618 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
2619 part.GroupPosition = newPos;
2207 part.OffsetPosition = Vector3.Zero; 2620 part.OffsetPosition = Vector3.Zero;
2208 part.RotationOffset = worldRot; 2621 part.RotationOffset = worldRot;
2209 2622
@@ -2214,7 +2627,7 @@ namespace OpenSim.Region.Framework.Scenes
2214 2627
2215 part.LinkNum = linkNum; 2628 part.LinkNum = linkNum;
2216 2629
2217 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 2630 part.OffsetPosition = newPos - AbsolutePosition;
2218 2631
2219 Quaternion rootRotation = m_rootPart.RotationOffset; 2632 Quaternion rootRotation = m_rootPart.RotationOffset;
2220 2633
@@ -2224,7 +2637,7 @@ namespace OpenSim.Region.Framework.Scenes
2224 2637
2225 parentRot = m_rootPart.RotationOffset; 2638 parentRot = m_rootPart.RotationOffset;
2226 oldRot = part.RotationOffset; 2639 oldRot = part.RotationOffset;
2227 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2640 Quaternion newRot = Quaternion.Inverse(parentRot) * worldRot;
2228 part.RotationOffset = newRot; 2641 part.RotationOffset = newRot;
2229 } 2642 }
2230 2643
@@ -2322,7 +2735,7 @@ namespace OpenSim.Region.Framework.Scenes
2322 // but it will result in over-shoot or under-shoot of the target orientation. 2735 // but it will result in over-shoot or under-shoot of the target orientation.
2323 // For the end user, this means that ctrl+shift+drag can be used for relative, 2736 // For the end user, this means that ctrl+shift+drag can be used for relative,
2324 // but not absolute, adjustments of orientation for physical prims. 2737 // but not absolute, adjustments of orientation for physical prims.
2325 2738
2326 if (m_scene.EventManager.TriggerGroupSpin(UUID, newOrientation)) 2739 if (m_scene.EventManager.TriggerGroupSpin(UUID, newOrientation))
2327 { 2740 {
2328 if (m_rootPart.PhysActor != null) 2741 if (m_rootPart.PhysActor != null)
@@ -2337,25 +2750,25 @@ namespace OpenSim.Region.Framework.Scenes
2337 } 2750 }
2338 else 2751 else
2339 { 2752 {
2340 // save and update old orientation 2753 // save and update old orientation
2341 Quaternion old = m_rootPart.SpinOldOrientation; 2754 Quaternion old = m_rootPart.SpinOldOrientation;
2342 m_rootPart.SpinOldOrientation = newOrientation; 2755 m_rootPart.SpinOldOrientation = newOrientation;
2343 //m_log.Error("[SCENE OBJECT GROUP]: Old orientation is " + old); 2756 //m_log.Error("[SCENE OBJECT GROUP]: Old orientation is " + old);
2344 //m_log.Error("[SCENE OBJECT GROUP]: Incoming new orientation is " + newOrientation); 2757 //m_log.Error("[SCENE OBJECT GROUP]: Incoming new orientation is " + newOrientation);
2345 2758
2346 // compute difference between previous old rotation and new incoming rotation 2759 // compute difference between previous old rotation and new incoming rotation
2347 Quaternion minimalRotationFromQ1ToQ2 = Quaternion.Inverse(old) * newOrientation; 2760 Quaternion minimalRotationFromQ1ToQ2 = Quaternion.Inverse(old) * newOrientation;
2348 2761
2349 float rotationAngle; 2762 float rotationAngle;
2350 Vector3 rotationAxis; 2763 Vector3 rotationAxis;
2351 minimalRotationFromQ1ToQ2.GetAxisAngle(out rotationAxis, out rotationAngle); 2764 minimalRotationFromQ1ToQ2.GetAxisAngle(out rotationAxis, out rotationAngle);
2352 rotationAxis.Normalize(); 2765 rotationAxis.Normalize();
2353 2766
2354 //m_log.Error("SCENE OBJECT GROUP]: rotation axis is " + rotationAxis); 2767 //m_log.Error("SCENE OBJECT GROUP]: rotation axis is " + rotationAxis);
2355 Vector3 spinforce = new Vector3(rotationAxis.X, rotationAxis.Y, rotationAxis.Z); 2768 Vector3 spinforce = new Vector3(rotationAxis.X, rotationAxis.Y, rotationAxis.Z);
2356 spinforce = (spinforce / 8) * m_rootPart.PhysActor.Mass; // 8 is an arbitrary torque scaling factor 2769 spinforce = (spinforce/8) * m_rootPart.PhysActor.Mass; // 8 is an arbitrary torque scaling factor
2357 m_rootPart.PhysActor.AddAngularForce(spinforce, true); 2770 m_rootPart.PhysActor.AddAngularForce(spinforce,true);
2358 m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor); 2771 m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor);
2359 } 2772 }
2360 } 2773 }
2361 else 2774 else
@@ -2444,15 +2857,14 @@ namespace OpenSim.Region.Framework.Scenes
2444 /// Update prim flags for this group. 2857 /// Update prim flags for this group.
2445 /// </summary> 2858 /// </summary>
2446 /// <param name="localID"></param> 2859 /// <param name="localID"></param>
2447 /// <param name="UsePhysics"></param> 2860 /// <param name="type"></param>
2448 /// <param name="SetTemporary"></param> 2861 /// <param name="inUse"></param>
2449 /// <param name="SetPhantom"></param> 2862 /// <param name="data"></param>
2450 /// <param name="SetVolumeDetect"></param> 2863 public void UpdatePrimFlags(uint localID, bool UsePhysics, bool IsTemporary, bool IsPhantom, bool IsVolumeDetect)
2451 public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect)
2452 { 2864 {
2453 SceneObjectPart selectionPart = GetChildPart(localID); 2865 SceneObjectPart selectionPart = GetChildPart(localID);
2454 2866
2455 if (SetTemporary && Scene != null) 2867 if (IsTemporary)
2456 { 2868 {
2457 DetachFromBackup(); 2869 DetachFromBackup();
2458 // Remove from database and parcel prim count 2870 // Remove from database and parcel prim count
@@ -2464,24 +2876,24 @@ namespace OpenSim.Region.Framework.Scenes
2464 if (selectionPart != null) 2876 if (selectionPart != null)
2465 { 2877 {
2466 SceneObjectPart[] parts = m_parts.GetArray(); 2878 SceneObjectPart[] parts = m_parts.GetArray();
2467 2879 for (int i = 0; i < parts.Length; i++)
2468 if (Scene != null)
2469 { 2880 {
2470 for (int i = 0; i < parts.Length; i++) 2881 SceneObjectPart part = parts[i];
2882 if (part.Scale.X > m_scene.RegionInfo.PhysPrimMax ||
2883 part.Scale.Y > m_scene.RegionInfo.PhysPrimMax ||
2884 part.Scale.Z > m_scene.RegionInfo.PhysPrimMax)
2471 { 2885 {
2472 SceneObjectPart part = parts[i]; 2886 UsePhysics = false; // Reset physics
2473 if (part.Scale.X > m_scene.RegionInfo.PhysPrimMax || 2887 break;
2474 part.Scale.Y > m_scene.RegionInfo.PhysPrimMax ||
2475 part.Scale.Z > m_scene.RegionInfo.PhysPrimMax)
2476 {
2477 UsePhysics = false; // Reset physics
2478 break;
2479 }
2480 } 2888 }
2481 } 2889 }
2482 2890
2891 RootPart.UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
2483 for (int i = 0; i < parts.Length; i++) 2892 for (int i = 0; i < parts.Length; i++)
2484 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 2893 {
2894 if (parts[i] != RootPart)
2895 parts[i].UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
2896 }
2485 } 2897 }
2486 } 2898 }
2487 2899
@@ -2494,6 +2906,17 @@ namespace OpenSim.Region.Framework.Scenes
2494 } 2906 }
2495 } 2907 }
2496 2908
2909
2910
2911 /// <summary>
2912 /// Gets the number of parts
2913 /// </summary>
2914 /// <returns></returns>
2915 public int GetPartCount()
2916 {
2917 return Parts.Count();
2918 }
2919
2497 /// <summary> 2920 /// <summary>
2498 /// Update the texture entry for this part 2921 /// Update the texture entry for this part
2499 /// </summary> 2922 /// </summary>
@@ -2543,150 +2966,202 @@ namespace OpenSim.Region.Framework.Scenes
2543 #region Resize 2966 #region Resize
2544 2967
2545 /// <summary> 2968 /// <summary>
2546 /// Resize the entire group of prims. 2969 /// Resize the given part
2547 /// </summary> 2970 /// </summary>
2548 /// <param name="scale"></param> 2971 /// <param name="scale"></param>
2549 public void GroupResize(Vector3 scale) 2972 /// <param name="localID"></param>
2550 { 2973 public void Resize(Vector3 scale, uint localID)
2551 // m_log.DebugFormat( 2974 {
2552 // "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale); 2975 if (scale.X > m_scene.m_maxNonphys)
2553 2976 scale.X = m_scene.m_maxNonphys;
2554 RootPart.StoreUndoState(true); 2977 if (scale.Y > m_scene.m_maxNonphys)
2978 scale.Y = m_scene.m_maxNonphys;
2979 if (scale.Z > m_scene.m_maxNonphys)
2980 scale.Z = m_scene.m_maxNonphys;
2981 SceneObjectPart part = GetChildPart(localID);
2982 if (part != null)
2983 {
2984 if (part.PhysActor != null)
2985 {
2986 if (part.PhysActor.IsPhysical)
2987 {
2988 if (scale.X > m_scene.m_maxPhys)
2989 scale.X = m_scene.m_maxPhys;
2990 if (scale.Y > m_scene.m_maxPhys)
2991 scale.Y = m_scene.m_maxPhys;
2992 if (scale.Z > m_scene.m_maxPhys)
2993 scale.Z = m_scene.m_maxPhys;
2994 }
2995 part.PhysActor.Size = scale;
2996 m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor);
2997 }
2998 part.Resize(scale);
2555 2999
2556 scale.X = Math.Min(scale.X, Scene.m_maxNonphys); 3000 HasGroupChanged = true;
2557 scale.Y = Math.Min(scale.Y, Scene.m_maxNonphys); 3001 part.TriggerScriptChangedEvent(Changed.SCALE);
2558 scale.Z = Math.Min(scale.Z, Scene.m_maxNonphys); 3002 ScheduleGroupForFullUpdate();
2559 3003
2560 if (RootPart.PhysActor != null && RootPart.PhysActor.IsPhysical) 3004 //if (part.UUID == m_rootPart.UUID)
2561 { 3005 //{
2562 scale.X = Math.Min(scale.X, Scene.m_maxPhys); 3006 //if (m_rootPart.PhysActor != null)
2563 scale.Y = Math.Min(scale.Y, Scene.m_maxPhys); 3007 //{
2564 scale.Z = Math.Min(scale.Z, Scene.m_maxPhys); 3008 //m_rootPart.PhysActor.Size =
3009 //new PhysicsVector(m_rootPart.Scale.X, m_rootPart.Scale.Y, m_rootPart.Scale.Z);
3010 //m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor);
3011 //}
3012 //}
2565 } 3013 }
3014 }
2566 3015
2567 float x = (scale.X / RootPart.Scale.X); 3016 public void GroupResize(Vector3 scale, uint localID)
2568 float y = (scale.Y / RootPart.Scale.Y); 3017 {
2569 float z = (scale.Z / RootPart.Scale.Z); 3018 SceneObjectPart part = GetChildPart(localID);
2570 3019 if (part != null)
2571 SceneObjectPart[] parts;
2572 if (x > 1.0f || y > 1.0f || z > 1.0f)
2573 { 3020 {
2574 parts = m_parts.GetArray(); 3021 if (scale.X > m_scene.m_maxNonphys)
2575 for (int i = 0; i < parts.Length; i++) 3022 scale.X = m_scene.m_maxNonphys;
3023 if (scale.Y > m_scene.m_maxNonphys)
3024 scale.Y = m_scene.m_maxNonphys;
3025 if (scale.Z > m_scene.m_maxNonphys)
3026 scale.Z = m_scene.m_maxNonphys;
3027 if (part.PhysActor != null && part.PhysActor.IsPhysical)
2576 { 3028 {
2577 SceneObjectPart obPart = parts[i]; 3029 if (scale.X > m_scene.m_maxPhys)
2578 if (obPart.UUID != m_rootPart.UUID) 3030 scale.X = m_scene.m_maxPhys;
2579 { 3031 if (scale.Y > m_scene.m_maxPhys)
2580 // obPart.IgnoreUndoUpdate = true; 3032 scale.Y = m_scene.m_maxPhys;
2581 Vector3 oldSize = new Vector3(obPart.Scale); 3033 if (scale.Z > m_scene.m_maxPhys)
2582 3034 scale.Z = m_scene.m_maxPhys;
2583 float f = 1.0f; 3035 }
2584 float a = 1.0f; 3036 float x = (scale.X / part.Scale.X);
3037 float y = (scale.Y / part.Scale.Y);
3038 float z = (scale.Z / part.Scale.Z);
2585 3039
2586 if (RootPart.PhysActor != null && RootPart.PhysActor.IsPhysical) 3040 SceneObjectPart[] parts;
3041 if (x > 1.0f || y > 1.0f || z > 1.0f)
3042 {
3043 parts = m_parts.GetArray();
3044 for (int i = 0; i < parts.Length; i++)
3045 {
3046 SceneObjectPart obPart = parts[i];
3047 if (obPart.UUID != m_rootPart.UUID)
2587 { 3048 {
2588 if (oldSize.X * x > m_scene.m_maxPhys) 3049 obPart.IgnoreUndoUpdate = true;
2589 { 3050 Vector3 oldSize = new Vector3(obPart.Scale);
2590 f = m_scene.m_maxPhys / oldSize.X;
2591 a = f / x;
2592 x *= a;
2593 y *= a;
2594 z *= a;
2595 }
2596 3051
2597 if (oldSize.Y * y > m_scene.m_maxPhys) 3052 float f = 1.0f;
2598 { 3053 float a = 1.0f;
2599 f = m_scene.m_maxPhys / oldSize.Y;
2600 a = f / y;
2601 x *= a;
2602 y *= a;
2603 z *= a;
2604 }
2605
2606 if (oldSize.Z * z > m_scene.m_maxPhys)
2607 {
2608 f = m_scene.m_maxPhys / oldSize.Z;
2609 a = f / z;
2610 x *= a;
2611 y *= a;
2612 z *= a;
2613 }
2614 }
2615 else
2616 {
2617 if (oldSize.X * x > m_scene.m_maxNonphys)
2618 {
2619 f = m_scene.m_maxNonphys / oldSize.X;
2620 a = f / x;
2621 x *= a;
2622 y *= a;
2623 z *= a;
2624 }
2625 3054
2626 if (oldSize.Y * y > m_scene.m_maxNonphys) 3055 if (part.PhysActor != null && part.PhysActor.IsPhysical)
2627 { 3056 {
2628 f = m_scene.m_maxNonphys / oldSize.Y; 3057 if (oldSize.X*x > m_scene.m_maxPhys)
2629 a = f / y; 3058 {
2630 x *= a; 3059 f = m_scene.m_maxPhys / oldSize.X;
2631 y *= a; 3060 a = f / x;
2632 z *= a; 3061 x *= a;
3062 y *= a;
3063 z *= a;
3064 }
3065 if (oldSize.Y*y > m_scene.m_maxPhys)
3066 {
3067 f = m_scene.m_maxPhys / oldSize.Y;
3068 a = f / y;
3069 x *= a;
3070 y *= a;
3071 z *= a;
3072 }
3073 if (oldSize.Z*z > m_scene.m_maxPhys)
3074 {
3075 f = m_scene.m_maxPhys / oldSize.Z;
3076 a = f / z;
3077 x *= a;
3078 y *= a;
3079 z *= a;
3080 }
2633 } 3081 }
2634 3082 else
2635 if (oldSize.Z * z > m_scene.m_maxNonphys)
2636 { 3083 {
2637 f = m_scene.m_maxNonphys / oldSize.Z; 3084 if (oldSize.X*x > m_scene.m_maxNonphys)
2638 a = f / z; 3085 {
2639 x *= a; 3086 f = m_scene.m_maxNonphys / oldSize.X;
2640 y *= a; 3087 a = f / x;
2641 z *= a; 3088 x *= a;
3089 y *= a;
3090 z *= a;
3091 }
3092 if (oldSize.Y*y > m_scene.m_maxNonphys)
3093 {
3094 f = m_scene.m_maxNonphys / oldSize.Y;
3095 a = f / y;
3096 x *= a;
3097 y *= a;
3098 z *= a;
3099 }
3100 if (oldSize.Z*z > m_scene.m_maxNonphys)
3101 {
3102 f = m_scene.m_maxNonphys / oldSize.Z;
3103 a = f / z;
3104 x *= a;
3105 y *= a;
3106 z *= a;
3107 }
2642 } 3108 }
3109 obPart.IgnoreUndoUpdate = false;
2643 } 3110 }
2644
2645 // obPart.IgnoreUndoUpdate = false;
2646 } 3111 }
2647 } 3112 }
2648 }
2649
2650 Vector3 prevScale = RootPart.Scale;
2651 prevScale.X *= x;
2652 prevScale.Y *= y;
2653 prevScale.Z *= z;
2654 3113
2655 // RootPart.IgnoreUndoUpdate = true; 3114 Vector3 prevScale = part.Scale;
2656 RootPart.Resize(prevScale); 3115 prevScale.X *= x;
2657 // RootPart.IgnoreUndoUpdate = false; 3116 prevScale.Y *= y;
3117 prevScale.Z *= z;;
2658 3118
2659 parts = m_parts.GetArray(); 3119 part.IgnoreUndoUpdate = false;
2660 for (int i = 0; i < parts.Length; i++) 3120 part.StoreUndoState(UndoType.STATE_GROUP_SCALE);
2661 { 3121 part.IgnoreUndoUpdate = true;
2662 SceneObjectPart obPart = parts[i]; 3122 part.Resize(prevScale);
3123 part.IgnoreUndoUpdate = false;
2663 3124
2664 if (obPart.UUID != m_rootPart.UUID) 3125 parts = m_parts.GetArray();
3126 for (int i = 0; i < parts.Length; i++)
2665 { 3127 {
3128 SceneObjectPart obPart = parts[i];
2666 obPart.IgnoreUndoUpdate = true; 3129 obPart.IgnoreUndoUpdate = true;
2667 3130 if (obPart.UUID != m_rootPart.UUID)
2668 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3131 {
2669 currentpos.X *= x; 3132 if (obPart.UUID != m_rootPart.UUID)
2670 currentpos.Y *= y; 3133 {
2671 currentpos.Z *= z; 3134 obPart.IgnoreUndoUpdate = false;
2672 3135 obPart.StoreUndoState(UndoType.STATE_GROUP_SCALE);
2673 Vector3 newSize = new Vector3(obPart.Scale); 3136 obPart.IgnoreUndoUpdate = true;
2674 newSize.X *= x; 3137
2675 newSize.Y *= y; 3138 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2676 newSize.Z *= z; 3139 currentpos.X *= x;
2677 3140 currentpos.Y *= y;
2678 obPart.Resize(newSize); 3141 currentpos.Z *= z;
2679 obPart.UpdateOffSet(currentpos); 3142 Vector3 newSize = new Vector3(obPart.Scale);
2680 3143 newSize.X *= x;
3144 newSize.Y *= y;
3145 newSize.Z *= z;
3146 obPart.Resize(newSize);
3147 obPart.UpdateOffSet(currentpos);
3148 }
3149 obPart.IgnoreUndoUpdate = false;
3150 }
2681 obPart.IgnoreUndoUpdate = false; 3151 obPart.IgnoreUndoUpdate = false;
2682 } 3152 }
2683 3153
2684 // obPart.IgnoreUndoUpdate = false; 3154 if (part.PhysActor != null)
2685 // obPart.StoreUndoState(); 3155 {
2686 } 3156 part.PhysActor.Size = prevScale;
3157 m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor);
3158 }
2687 3159
2688 // m_log.DebugFormat( 3160 part.IgnoreUndoUpdate = false;
2689 // "[SCENE OBJECT GROUP]: Finished group resizing {0} {1} to {2}", Name, LocalId, RootPart.Scale); 3161 HasGroupChanged = true;
3162 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3163 ScheduleGroupForTerseUpdate();
3164 }
2690 } 3165 }
2691 3166
2692 #endregion 3167 #endregion
@@ -2699,18 +3174,11 @@ namespace OpenSim.Region.Framework.Scenes
2699 /// <param name="pos"></param> 3174 /// <param name="pos"></param>
2700 public void UpdateGroupPosition(Vector3 pos) 3175 public void UpdateGroupPosition(Vector3 pos)
2701 { 3176 {
2702 // m_log.DebugFormat("[SCENE OBJECT GROUP]: Updating group position on {0} {1} to {2}", Name, LocalId, pos);
2703
2704 RootPart.StoreUndoState(true);
2705
2706 // SceneObjectPart[] parts = m_parts.GetArray();
2707 // for (int i = 0; i < parts.Length; i++)
2708 // parts[i].StoreUndoState();
2709
2710 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 3177 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2711 { 3178 {
2712 if (IsAttachment) 3179 if (IsAttachment)
2713 { 3180 {
3181 m_rootPart.StoreUndoState(UndoType.STATE_GROUP_POSITION);
2714 m_rootPart.AttachedPos = pos; 3182 m_rootPart.AttachedPos = pos;
2715 } 3183 }
2716 if (RootPart.GetStatusSandbox()) 3184 if (RootPart.GetStatusSandbox())
@@ -2742,18 +3210,12 @@ namespace OpenSim.Region.Framework.Scenes
2742 { 3210 {
2743 SceneObjectPart part = GetChildPart(localID); 3211 SceneObjectPart part = GetChildPart(localID);
2744 3212
2745 // SceneObjectPart[] parts = m_parts.GetArray(); 3213 SceneObjectPart[] parts = m_parts.GetArray();
2746 // for (int i = 0; i < parts.Length; i++) 3214 for (int i = 0; i < parts.Length; i++)
2747 // parts[i].StoreUndoState(); 3215 parts[i].StoreUndoState(UndoType.STATE_PRIM_POSITION);
2748 3216
2749 if (part != null) 3217 if (part != null)
2750 { 3218 {
2751 // m_log.DebugFormat(
2752 // "[SCENE OBJECT GROUP]: Updating single position of {0} {1} to {2}", part.Name, part.LocalId, pos);
2753
2754 part.StoreUndoState(false);
2755 part.IgnoreUndoUpdate = true;
2756
2757 if (part.UUID == m_rootPart.UUID) 3219 if (part.UUID == m_rootPart.UUID)
2758 { 3220 {
2759 UpdateRootPosition(pos); 3221 UpdateRootPosition(pos);
@@ -2764,22 +3226,18 @@ namespace OpenSim.Region.Framework.Scenes
2764 } 3226 }
2765 3227
2766 HasGroupChanged = true; 3228 HasGroupChanged = true;
2767 part.IgnoreUndoUpdate = false;
2768 } 3229 }
2769 } 3230 }
2770 3231
2771 /// <summary> 3232 /// <summary>
2772 /// Update just the root prim position in a linkset 3233 ///
2773 /// </summary> 3234 /// </summary>
2774 /// <param name="pos"></param> 3235 /// <param name="pos"></param>
2775 public void UpdateRootPosition(Vector3 pos) 3236 private void UpdateRootPosition(Vector3 pos)
2776 { 3237 {
2777 // m_log.DebugFormat( 3238 SceneObjectPart[] parts = m_parts.GetArray();
2778 // "[SCENE OBJECT GROUP]: Updating root position of {0} {1} to {2}", Name, LocalId, pos); 3239 for (int i = 0; i < parts.Length; i++)
2779 3240 parts[i].StoreUndoState(UndoType.STATE_PRIM_POSITION);
2780 // SceneObjectPart[] parts = m_parts.GetArray();
2781 // for (int i = 0; i < parts.Length; i++)
2782 // parts[i].StoreUndoState();
2783 3241
2784 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3242 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
2785 Vector3 oldPos = 3243 Vector3 oldPos =
@@ -2792,7 +3250,7 @@ namespace OpenSim.Region.Framework.Scenes
2792 axDiff *= Quaternion.Inverse(partRotation); 3250 axDiff *= Quaternion.Inverse(partRotation);
2793 diff = axDiff; 3251 diff = axDiff;
2794 3252
2795 SceneObjectPart[] parts = m_parts.GetArray(); 3253 parts = m_parts.GetArray();
2796 for (int i = 0; i < parts.Length; i++) 3254 for (int i = 0; i < parts.Length; i++)
2797 { 3255 {
2798 SceneObjectPart obPart = parts[i]; 3256 SceneObjectPart obPart = parts[i];
@@ -2800,10 +3258,27 @@ namespace OpenSim.Region.Framework.Scenes
2800 obPart.OffsetPosition = obPart.OffsetPosition + diff; 3258 obPart.OffsetPosition = obPart.OffsetPosition + diff;
2801 } 3259 }
2802 3260
2803 AbsolutePosition = newPos; 3261 //We have to set undoing here because otherwise an undo state will be saved
3262 if (!m_rootPart.Undoing)
3263 {
3264 m_rootPart.Undoing = true;
3265 AbsolutePosition = newPos;
3266 m_rootPart.Undoing = false;
3267 }
3268 else
3269 {
3270 AbsolutePosition = newPos;
3271 }
2804 3272
2805 HasGroupChanged = true; 3273 HasGroupChanged = true;
2806 ScheduleGroupForTerseUpdate(); 3274 if (m_rootPart.Undoing)
3275 {
3276 ScheduleGroupForFullUpdate();
3277 }
3278 else
3279 {
3280 ScheduleGroupForTerseUpdate();
3281 }
2807 } 3282 }
2808 3283
2809 public void OffsetForNewRegion(Vector3 offset) 3284 public void OffsetForNewRegion(Vector3 offset)
@@ -2821,14 +3296,9 @@ namespace OpenSim.Region.Framework.Scenes
2821 /// <param name="rot"></param> 3296 /// <param name="rot"></param>
2822 public void UpdateGroupRotationR(Quaternion rot) 3297 public void UpdateGroupRotationR(Quaternion rot)
2823 { 3298 {
2824 // m_log.DebugFormat( 3299 SceneObjectPart[] parts = m_parts.GetArray();
2825 // "[SCENE OBJECT GROUP]: Updating group rotation R of {0} {1} to {2}", Name, LocalId, rot); 3300 for (int i = 0; i < parts.Length; i++)
2826 3301 parts[i].StoreUndoState(UndoType.STATE_GROUP_ROTATION);
2827 // SceneObjectPart[] parts = m_parts.GetArray();
2828 // for (int i = 0; i < parts.Length; i++)
2829 // parts[i].StoreUndoState();
2830
2831 m_rootPart.StoreUndoState(true);
2832 3302
2833 m_rootPart.UpdateRotation(rot); 3303 m_rootPart.UpdateRotation(rot);
2834 3304
@@ -2850,15 +3320,9 @@ namespace OpenSim.Region.Framework.Scenes
2850 /// <param name="rot"></param> 3320 /// <param name="rot"></param>
2851 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) 3321 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot)
2852 { 3322 {
2853 // m_log.DebugFormat( 3323 SceneObjectPart[] parts = m_parts.GetArray();
2854 // "[SCENE OBJECT GROUP]: Updating group rotation PR of {0} {1} to {2}", Name, LocalId, rot); 3324 for (int i = 0; i < parts.Length; i++)
2855 3325 parts[i].StoreUndoState(UndoType.STATE_GROUP_ROTATION);
2856 // SceneObjectPart[] parts = m_parts.GetArray();
2857 // for (int i = 0; i < parts.Length; i++)
2858 // parts[i].StoreUndoState();
2859
2860 RootPart.StoreUndoState(true);
2861 RootPart.IgnoreUndoUpdate = true;
2862 3326
2863 m_rootPart.UpdateRotation(rot); 3327 m_rootPart.UpdateRotation(rot);
2864 3328
@@ -2873,8 +3337,6 @@ namespace OpenSim.Region.Framework.Scenes
2873 3337
2874 HasGroupChanged = true; 3338 HasGroupChanged = true;
2875 ScheduleGroupForTerseUpdate(); 3339 ScheduleGroupForTerseUpdate();
2876
2877 RootPart.IgnoreUndoUpdate = false;
2878 } 3340 }
2879 3341
2880 /// <summary> 3342 /// <summary>
@@ -2885,16 +3347,12 @@ namespace OpenSim.Region.Framework.Scenes
2885 public void UpdateSingleRotation(Quaternion rot, uint localID) 3347 public void UpdateSingleRotation(Quaternion rot, uint localID)
2886 { 3348 {
2887 SceneObjectPart part = GetChildPart(localID); 3349 SceneObjectPart part = GetChildPart(localID);
2888
2889 SceneObjectPart[] parts = m_parts.GetArray(); 3350 SceneObjectPart[] parts = m_parts.GetArray();
2890 for (int i = 0; i < parts.Length; i++) 3351 for (int i = 0; i < parts.Length; i++)
2891 parts[i].StoreUndoState(); 3352 parts[i].StoreUndoState(UndoType.STATE_PRIM_ROTATION);
2892 3353
2893 if (part != null) 3354 if (part != null)
2894 { 3355 {
2895 // m_log.DebugFormat(
2896 // "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot);
2897
2898 if (part.UUID == m_rootPart.UUID) 3356 if (part.UUID == m_rootPart.UUID)
2899 { 3357 {
2900 UpdateRootRotation(rot); 3358 UpdateRootRotation(rot);
@@ -2916,25 +3374,28 @@ namespace OpenSim.Region.Framework.Scenes
2916 SceneObjectPart part = GetChildPart(localID); 3374 SceneObjectPart part = GetChildPart(localID);
2917 if (part != null) 3375 if (part != null)
2918 { 3376 {
2919 // m_log.DebugFormat(
2920 // "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}",
2921 // part.Name, part.LocalId, rot);
2922
2923 part.StoreUndoState();
2924 part.IgnoreUndoUpdate = true;
2925
2926 if (part.UUID == m_rootPart.UUID) 3377 if (part.UUID == m_rootPart.UUID)
2927 { 3378 {
2928 UpdateRootRotation(rot); 3379 UpdateRootRotation(rot);
2929 AbsolutePosition = pos; 3380 if (!m_rootPart.Undoing)
3381 {
3382 m_rootPart.Undoing = true;
3383 AbsolutePosition = pos;
3384 m_rootPart.Undoing = false;
3385 }
3386 else
3387 {
3388 AbsolutePosition = pos;
3389 }
2930 } 3390 }
2931 else 3391 else
2932 { 3392 {
3393 part.StoreUndoState(UndoType.STATE_PRIM_ROTATION);
3394 part.IgnoreUndoUpdate = true;
2933 part.UpdateRotation(rot); 3395 part.UpdateRotation(rot);
2934 part.OffsetPosition = pos; 3396 part.OffsetPosition = pos;
3397 part.IgnoreUndoUpdate = false;
2935 } 3398 }
2936
2937 part.IgnoreUndoUpdate = false;
2938 } 3399 }
2939 } 3400 }
2940 3401
@@ -2942,17 +3403,21 @@ namespace OpenSim.Region.Framework.Scenes
2942 /// 3403 ///
2943 /// </summary> 3404 /// </summary>
2944 /// <param name="rot"></param> 3405 /// <param name="rot"></param>
2945 public void UpdateRootRotation(Quaternion rot) 3406 private void UpdateRootRotation(Quaternion rot)
2946 { 3407 {
2947 // m_log.DebugFormat(
2948 // "[SCENE OBJECT GROUP]: Updating root rotation of {0} {1} to {2}",
2949 // Name, LocalId, rot);
2950
2951 Quaternion axRot = rot; 3408 Quaternion axRot = rot;
2952 Quaternion oldParentRot = m_rootPart.RotationOffset; 3409 Quaternion oldParentRot = m_rootPart.RotationOffset;
2953 3410
2954 m_rootPart.StoreUndoState(); 3411 m_rootPart.StoreUndoState(UndoType.STATE_PRIM_ROTATION);
2955 m_rootPart.UpdateRotation(rot); 3412 bool cancelUndo = false;
3413 if (!m_rootPart.Undoing)
3414 {
3415 m_rootPart.Undoing = true;
3416 cancelUndo = true;
3417 }
3418
3419 //Don't use UpdateRotation because it schedules an update prematurely
3420 m_rootPart.RotationOffset = rot;
2956 if (m_rootPart.PhysActor != null) 3421 if (m_rootPart.PhysActor != null)
2957 { 3422 {
2958 m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset; 3423 m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset;
@@ -2967,33 +3432,22 @@ namespace OpenSim.Region.Framework.Scenes
2967 { 3432 {
2968 prim.IgnoreUndoUpdate = true; 3433 prim.IgnoreUndoUpdate = true;
2969 Vector3 axPos = prim.OffsetPosition; 3434 Vector3 axPos = prim.OffsetPosition;
3435
2970 axPos *= oldParentRot; 3436 axPos *= oldParentRot;
2971 axPos *= Quaternion.Inverse(axRot); 3437 axPos *= Quaternion.Inverse(axRot);
2972 prim.OffsetPosition = axPos; 3438 prim.OffsetPosition = axPos;
2973 Quaternion primsRot = prim.RotationOffset; 3439
2974 Quaternion newRot = primsRot * oldParentRot; 3440 prim.RotationOffset *= Quaternion.Inverse(prim.GetWorldRotation()) * (oldParentRot * prim.RotationOffset);
2975 newRot *= Quaternion.Inverse(axRot); 3441
2976 prim.RotationOffset = newRot;
2977 prim.ScheduleTerseUpdate();
2978 prim.IgnoreUndoUpdate = false; 3442 prim.IgnoreUndoUpdate = false;
2979 } 3443 }
2980 } 3444 }
2981 3445 if (cancelUndo == true)
2982 // for (int i = 0; i < parts.Length; i++) 3446 {
2983 // { 3447 m_rootPart.Undoing = false;
2984 // SceneObjectPart childpart = parts[i]; 3448 }
2985 // if (childpart != m_rootPart) 3449 HasGroupChanged = true;
2986 // { 3450 ScheduleGroupForFullUpdate();
2987 //// childpart.IgnoreUndoUpdate = false;
2988 //// childpart.StoreUndoState();
2989 // }
2990 // }
2991
2992 m_rootPart.ScheduleTerseUpdate();
2993
2994 // m_log.DebugFormat(
2995 // "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}",
2996 // Name, LocalId, rot);
2997 } 3451 }
2998 3452
2999 #endregion 3453 #endregion
@@ -3008,23 +3462,28 @@ namespace OpenSim.Region.Framework.Scenes
3008 int yaxis = 4; 3462 int yaxis = 4;
3009 int zaxis = 8; 3463 int zaxis = 8;
3010 3464
3011 setX = ((axis & xaxis) != 0) ? true : false; 3465 if (m_rootPart != null)
3012 setY = ((axis & yaxis) != 0) ? true : false; 3466 {
3013 setZ = ((axis & zaxis) != 0) ? true : false; 3467 setX = ((axis & xaxis) != 0) ? true : false;
3468 setY = ((axis & yaxis) != 0) ? true : false;
3469 setZ = ((axis & zaxis) != 0) ? true : false;
3014 3470
3015 float setval = (rotate10 > 0) ? 1f : 0f; 3471 float setval = (rotate10 > 0) ? 1f : 0f;
3016 3472
3017 if (setX) 3473 if (setX)
3018 RootPart.RotationAxis.X = setval; 3474 m_rootPart.RotationAxis.X = setval;
3019 if (setY) 3475 if (setY)
3020 RootPart.RotationAxis.Y = setval; 3476 m_rootPart.RotationAxis.Y = setval;
3021 if (setZ) 3477 if (setZ)
3022 RootPart.RotationAxis.Z = setval; 3478 m_rootPart.RotationAxis.Z = setval;
3023 3479
3024 if (setX || setY || setZ) 3480 if (setX || setY || setZ)
3025 RootPart.SetPhysicsAxisRotation(); 3481 {
3026 } 3482 m_rootPart.SetPhysicsAxisRotation();
3483 }
3027 3484
3485 }
3486 }
3028 public int registerRotTargetWaypoint(Quaternion target, float tolerance) 3487 public int registerRotTargetWaypoint(Quaternion target, float tolerance)
3029 { 3488 {
3030 scriptRotTarget waypoint = new scriptRotTarget(); 3489 scriptRotTarget waypoint = new scriptRotTarget();
@@ -3064,7 +3523,7 @@ namespace OpenSim.Region.Framework.Scenes
3064 m_scene.AddGroupTarget(this); 3523 m_scene.AddGroupTarget(this);
3065 return (int)handle; 3524 return (int)handle;
3066 } 3525 }
3067 3526
3068 public void unregisterTargetWaypoint(int handle) 3527 public void unregisterTargetWaypoint(int handle)
3069 { 3528 {
3070 lock (m_targets) 3529 lock (m_targets)
@@ -3105,14 +3564,14 @@ namespace OpenSim.Region.Framework.Scenes
3105 } 3564 }
3106 } 3565 }
3107 } 3566 }
3108 3567
3109 if (atTargets.Count > 0) 3568 if (atTargets.Count > 0)
3110 { 3569 {
3111 SceneObjectPart[] parts = m_parts.GetArray(); 3570 SceneObjectPart[] parts = m_parts.GetArray();
3112 uint[] localids = new uint[parts.Length]; 3571 uint[] localids = new uint[parts.Length];
3113 for (int i = 0; i < parts.Length; i++) 3572 for (int i = 0; i < parts.Length; i++)
3114 localids[i] = parts[i].LocalId; 3573 localids[i] = parts[i].LocalId;
3115 3574
3116 for (int ctr = 0; ctr < localids.Length; ctr++) 3575 for (int ctr = 0; ctr < localids.Length; ctr++)
3117 { 3576 {
3118 foreach (uint target in atTargets.Keys) 3577 foreach (uint target in atTargets.Keys)
@@ -3122,10 +3581,10 @@ namespace OpenSim.Region.Framework.Scenes
3122 localids[ctr], att.handle, att.targetPos, m_rootPart.GroupPosition); 3581 localids[ctr], att.handle, att.targetPos, m_rootPart.GroupPosition);
3123 } 3582 }
3124 } 3583 }
3125 3584
3126 return; 3585 return;
3127 } 3586 }
3128 3587
3129 if (m_scriptListens_notAtTarget && !at_target) 3588 if (m_scriptListens_notAtTarget && !at_target)
3130 { 3589 {
3131 //trigger not_at_target 3590 //trigger not_at_target
@@ -3133,7 +3592,7 @@ namespace OpenSim.Region.Framework.Scenes
3133 uint[] localids = new uint[parts.Length]; 3592 uint[] localids = new uint[parts.Length];
3134 for (int i = 0; i < parts.Length; i++) 3593 for (int i = 0; i < parts.Length; i++)
3135 localids[i] = parts[i].LocalId; 3594 localids[i] = parts[i].LocalId;
3136 3595
3137 for (int ctr = 0; ctr < localids.Length; ctr++) 3596 for (int ctr = 0; ctr < localids.Length; ctr++)
3138 { 3597 {
3139 m_scene.EventManager.TriggerNotAtTargetEvent(localids[ctr]); 3598 m_scene.EventManager.TriggerNotAtTargetEvent(localids[ctr]);
@@ -3152,13 +3611,7 @@ namespace OpenSim.Region.Framework.Scenes
3152 foreach (uint idx in m_rotTargets.Keys) 3611 foreach (uint idx in m_rotTargets.Keys)
3153 { 3612 {
3154 scriptRotTarget target = m_rotTargets[idx]; 3613 scriptRotTarget target = m_rotTargets[idx];
3155 double angle 3614 double angle = Math.Acos(target.targetRot.X * m_rootPart.RotationOffset.X + target.targetRot.Y * m_rootPart.RotationOffset.Y + target.targetRot.Z * m_rootPart.RotationOffset.Z + target.targetRot.W * m_rootPart.RotationOffset.W) * 2;
3156 = Math.Acos(
3157 target.targetRot.X * m_rootPart.RotationOffset.X
3158 + target.targetRot.Y * m_rootPart.RotationOffset.Y
3159 + target.targetRot.Z * m_rootPart.RotationOffset.Z
3160 + target.targetRot.W * m_rootPart.RotationOffset.W)
3161 * 2;
3162 if (angle < 0) angle = -angle; 3615 if (angle < 0) angle = -angle;
3163 if (angle > Math.PI) angle = (Math.PI * 2 - angle); 3616 if (angle > Math.PI) angle = (Math.PI * 2 - angle);
3164 if (angle <= target.tolerance) 3617 if (angle <= target.tolerance)
@@ -3213,39 +3666,53 @@ namespace OpenSim.Region.Framework.Scenes
3213 } 3666 }
3214 } 3667 }
3215 } 3668 }
3216 3669
3217 public float GetMass() 3670 public float GetMass()
3218 { 3671 {
3219 float retmass = 0f; 3672 float retmass = 0f;
3220
3221 SceneObjectPart[] parts = m_parts.GetArray(); 3673 SceneObjectPart[] parts = m_parts.GetArray();
3222 for (int i = 0; i < parts.Length; i++) 3674 for (int i = 0; i < parts.Length; i++)
3223 retmass += parts[i].GetMass(); 3675 retmass += parts[i].GetMass();
3224 3676
3225 return retmass; 3677 return retmass;
3226 } 3678 }
3227 3679
3228 /// <summary>
3229 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that
3230 /// the physics engine can use it.
3231 /// </summary>
3232 /// <remarks>
3233 /// When the physics engine has finished with it, the sculpt data is discarded to save memory.
3234 /// </remarks>
3235 public void CheckSculptAndLoad() 3680 public void CheckSculptAndLoad()
3236 { 3681 {
3237 if (IsDeleted) 3682 if (IsDeleted)
3238 return; 3683 return;
3239
3240 if ((RootPart.GetEffectiveObjectFlags() & (uint)PrimFlags.Phantom) != 0) 3684 if ((RootPart.GetEffectiveObjectFlags() & (uint)PrimFlags.Phantom) != 0)
3241 return; 3685 return;
3242 3686
3243 // m_log.Debug("Processing CheckSculptAndLoad for {0} {1}", Name, LocalId);
3244
3245 SceneObjectPart[] parts = m_parts.GetArray(); 3687 SceneObjectPart[] parts = m_parts.GetArray();
3246
3247 for (int i = 0; i < parts.Length; i++) 3688 for (int i = 0; i < parts.Length; i++)
3248 parts[i].CheckSculptAndLoad(); 3689 {
3690 SceneObjectPart part = parts[i];
3691 if (part.Shape.SculptEntry && part.Shape.SculptTexture != UUID.Zero)
3692 {
3693 // check if a previously decoded sculpt map has been cached
3694 if (File.Exists(System.IO.Path.Combine("j2kDecodeCache", "smap_" + part.Shape.SculptTexture.ToString())))
3695 {
3696 part.SculptTextureCallback(part.Shape.SculptTexture, null);
3697 }
3698 else
3699 {
3700 m_scene.AssetService.Get(
3701 part.Shape.SculptTexture.ToString(), part, AssetReceived);
3702 }
3703 }
3704 }
3705 }
3706
3707 protected void AssetReceived(string id, Object sender, AssetBase asset)
3708 {
3709 SceneObjectPart sop = (SceneObjectPart)sender;
3710
3711 if (sop != null)
3712 {
3713 if (asset != null)
3714 sop.SculptTextureCallback(asset.FullID, asset);
3715 }
3249 } 3716 }
3250 3717
3251 /// <summary> 3718 /// <summary>
@@ -3274,18 +3741,25 @@ namespace OpenSim.Region.Framework.Scenes
3274 for (int i = 0; i < parts.Length; i++) 3741 for (int i = 0; i < parts.Length; i++)
3275 parts[i].TriggerScriptChangedEvent(val); 3742 parts[i].TriggerScriptChangedEvent(val);
3276 } 3743 }
3277 3744
3278 public override string ToString() 3745 public override string ToString()
3279 { 3746 {
3280 return String.Format("{0} {1} ({2})", Name, UUID, AbsolutePosition); 3747 return String.Format("{0} {1} ({2})", Name, UUID, AbsolutePosition);
3281 } 3748 }
3282 3749
3283 #region ISceneObject 3750 public void SetAttachmentPoint(byte point)
3751 {
3752 SceneObjectPart[] parts = m_parts.GetArray();
3753 for (int i = 0; i < parts.Length; i++)
3754 parts[i].SetAttachmentPoint(point);
3755 }
3284 3756
3757 #region ISceneObject
3758
3285 public virtual ISceneObject CloneForNewScene() 3759 public virtual ISceneObject CloneForNewScene()
3286 { 3760 {
3287 SceneObjectGroup sog = Copy(false); 3761 SceneObjectGroup sog = Copy(false);
3288 sog.IsDeleted = false; 3762 sog.m_isDeleted = false;
3289 return sog; 3763 return sog;
3290 } 3764 }
3291 3765
@@ -3311,6 +3785,14 @@ namespace OpenSim.Region.Framework.Scenes
3311 SetFromItemID(uuid); 3785 SetFromItemID(uuid);
3312 } 3786 }
3313 3787
3788 public void ResetOwnerChangeFlag()
3789 {
3790 ForEachPart(delegate(SceneObjectPart part)
3791 {
3792 part.ResetOwnerChangeFlag();
3793 });
3794 }
3795
3314 #endregion 3796 #endregion
3315 } 3797 }
3316} \ No newline at end of file 3798}