diff options
author | onefang | 2019-09-11 16:36:50 +1000 |
---|---|---|
committer | onefang | 2019-09-11 16:36:50 +1000 |
commit | 50cd1ffd32f69228e566f2b0b89f86ea0d9fe489 (patch) | |
tree | 52f2ab0c04f1a5d7d6ac5dc872981b4b156447e7 /OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | |
parent | Renamed branch to SledjChisl. (diff) | |
parent | Bump to release flavour, build 0. (diff) | |
download | opensim-SC-50cd1ffd32f69228e566f2b0b89f86ea0d9fe489.zip opensim-SC-50cd1ffd32f69228e566f2b0b89f86ea0d9fe489.tar.gz opensim-SC-50cd1ffd32f69228e566f2b0b89f86ea0d9fe489.tar.bz2 opensim-SC-50cd1ffd32f69228e566f2b0b89f86ea0d9fe489.tar.xz |
Merge branch 'SledjChisl'
Diffstat (limited to 'OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs')
-rw-r--r-- | OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | 3160 |
1 files changed, 2385 insertions, 775 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index d08237e..21311b0 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | |||
@@ -30,6 +30,7 @@ using System.ComponentModel; | |||
30 | using System.Collections.Generic; | 30 | using System.Collections.Generic; |
31 | using System.Drawing; | 31 | using System.Drawing; |
32 | using System.IO; | 32 | using System.IO; |
33 | using System.Diagnostics; | ||
33 | using System.Linq; | 34 | using System.Linq; |
34 | using System.Threading; | 35 | using System.Threading; |
35 | using System.Xml; | 36 | using System.Xml; |
@@ -45,6 +46,7 @@ using OpenSim.Services.Interfaces; | |||
45 | 46 | ||
46 | namespace OpenSim.Region.Framework.Scenes | 47 | namespace OpenSim.Region.Framework.Scenes |
47 | { | 48 | { |
49 | |||
48 | [Flags] | 50 | [Flags] |
49 | public enum scriptEvents | 51 | public enum scriptEvents |
50 | { | 52 | { |
@@ -77,17 +79,18 @@ namespace OpenSim.Region.Framework.Scenes | |||
77 | touch_end = 536870912, | 79 | touch_end = 536870912, |
78 | touch_start = 2097152, | 80 | touch_start = 2097152, |
79 | transaction_result = 33554432, | 81 | transaction_result = 33554432, |
80 | object_rez = 4194304 | 82 | object_rez = 4194304, |
83 | anytouch = touch | touch_end | touch_start | ||
81 | } | 84 | } |
82 | 85 | ||
83 | struct scriptPosTarget | 86 | public struct scriptPosTarget |
84 | { | 87 | { |
85 | public Vector3 targetPos; | 88 | public Vector3 targetPos; |
86 | public float tolerance; | 89 | public float tolerance; |
87 | public uint handle; | 90 | public uint handle; |
88 | } | 91 | } |
89 | 92 | ||
90 | struct scriptRotTarget | 93 | public struct scriptRotTarget |
91 | { | 94 | { |
92 | public Quaternion targetRot; | 95 | public Quaternion targetRot; |
93 | public float tolerance; | 96 | public float tolerance; |
@@ -109,11 +112,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
109 | STATUS_ROTATE_X = 0x002, | 112 | STATUS_ROTATE_X = 0x002, |
110 | STATUS_ROTATE_Y = 0x004, | 113 | STATUS_ROTATE_Y = 0x004, |
111 | STATUS_ROTATE_Z = 0x008, | 114 | STATUS_ROTATE_Z = 0x008, |
115 | NOT_STATUS_ROTATE_X = 0xFD, | ||
116 | NOT_STATUS_ROTATE_Y = 0xFB, | ||
117 | NOT_STATUS_ROTATE_Z = 0xF7 | ||
112 | } | 118 | } |
113 | 119 | ||
114 | // This flag has the same purpose as InventoryItemFlags.ObjectSlamPerm | ||
115 | public static readonly uint SLAM = 16; | ||
116 | |||
117 | // private PrimCountTaintedDelegate handlerPrimCountTainted = null; | 120 | // private PrimCountTaintedDelegate handlerPrimCountTainted = null; |
118 | 121 | ||
119 | /// <summary> | 122 | /// <summary> |
@@ -121,8 +124,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
121 | /// since the group's last persistent backup | 124 | /// since the group's last persistent backup |
122 | /// </summary> | 125 | /// </summary> |
123 | private bool m_hasGroupChanged = false; | 126 | private bool m_hasGroupChanged = false; |
124 | private long timeFirstChanged; | 127 | private long timeFirstChanged = 0; |
125 | private long timeLastChanged; | 128 | private long timeLastChanged = 0; |
129 | private long m_maxPersistTime = 0; | ||
130 | private long m_minPersistTime = 0; | ||
131 | // private Random m_rand; | ||
126 | 132 | ||
127 | /// <summary> | 133 | /// <summary> |
128 | /// This indicates whether the object has changed such that it needs to be repersisted to permenant storage | 134 | /// This indicates whether the object has changed such that it needs to be repersisted to permenant storage |
@@ -139,12 +145,47 @@ namespace OpenSim.Region.Framework.Scenes | |||
139 | { | 145 | { |
140 | if (value) | 146 | if (value) |
141 | { | 147 | { |
142 | timeLastChanged = DateTime.Now.Ticks; | 148 | |
149 | if (Backup) | ||
150 | { | ||
151 | m_scene.SceneGraph.FireChangeBackup(this); | ||
152 | } | ||
153 | timeLastChanged = DateTime.UtcNow.Ticks; | ||
143 | if (!m_hasGroupChanged) | 154 | if (!m_hasGroupChanged) |
144 | timeFirstChanged = DateTime.Now.Ticks; | 155 | timeFirstChanged = DateTime.UtcNow.Ticks; |
156 | if (m_rootPart != null && m_scene != null) | ||
157 | { | ||
158 | /* | ||
159 | if (m_rand == null) | ||
160 | { | ||
161 | byte[] val = new byte[16]; | ||
162 | m_rootPart.UUID.ToBytes(val, 0); | ||
163 | m_rand = new Random(BitConverter.ToInt32(val, 0)); | ||
164 | } | ||
165 | */ | ||
166 | if (m_scene.GetRootAgentCount() == 0) | ||
167 | { | ||
168 | //If the region is empty, this change has been made by an automated process | ||
169 | //and thus we delay the persist time by a random amount between 1.5 and 2.5. | ||
170 | |||
171 | // float factor = 1.5f + (float)(m_rand.NextDouble()); | ||
172 | float factor = 2.0f; | ||
173 | m_maxPersistTime = (long)((float)m_scene.m_persistAfter * factor); | ||
174 | m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * factor); | ||
175 | } | ||
176 | else | ||
177 | { | ||
178 | //If the region is not empty, we want to obey the minimum and maximum persist times | ||
179 | //but add a random factor so we stagger the object persistance a little | ||
180 | // m_maxPersistTime = (long)((float)m_scene.m_persistAfter * (1.0d - (m_rand.NextDouble() / 5.0d))); //Multiply by 1.0-1.5 | ||
181 | // m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * (1.0d + (m_rand.NextDouble() / 2.0d))); //Multiply by 0.8-1.0 | ||
182 | m_maxPersistTime = m_scene.m_persistAfter; | ||
183 | m_minPersistTime = m_scene.m_dontPersistBefore; | ||
184 | } | ||
185 | } | ||
145 | } | 186 | } |
146 | m_hasGroupChanged = value; | 187 | m_hasGroupChanged = value; |
147 | 188 | ||
148 | // m_log.DebugFormat( | 189 | // m_log.DebugFormat( |
149 | // "[SCENE OBJECT GROUP]: HasGroupChanged set to {0} for {1} {2}", m_hasGroupChanged, Name, LocalId); | 190 | // "[SCENE OBJECT GROUP]: HasGroupChanged set to {0} for {1} {2}", m_hasGroupChanged, Name, LocalId); |
150 | } | 191 | } |
@@ -153,7 +194,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
153 | } | 194 | } |
154 | 195 | ||
155 | private bool m_groupContainsForeignPrims = false; | 196 | private bool m_groupContainsForeignPrims = false; |
156 | 197 | ||
157 | /// <summary> | 198 | /// <summary> |
158 | /// Whether the group contains prims that came from a different group. This happens when | 199 | /// Whether the group contains prims that came from a different group. This happens when |
159 | /// linking or delinking groups. The implication is that until the group is persisted, | 200 | /// linking or delinking groups. The implication is that until the group is persisted, |
@@ -172,6 +213,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
172 | get { return m_groupContainsForeignPrims; } | 213 | get { return m_groupContainsForeignPrims; } |
173 | } | 214 | } |
174 | 215 | ||
216 | public bool HasGroupChangedDueToDelink { get; set; } | ||
175 | 217 | ||
176 | private bool isTimeToPersist() | 218 | private bool isTimeToPersist() |
177 | { | 219 | { |
@@ -181,8 +223,19 @@ namespace OpenSim.Region.Framework.Scenes | |||
181 | return false; | 223 | return false; |
182 | if (m_scene.ShuttingDown) | 224 | if (m_scene.ShuttingDown) |
183 | return true; | 225 | return true; |
184 | long currentTime = DateTime.Now.Ticks; | 226 | |
185 | if (currentTime - timeLastChanged > m_scene.m_dontPersistBefore || currentTime - timeFirstChanged > m_scene.m_persistAfter) | 227 | if (m_minPersistTime == 0 || m_maxPersistTime == 0) |
228 | { | ||
229 | m_maxPersistTime = m_scene.m_persistAfter; | ||
230 | m_minPersistTime = m_scene.m_dontPersistBefore; | ||
231 | } | ||
232 | |||
233 | long currentTime = DateTime.UtcNow.Ticks; | ||
234 | |||
235 | if (timeLastChanged == 0) timeLastChanged = currentTime; | ||
236 | if (timeFirstChanged == 0) timeFirstChanged = currentTime; | ||
237 | |||
238 | if (currentTime - timeLastChanged > m_minPersistTime || currentTime - timeFirstChanged > m_maxPersistTime) | ||
186 | return true; | 239 | return true; |
187 | return false; | 240 | return false; |
188 | } | 241 | } |
@@ -240,6 +293,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
240 | { | 293 | { |
241 | AttachmentPoint = 0; | 294 | AttachmentPoint = 0; |
242 | 295 | ||
296 | // Don't zap trees | ||
297 | if (RootPart.Shape.PCode == (byte)PCode.Tree || | ||
298 | RootPart.Shape.PCode == (byte)PCode.NewTree) | ||
299 | return; | ||
300 | |||
243 | // Even though we don't use child part state parameters for attachments any more, we still need to set | 301 | // Even though we don't use child part state parameters for attachments any more, we still need to set |
244 | // these to zero since having them non-zero in rezzed scene objects will crash some clients. Even if | 302 | // these to zero since having them non-zero in rezzed scene objects will crash some clients. Even if |
245 | // we store them correctly, scene objects that we receive from elsewhere might not. | 303 | // we store them correctly, scene objects that we receive from elsewhere might not. |
@@ -269,6 +327,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
269 | get { return (RootPart.Flags & PrimFlags.Physics) != 0; } | 327 | get { return (RootPart.Flags & PrimFlags.Physics) != 0; } |
270 | } | 328 | } |
271 | 329 | ||
330 | |||
272 | /// <summary> | 331 | /// <summary> |
273 | /// Is this scene object temporary? | 332 | /// Is this scene object temporary? |
274 | /// </summary> | 333 | /// </summary> |
@@ -285,9 +344,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
285 | get { return RootPart.VolumeDetectActive; } | 344 | get { return RootPart.VolumeDetectActive; } |
286 | } | 345 | } |
287 | 346 | ||
288 | private Vector3 lastPhysGroupPos; | ||
289 | private Quaternion lastPhysGroupRot; | ||
290 | |||
291 | /// <summary> | 347 | /// <summary> |
292 | /// Is this entity set to be saved in persistent storage? | 348 | /// Is this entity set to be saved in persistent storage? |
293 | /// </summary> | 349 | /// </summary> |
@@ -299,17 +355,29 @@ namespace OpenSim.Region.Framework.Scenes | |||
299 | protected SceneObjectPart m_rootPart; | 355 | protected SceneObjectPart m_rootPart; |
300 | // private Dictionary<UUID, scriptEvents> m_scriptEvents = new Dictionary<UUID, scriptEvents>(); | 356 | // private Dictionary<UUID, scriptEvents> m_scriptEvents = new Dictionary<UUID, scriptEvents>(); |
301 | 357 | ||
302 | private Dictionary<uint, scriptPosTarget> m_targets = new Dictionary<uint, scriptPosTarget>(); | 358 | private SortedDictionary<uint, scriptPosTarget> m_targets = new SortedDictionary<uint, scriptPosTarget>(); |
303 | private Dictionary<uint, scriptRotTarget> m_rotTargets = new Dictionary<uint, scriptRotTarget>(); | 359 | private SortedDictionary<uint, scriptRotTarget> m_rotTargets = new SortedDictionary<uint, scriptRotTarget>(); |
360 | |||
361 | public SortedDictionary<uint, scriptPosTarget> AtTargets | ||
362 | { | ||
363 | get { return m_targets; } | ||
364 | } | ||
365 | |||
366 | public SortedDictionary<uint, scriptRotTarget> RotTargets | ||
367 | { | ||
368 | get { return m_rotTargets; } | ||
369 | } | ||
304 | 370 | ||
305 | private bool m_scriptListens_atTarget; | 371 | private bool m_scriptListens_atTarget; |
306 | private bool m_scriptListens_notAtTarget; | 372 | private bool m_scriptListens_notAtTarget; |
307 | |||
308 | private bool m_scriptListens_atRotTarget; | 373 | private bool m_scriptListens_atRotTarget; |
309 | private bool m_scriptListens_notAtRotTarget; | 374 | private bool m_scriptListens_notAtRotTarget; |
310 | 375 | ||
376 | public bool m_dupeInProgress = false; | ||
311 | internal Dictionary<UUID, string> m_savedScriptState; | 377 | internal Dictionary<UUID, string> m_savedScriptState; |
312 | 378 | ||
379 | public UUID MonitoringObject { get; set; } | ||
380 | |||
313 | #region Properties | 381 | #region Properties |
314 | 382 | ||
315 | /// <summary> | 383 | /// <summary> |
@@ -344,6 +412,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
344 | get { return m_parts.Count; } | 412 | get { return m_parts.Count; } |
345 | } | 413 | } |
346 | 414 | ||
415 | // protected Quaternion m_rotation = Quaternion.Identity; | ||
416 | // | ||
417 | // public virtual Quaternion Rotation | ||
418 | // { | ||
419 | // get { return m_rotation; } | ||
420 | // set { | ||
421 | // m_rotation = value; | ||
422 | // } | ||
423 | // } | ||
424 | |||
347 | public Quaternion GroupRotation | 425 | public Quaternion GroupRotation |
348 | { | 426 | { |
349 | get { return m_rootPart.RotationOffset; } | 427 | get { return m_rootPart.RotationOffset; } |
@@ -356,27 +434,27 @@ namespace OpenSim.Region.Framework.Scenes | |||
356 | Vector3 minScale = new Vector3(Constants.MaximumRegionSize, Constants.MaximumRegionSize, Constants.MaximumRegionSize); | 434 | Vector3 minScale = new Vector3(Constants.MaximumRegionSize, Constants.MaximumRegionSize, Constants.MaximumRegionSize); |
357 | Vector3 maxScale = Vector3.Zero; | 435 | Vector3 maxScale = Vector3.Zero; |
358 | Vector3 finalScale = new Vector3(0.5f, 0.5f, 0.5f); | 436 | Vector3 finalScale = new Vector3(0.5f, 0.5f, 0.5f); |
359 | 437 | ||
360 | SceneObjectPart[] parts = m_parts.GetArray(); | 438 | SceneObjectPart[] parts = m_parts.GetArray(); |
361 | for (int i = 0; i < parts.Length; i++) | 439 | for (int i = 0; i < parts.Length; i++) |
362 | { | 440 | { |
363 | SceneObjectPart part = parts[i]; | 441 | SceneObjectPart part = parts[i]; |
364 | Vector3 partscale = part.Scale; | 442 | Vector3 partscale = part.Scale; |
365 | Vector3 partoffset = part.OffsetPosition; | 443 | Vector3 partoffset = part.OffsetPosition; |
366 | 444 | ||
367 | minScale.X = (partscale.X + partoffset.X < minScale.X) ? partscale.X + partoffset.X : minScale.X; | 445 | minScale.X = (partscale.X + partoffset.X < minScale.X) ? partscale.X + partoffset.X : minScale.X; |
368 | minScale.Y = (partscale.Y + partoffset.Y < minScale.Y) ? partscale.Y + partoffset.Y : minScale.Y; | 446 | minScale.Y = (partscale.Y + partoffset.Y < minScale.Y) ? partscale.Y + partoffset.Y : minScale.Y; |
369 | minScale.Z = (partscale.Z + partoffset.Z < minScale.Z) ? partscale.Z + partoffset.Z : minScale.Z; | 447 | minScale.Z = (partscale.Z + partoffset.Z < minScale.Z) ? partscale.Z + partoffset.Z : minScale.Z; |
370 | 448 | ||
371 | maxScale.X = (partscale.X + partoffset.X > maxScale.X) ? partscale.X + partoffset.X : maxScale.X; | 449 | maxScale.X = (partscale.X + partoffset.X > maxScale.X) ? partscale.X + partoffset.X : maxScale.X; |
372 | maxScale.Y = (partscale.Y + partoffset.Y > maxScale.Y) ? partscale.Y + partoffset.Y : maxScale.Y; | 450 | maxScale.Y = (partscale.Y + partoffset.Y > maxScale.Y) ? partscale.Y + partoffset.Y : maxScale.Y; |
373 | maxScale.Z = (partscale.Z + partoffset.Z > maxScale.Z) ? partscale.Z + partoffset.Z : maxScale.Z; | 451 | maxScale.Z = (partscale.Z + partoffset.Z > maxScale.Z) ? partscale.Z + partoffset.Z : maxScale.Z; |
374 | } | 452 | } |
375 | 453 | ||
376 | finalScale.X = (minScale.X > maxScale.X) ? minScale.X : maxScale.X; | 454 | finalScale.X = (minScale.X > maxScale.X) ? minScale.X : maxScale.X; |
377 | finalScale.Y = (minScale.Y > maxScale.Y) ? minScale.Y : maxScale.Y; | 455 | finalScale.Y = (minScale.Y > maxScale.Y) ? minScale.Y : maxScale.Y; |
378 | finalScale.Z = (minScale.Z > maxScale.Z) ? minScale.Z : maxScale.Z; | 456 | finalScale.Z = (minScale.Z > maxScale.Z) ? minScale.Z : maxScale.Z; |
379 | 457 | ||
380 | return finalScale; | 458 | return finalScale; |
381 | } | 459 | } |
382 | } | 460 | } |
@@ -441,7 +519,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
441 | /// <remarks> | 519 | /// <remarks> |
442 | /// This is necessary in some cases, particularly when a scene object has just crossed into a region and doesn't | 520 | /// This is necessary in some cases, particularly when a scene object has just crossed into a region and doesn't |
443 | /// have the IsAttachment property yet checked. | 521 | /// have the IsAttachment property yet checked. |
444 | /// | 522 | /// |
445 | /// FIXME: However, this should be fixed so that this property | 523 | /// FIXME: However, this should be fixed so that this property |
446 | /// propertly reflects the underlying status. | 524 | /// propertly reflects the underlying status. |
447 | /// </remarks> | 525 | /// </remarks> |
@@ -451,13 +529,17 @@ namespace OpenSim.Region.Framework.Scenes | |||
451 | return (IsAttachment || | 529 | return (IsAttachment || |
452 | (m_rootPart.Shape.PCode == (byte)PCodeEnum.Primitive && m_rootPart.Shape.State != 0)); | 530 | (m_rootPart.Shape.PCode == (byte)PCodeEnum.Primitive && m_rootPart.Shape.State != 0)); |
453 | } | 531 | } |
454 | 532 | ||
455 | private struct avtocrossInfo | 533 | private struct avtocrossInfo |
456 | { | 534 | { |
457 | public ScenePresence av; | 535 | public ScenePresence av; |
458 | public uint ParentID; | 536 | public uint ParentID; |
459 | } | 537 | } |
460 | 538 | ||
539 | |||
540 | public bool inTransit = false; | ||
541 | private delegate SceneObjectGroup SOGCrossDelegate(SceneObjectGroup sog,Vector3 pos, TeleportObjectData tpData); | ||
542 | |||
461 | /// <summary> | 543 | /// <summary> |
462 | /// The absolute position of this scene object in the scene | 544 | /// The absolute position of this scene object in the scene |
463 | /// </summary> | 545 | /// </summary> |
@@ -467,205 +549,547 @@ namespace OpenSim.Region.Framework.Scenes | |||
467 | set | 549 | set |
468 | { | 550 | { |
469 | Vector3 val = value; | 551 | Vector3 val = value; |
552 | if (Scene != null | ||
553 | && !Scene.PositionIsInCurrentRegion(val) | ||
554 | && !IsAttachmentCheckFull() | ||
555 | && !Scene.LoadingPrims | ||
556 | && !Scene.DisableObjectTransfer | ||
557 | ) | ||
558 | { | ||
559 | if (!inTransit) | ||
560 | { | ||
561 | inTransit = true; | ||
562 | SOGCrossDelegate d = CrossAsync; | ||
563 | d.BeginInvoke(this, val, null, CrossAsyncCompleted, d); | ||
564 | } | ||
565 | return; | ||
566 | } | ||
567 | |||
568 | if (RootPart.GetStatusSandbox()) | ||
569 | { | ||
570 | if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) | ||
571 | { | ||
572 | RootPart.ScriptSetPhysicsStatus(false); | ||
573 | |||
574 | if (Scene != null) | ||
575 | Scene.SimChat(Utils.StringToBytes("Hit Sandbox Limit"), | ||
576 | ChatTypeEnum.DebugChannel, 0x7FFFFFFF, RootPart.AbsolutePosition, Name, UUID, false); | ||
577 | |||
578 | return; | ||
579 | } | ||
580 | } | ||
581 | |||
582 | bool triggerScriptEvent = m_rootPart.GroupPosition != val; | ||
583 | if (m_dupeInProgress || IsDeleted) | ||
584 | triggerScriptEvent = false; | ||
585 | |||
586 | m_rootPart.GroupPosition = val; | ||
587 | |||
588 | // Restuff the new GroupPosition into each child SOP of the linkset. | ||
589 | // this is needed because physics may not have linksets but just loose SOPs in world | ||
590 | |||
591 | SceneObjectPart[] parts = m_parts.GetArray(); | ||
592 | |||
593 | foreach (SceneObjectPart part in parts) | ||
594 | { | ||
595 | if (part != m_rootPart) | ||
596 | part.GroupPosition = val; | ||
597 | } | ||
598 | |||
599 | foreach (ScenePresence av in m_sittingAvatars) | ||
600 | { | ||
601 | av.sitSOGmoved(); | ||
602 | } | ||
603 | |||
604 | // now that position is changed tell it to scripts | ||
605 | if (triggerScriptEvent) | ||
606 | { | ||
607 | foreach (SceneObjectPart part in parts) | ||
608 | { | ||
609 | part.TriggerScriptChangedEvent(Changed.POSITION); | ||
610 | } | ||
611 | } | ||
470 | 612 | ||
471 | if (Scene != null) | 613 | if (Scene != null) |
614 | Scene.EventManager.TriggerParcelPrimCountTainted(); | ||
615 | |||
616 | } | ||
617 | } | ||
618 | |||
619 | private SceneObjectGroup CrossAsync(SceneObjectGroup sog, Vector3 val, TeleportObjectData tpdata) | ||
620 | { | ||
621 | Scene sogScene = sog.m_scene; | ||
622 | SceneObjectPart root = sog.RootPart; | ||
623 | |||
624 | bool isTeleport = tpdata != null; | ||
625 | |||
626 | if(!isTeleport) | ||
627 | { | ||
628 | if (root.DIE_AT_EDGE) | ||
472 | { | 629 | { |
473 | if ( | 630 | try |
474 | !Scene.PositionIsInCurrentRegion(val) | ||
475 | && !IsAttachmentCheckFull() | ||
476 | && (!Scene.LoadingPrims) | ||
477 | ) | ||
478 | { | 631 | { |
479 | IEntityTransferModule entityTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>(); | 632 | sogScene.DeleteSceneObject(sog, false); |
480 | EntityTransferContext ctx = new EntityTransferContext(); | 633 | } |
481 | Vector3 newpos = Vector3.Zero; | 634 | catch (Exception) |
482 | string failureReason = String.Empty; | 635 | { |
483 | OpenSim.Services.Interfaces.GridRegion destination = null; | 636 | m_log.Warn("[SCENE]: exception when trying to remove the prim that crossed the border."); |
637 | } | ||
638 | return sog; | ||
639 | } | ||
484 | 640 | ||
485 | if (m_rootPart.KeyframeMotion != null) | 641 | if (root.RETURN_AT_EDGE) |
486 | m_rootPart.KeyframeMotion.StartCrossingCheck(); | 642 | { |
643 | // We remove the object here | ||
644 | try | ||
645 | { | ||
646 | List<uint> localIDs = new List<uint>(); | ||
647 | localIDs.Add(root.LocalId); | ||
648 | sogScene.AddReturn(sog.OwnerID, sog.Name, sog.AbsolutePosition, | ||
649 | "Returned at region cross"); | ||
650 | sogScene.DeRezObjects(null, localIDs, UUID.Zero, DeRezAction.Return, UUID.Zero, false); | ||
651 | } | ||
652 | catch (Exception) | ||
653 | { | ||
654 | m_log.Warn("[SCENE]: exception when trying to return the prim that crossed the border."); | ||
655 | } | ||
656 | return sog; | ||
657 | } | ||
658 | } | ||
487 | 659 | ||
488 | bool canCross = true; | 660 | // if(!m_scene.IsRunning) |
489 | foreach (ScenePresence av in GetSittingAvatars()) | 661 | // return sog; |
490 | { | ||
491 | // We need to cross these agents. First, let's find | ||
492 | // out if any of them can't cross for some reason. | ||
493 | // We have to deny the crossing entirely if any | ||
494 | // of them are banned. Alternatively, we could | ||
495 | // unsit banned agents.... | ||
496 | 662 | ||
663 | if (root.KeyframeMotion != null) | ||
664 | root.KeyframeMotion.StartCrossingCheck(); | ||
497 | 665 | ||
498 | // We set the avatar position as being the object | 666 | if(root.PhysActor != null) |
499 | // position to get the region to send to | 667 | root.PhysActor.CrossingStart(); |
500 | if ((destination = entityTransfer.GetDestination(m_scene, av.UUID, val, ctx, out newpos, out failureReason)) == null) | ||
501 | { | ||
502 | canCross = false; | ||
503 | break; | ||
504 | } | ||
505 | 668 | ||
506 | m_log.DebugFormat("[SCENE OBJECT]: Avatar {0} needs to be crossed to {1}", av.Name, destination.RegionName); | 669 | IEntityTransferModule entityTransfer = sogScene.RequestModuleInterface<IEntityTransferModule>(); |
507 | } | ||
508 | 670 | ||
509 | if (canCross) | 671 | if (entityTransfer == null) |
510 | { | 672 | return sog; |
511 | // We unparent the SP quietly so that it won't | ||
512 | // be made to stand up | ||
513 | 673 | ||
514 | List<avtocrossInfo> avsToCross = new List<avtocrossInfo>(); | 674 | Vector3 newpos = Vector3.Zero; |
675 | OpenSim.Services.Interfaces.GridRegion destination = null; | ||
515 | 676 | ||
516 | foreach (ScenePresence av in GetSittingAvatars()) | 677 | destination = entityTransfer.GetObjectDestination(sog, val, out newpos); |
517 | { | 678 | if (destination == null) |
518 | avtocrossInfo avinfo = new avtocrossInfo(); | 679 | return sog; |
519 | SceneObjectPart parentPart = m_scene.GetSceneObjectPart(av.ParentID); | ||
520 | if (parentPart != null) | ||
521 | av.ParentUUID = parentPart.UUID; | ||
522 | 680 | ||
523 | avinfo.av = av; | 681 | if (sog.m_sittingAvatars.Count == 0) |
524 | avinfo.ParentID = av.ParentID; | 682 | { |
525 | avsToCross.Add(avinfo); | 683 | entityTransfer.CrossPrimGroupIntoNewRegion(destination, newpos, sog, !isTeleport, true); |
684 | return sog; | ||
685 | } | ||
526 | 686 | ||
527 | av.PrevSitOffset = av.OffsetPosition; | 687 | string reason = String.Empty; |
528 | av.ParentID = 0; | 688 | EntityTransferContext ctx = new EntityTransferContext(); |
529 | } | ||
530 | 689 | ||
531 | m_scene.CrossPrimGroupIntoNewRegion(val, this, true); | 690 | Vector3 curPos = root.GroupPosition; |
691 | foreach (ScenePresence av in sog.m_sittingAvatars) | ||
692 | { | ||
693 | // We need to cross these agents. First, let's find | ||
694 | // out if any of them can't cross for some reason. | ||
695 | // We have to deny the crossing entirely if any | ||
696 | // of them are banned. Alternatively, we could | ||
697 | // unsit banned agents.... | ||
698 | |||
699 | // We set the avatar position as being the object | ||
700 | // position to get the region to send to | ||
701 | if(av.IsNPC) | ||
702 | continue; | ||
532 | 703 | ||
533 | // Normalize | 704 | if(av.IsInTransit) |
534 | if (val.X >= m_scene.RegionInfo.RegionSizeX) | 705 | return sog; |
535 | val.X -= m_scene.RegionInfo.RegionSizeX; | ||
536 | if (val.Y >= m_scene.RegionInfo.RegionSizeY) | ||
537 | val.Y -= m_scene.RegionInfo.RegionSizeY; | ||
538 | if (val.X < 0) | ||
539 | val.X += m_scene.RegionInfo.RegionSizeX; | ||
540 | if (val.Y < 0) | ||
541 | val.Y += m_scene.RegionInfo.RegionSizeY; | ||
542 | 706 | ||
543 | // If it's deleted, crossing was successful | 707 | if(!entityTransfer.checkAgentAccessToRegion(av, destination, newpos, ctx, out reason)) |
544 | if (IsDeleted) | 708 | return sog; |
545 | { | ||
546 | foreach (avtocrossInfo avinfo in avsToCross) | ||
547 | { | ||
548 | ScenePresence av = avinfo.av; | ||
549 | if (!av.IsInTransit) // just in case... | ||
550 | { | ||
551 | m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar {0} to {1}", av.Name, val); | ||
552 | |||
553 | av.IsInTransit = true; | ||
554 | |||
555 | // A temporary measure to allow regression tests to work. | ||
556 | // Quite possibly, all BeginInvoke() calls should be replaced by Util.FireAndForget | ||
557 | // or similar since BeginInvoke() always uses the system threadpool to launch | ||
558 | // threads rather than any replace threadpool that we might be using. | ||
559 | if (Util.FireAndForgetMethod == FireAndForgetMethod.RegressionTest) | ||
560 | { | ||
561 | entityTransfer.CrossAgentToNewRegionAsync(av, val, destination, av.Flying, ctx); | ||
562 | CrossAgentToNewRegionCompleted(av); | ||
563 | } | ||
564 | else | ||
565 | { | ||
566 | CrossAgentToNewRegionDelegate d = entityTransfer.CrossAgentToNewRegionAsync; | ||
567 | d.BeginInvoke( | ||
568 | av, val, destination, av.Flying, ctx, | ||
569 | ar => CrossAgentToNewRegionCompleted(d.EndInvoke(ar)), null); | ||
570 | } | ||
571 | } | ||
572 | else | ||
573 | { | ||
574 | m_log.DebugFormat("[SCENE OBJECT]: Not crossing avatar {0} to {1} because it's already in transit", av.Name, val); | ||
575 | } | ||
576 | } | ||
577 | 709 | ||
578 | return; | 710 | m_log.DebugFormat("[SCENE OBJECT]: Avatar {0} needs to be crossed to {1}", av.Name, destination.RegionName); |
579 | } | 711 | } |
580 | else // cross failed, put avas back ?? | 712 | |
713 | // We unparent the SP quietly so that it won't | ||
714 | // be made to stand up | ||
715 | |||
716 | List<avtocrossInfo> avsToCross = new List<avtocrossInfo>(); | ||
717 | List<ScenePresence> avsToCrossFar = new List<ScenePresence>(); | ||
718 | ulong destHandle = destination.RegionHandle; | ||
719 | List<ScenePresence> sittingAvatars = GetSittingAvatars(); | ||
720 | foreach (ScenePresence av in sittingAvatars) | ||
721 | { | ||
722 | byte cflags = 1; | ||
723 | |||
724 | avtocrossInfo avinfo = new avtocrossInfo(); | ||
725 | SceneObjectPart parentPart = sogScene.GetSceneObjectPart(av.ParentID); | ||
726 | if (parentPart != null) | ||
727 | { | ||
728 | av.ParentUUID = parentPart.UUID; | ||
729 | if(parentPart.SitTargetAvatar == av.UUID) | ||
730 | cflags = 7; // low 3 bits set | ||
731 | else | ||
732 | cflags = 3; | ||
733 | } | ||
734 | if(!av.knowsNeighbourRegion(destHandle)) | ||
735 | cflags |= 8; | ||
736 | |||
737 | // 1 is crossing | ||
738 | // 2 is sitting | ||
739 | // 4 is sitting at sittarget | ||
740 | // 8 far crossing | ||
741 | |||
742 | avinfo.av = av; | ||
743 | avinfo.ParentID = av.ParentID; | ||
744 | avsToCross.Add(avinfo); | ||
745 | |||
746 | if(!av.knowsNeighbourRegion(destHandle)) | ||
747 | { | ||
748 | cflags |= 8; | ||
749 | avsToCrossFar.Add(av); | ||
750 | } | ||
751 | |||
752 | if(av.IsNPC) | ||
753 | av.crossingFlags = 0; | ||
754 | else | ||
755 | av.crossingFlags = cflags; | ||
756 | |||
757 | av.PrevSitOffset = av.OffsetPosition; | ||
758 | av.ParentID = 0; | ||
759 | } | ||
760 | |||
761 | Vector3 vel = root.Velocity; | ||
762 | Vector3 avel = root.AngularVelocity; | ||
763 | Vector3 acc = root.Acceleration; | ||
764 | Quaternion ori = root.RotationOffset; | ||
765 | |||
766 | if(isTeleport) | ||
767 | { | ||
768 | root.Stop(); | ||
769 | sogScene.ForEachScenePresence(delegate(ScenePresence av) | ||
770 | { | ||
771 | av.ControllingClient.SendEntityUpdate(root,PrimUpdateFlags.SendInTransit); | ||
772 | av.ControllingClient.SendEntityTerseUpdateImmediate(root); | ||
773 | }); | ||
774 | |||
775 | root.Velocity = tpdata.vel; | ||
776 | root.AngularVelocity = tpdata.avel; | ||
777 | root.Acceleration = tpdata.acc; | ||
778 | root.RotationOffset = tpdata.ori; | ||
779 | } | ||
780 | |||
781 | if (entityTransfer.CrossPrimGroupIntoNewRegion(destination, newpos, sog, true, false)) | ||
782 | { | ||
783 | if(isTeleport) | ||
784 | { | ||
785 | sogScene.ForEachScenePresence(delegate(ScenePresence oav) | ||
786 | { | ||
787 | if(sittingAvatars.Contains(oav)) | ||
788 | return; | ||
789 | if(oav.knowsNeighbourRegion(destHandle)) | ||
790 | return; | ||
791 | oav.ControllingClient.SendEntityUpdate(root, PrimUpdateFlags.Kill); | ||
792 | foreach (ScenePresence sav in sittingAvatars) | ||
793 | { | ||
794 | sav.SendKillTo(oav); | ||
795 | } | ||
796 | }); | ||
797 | } | ||
798 | bool crossedfar = false; | ||
799 | foreach (ScenePresence av in avsToCrossFar) | ||
800 | { | ||
801 | if(entityTransfer.CrossAgentCreateFarChild(av,destination, newpos, ctx)) | ||
802 | crossedfar = true; | ||
803 | else | ||
804 | av.crossingFlags = 0; | ||
805 | } | ||
806 | |||
807 | if(crossedfar) | ||
808 | Thread.Sleep(1000); | ||
809 | |||
810 | foreach (avtocrossInfo avinfo in avsToCross) | ||
811 | { | ||
812 | ScenePresence av = avinfo.av; | ||
813 | av.IsInLocalTransit = true; | ||
814 | av.IsInTransit = true; | ||
815 | m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar {0} to {1}", av.Name, val); | ||
816 | |||
817 | if(av.crossingFlags > 0) | ||
818 | entityTransfer.CrossAgentToNewRegionAsync(av, newpos, destination, false, ctx); | ||
819 | |||
820 | if (av.IsChildAgent) | ||
821 | { | ||
822 | // avatar crossed do some extra cleanup | ||
823 | if (av.ParentUUID != UUID.Zero) | ||
824 | { | ||
825 | av.ClearControls(); | ||
826 | av.ParentPart = null; | ||
827 | } | ||
828 | av.ParentUUID = UUID.Zero; | ||
829 | av.ParentPart = null; | ||
830 | // In any case | ||
831 | av.IsInTransit = false; | ||
832 | av.crossingFlags = 0; | ||
833 | m_log.DebugFormat("[SCENE OBJECT]: Crossing agent {0} {1} completed.", av.Firstname, av.Lastname); | ||
834 | } | ||
835 | else | ||
836 | { | ||
837 | // avatar cross failed we need do dedicated standUp | ||
838 | // part of it was done at CrossAgentToNewRegionAsync | ||
839 | // so for now just remove the sog controls | ||
840 | // this may need extra care | ||
841 | av.UnRegisterSeatControls(sog.UUID); | ||
842 | av.ParentUUID = UUID.Zero; | ||
843 | av.ParentPart = null; | ||
844 | Vector3 oldp = curPos; | ||
845 | oldp.X = Util.Clamp<float>(oldp.X, 0.5f, sog.m_scene.RegionInfo.RegionSizeX - 0.5f); | ||
846 | oldp.Y = Util.Clamp<float>(oldp.Y, 0.5f, sog.m_scene.RegionInfo.RegionSizeY - 0.5f); | ||
847 | av.AbsolutePosition = oldp; | ||
848 | av.crossingFlags = 0; | ||
849 | av.sitAnimation = "SIT"; | ||
850 | av.IsInTransit = false; | ||
851 | if(av.Animator!= null) | ||
852 | av.Animator.SetMovementAnimations("STAND"); | ||
853 | av.AddToPhysicalScene(false); | ||
854 | sogScene.ForEachScenePresence(delegate(ScenePresence oav) | ||
581 | { | 855 | { |
582 | foreach (avtocrossInfo avinfo in avsToCross) | 856 | if(sittingAvatars.Contains(oav)) |
857 | return; | ||
858 | if(oav.knowsNeighbourRegion(destHandle)) | ||
859 | av.SendAvatarDataToAgent(oav); | ||
860 | else | ||
583 | { | 861 | { |
584 | ScenePresence av = avinfo.av; | 862 | av.SendAvatarDataToAgent(oav); |
585 | av.ParentUUID = UUID.Zero; | 863 | av.SendAppearanceToAgent(oav); |
586 | av.ParentID = avinfo.ParentID; | 864 | if (av.Animator != null) |
865 | av.Animator.SendAnimPackToClient(oav.ControllingClient); | ||
866 | av.SendAttachmentsToAgentNF(oav); // not ok | ||
587 | } | 867 | } |
588 | } | 868 | }); |
589 | } | 869 | m_log.DebugFormat("[SCENE OBJECT]: Crossing agent {0} {1} failed.", av.Firstname, av.Lastname); |
590 | else | 870 | } |
591 | { | 871 | } |
592 | if (m_rootPart.KeyframeMotion != null) | ||
593 | m_rootPart.KeyframeMotion.CrossingFailure(); | ||
594 | 872 | ||
595 | if (RootPart.PhysActor != null) | 873 | if(crossedfar) |
596 | { | 874 | { |
597 | RootPart.PhysActor.CrossingFailure(); | 875 | Thread.Sleep(10000); |
598 | } | 876 | foreach (ScenePresence av in avsToCrossFar) |
877 | { | ||
878 | if(av.IsChildAgent) | ||
879 | { | ||
880 | av.Scene.CloseAgent(av.UUID, false); | ||
599 | } | 881 | } |
600 | 882 | else | |
601 | Vector3 oldp = AbsolutePosition; | 883 | av.RemoveNeighbourRegion(destHandle); |
602 | val.X = Util.Clamp<float>(oldp.X, 0.5f, (float)m_scene.RegionInfo.RegionSizeX - 0.5f); | ||
603 | val.Y = Util.Clamp<float>(oldp.Y, 0.5f, (float)m_scene.RegionInfo.RegionSizeY - 0.5f); | ||
604 | val.Z = Util.Clamp<float>(oldp.Z, 0.5f, Constants.RegionHeight); | ||
605 | } | 884 | } |
606 | } | 885 | } |
607 | 886 | avsToCrossFar.Clear(); | |
608 | if (RootPart.GetStatusSandbox()) | 887 | avsToCross.Clear(); |
888 | sog.RemoveScriptInstances(true); | ||
889 | sog.Clear(); | ||
890 | return sog; | ||
891 | } | ||
892 | else | ||
893 | { | ||
894 | if(isTeleport) | ||
609 | { | 895 | { |
610 | if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) | 896 | if((tpdata.flags & OSTPOBJ_STOPONFAIL) == 0) |
611 | { | 897 | { |
612 | RootPart.ScriptSetPhysicsStatus(false); | 898 | root.Velocity = vel; |
613 | 899 | root.AngularVelocity = avel; | |
614 | if (Scene != null) | 900 | root.Acceleration = acc; |
615 | Scene.SimChat(Utils.StringToBytes("Hit Sandbox Limit"), | ||
616 | ChatTypeEnum.DebugChannel, 0x7FFFFFFF, RootPart.AbsolutePosition, Name, UUID, false); | ||
617 | |||
618 | return; | ||
619 | } | 901 | } |
902 | root.RotationOffset = ori; | ||
903 | } | ||
904 | foreach (avtocrossInfo avinfo in avsToCross) | ||
905 | { | ||
906 | ScenePresence av = avinfo.av; | ||
907 | av.ParentUUID = UUID.Zero; | ||
908 | av.ParentID = avinfo.ParentID; | ||
909 | av.crossingFlags = 0; | ||
620 | } | 910 | } |
911 | } | ||
912 | avsToCross.Clear(); | ||
913 | return sog; | ||
914 | } | ||
621 | 915 | ||
622 | // Restuff the new GroupPosition into each SOP of the linkset. | 916 | public void CrossAsyncCompleted(IAsyncResult iar) |
623 | // This has the affect of resetting and tainting the physics actors. | 917 | { |
624 | SceneObjectPart[] parts = m_parts.GetArray(); | 918 | SOGCrossDelegate icon = (SOGCrossDelegate)iar.AsyncState; |
625 | for (int i = 0; i < parts.Length; i++) | 919 | SceneObjectGroup sog = icon.EndInvoke(iar); |
626 | parts[i].GroupPosition = val; | ||
627 | 920 | ||
628 | //if (m_rootPart.PhysActor != null) | 921 | if (!sog.IsDeleted) |
629 | //{ | 922 | { |
630 | //m_rootPart.PhysActor.Position = | 923 | SceneObjectPart rootp = sog.m_rootPart; |
631 | //new PhysicsVector(m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y, | 924 | |
632 | //m_rootPart.GroupPosition.Z); | 925 | Vector3 oldp = rootp.GroupPosition; |
633 | //m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor); | 926 | oldp.X = Util.Clamp<float>(oldp.X, 0.5f, sog.m_scene.RegionInfo.RegionSizeX - 0.5f); |
634 | //} | 927 | oldp.Y = Util.Clamp<float>(oldp.Y, 0.5f, sog.m_scene.RegionInfo.RegionSizeY - 0.5f); |
635 | 928 | rootp.GroupPosition = oldp; | |
636 | if (Scene != null) | 929 | |
637 | Scene.EventManager.TriggerParcelPrimCountTainted(); | 930 | rootp.Stop(); |
931 | |||
932 | SceneObjectPart[] parts = sog.m_parts.GetArray(); | ||
933 | |||
934 | foreach (SceneObjectPart part in parts) | ||
935 | { | ||
936 | if (part != rootp) | ||
937 | part.GroupPosition = oldp; | ||
938 | } | ||
939 | |||
940 | foreach (ScenePresence av in sog.m_sittingAvatars) | ||
941 | { | ||
942 | av.sitSOGmoved(); | ||
943 | } | ||
944 | |||
945 | if (sog.m_rootPart.KeyframeMotion != null) | ||
946 | sog.m_rootPart.KeyframeMotion.CrossingFailure(); | ||
947 | |||
948 | if (sog.RootPart.PhysActor != null) | ||
949 | sog.RootPart.PhysActor.CrossingFailure(); | ||
950 | |||
951 | sog.inTransit = false; | ||
952 | AttachToBackup(); | ||
953 | sog.ScheduleGroupForFullUpdate(); | ||
638 | } | 954 | } |
639 | } | 955 | } |
640 | 956 | ||
641 | public override Vector3 Velocity | 957 | private class TeleportObjectData |
642 | { | 958 | { |
643 | get { return RootPart.Velocity; } | 959 | public int flags; |
644 | set { RootPart.Velocity = value; } | 960 | public Vector3 vel; |
961 | public Vector3 avel; | ||
962 | public Vector3 acc; | ||
963 | public Quaternion ori; | ||
964 | public UUID sourceID; | ||
645 | } | 965 | } |
646 | 966 | ||
647 | private void CrossAgentToNewRegionCompleted(ScenePresence agent) | 967 | // copy from LSL_constants.cs |
968 | const int OSTPOBJ_STOPATTARGET = 0x1; // stops at destination | ||
969 | const int OSTPOBJ_STOPONFAIL = 0x2; // stops at start if tp fails | ||
970 | const int OSTPOBJ_SETROT = 0x4; // the rotation is the final rotation, otherwise is a added rotation | ||
971 | |||
972 | public int TeleportObject(UUID sourceID, Vector3 targetPosition, Quaternion rotation, int flags) | ||
648 | { | 973 | { |
649 | //// If the cross was successful, this agent is a child agent | 974 | if(inTransit || IsDeleted || IsAttachmentCheckFull() || IsSelected || Scene == null) |
650 | if (agent.IsChildAgent) | 975 | return -1; |
976 | |||
977 | inTransit = true; | ||
978 | |||
979 | PhysicsActor pa = RootPart.PhysActor; | ||
980 | if(pa == null || RootPart.KeyframeMotion != null /*|| m_sittingAvatars.Count == 0*/) | ||
651 | { | 981 | { |
652 | if (agent.ParentUUID != UUID.Zero) | 982 | inTransit = false; |
983 | return -1; | ||
984 | } | ||
985 | |||
986 | bool stop = (flags & OSTPOBJ_STOPATTARGET) != 0; | ||
987 | bool setrot = (flags & OSTPOBJ_SETROT) != 0; | ||
988 | |||
989 | rotation.Normalize(); | ||
990 | |||
991 | Quaternion currentRot = RootPart.RotationOffset; | ||
992 | if(setrot) | ||
993 | rotation = Quaternion.Conjugate(currentRot) * rotation; | ||
994 | |||
995 | bool dorot = setrot | (Math.Abs(rotation.W) < 0.99999); | ||
996 | |||
997 | Vector3 vel = Vector3.Zero; | ||
998 | Vector3 avel = Vector3.Zero; | ||
999 | Vector3 acc = Vector3.Zero; | ||
1000 | |||
1001 | if(!stop) | ||
1002 | { | ||
1003 | vel = RootPart.Velocity; | ||
1004 | avel = RootPart.AngularVelocity; | ||
1005 | acc = RootPart.Acceleration; | ||
1006 | } | ||
1007 | Quaternion ori = RootPart.RotationOffset; | ||
1008 | |||
1009 | if(dorot) | ||
1010 | { | ||
1011 | if(!stop) | ||
653 | { | 1012 | { |
654 | agent.ParentPart = null; | 1013 | vel *= rotation; |
655 | // agent.ParentPosition = Vector3.Zero; | 1014 | avel *= rotation; |
656 | // agent.ParentUUID = UUID.Zero; | 1015 | acc *= rotation; |
657 | } | 1016 | } |
1017 | ori *= rotation; | ||
658 | } | 1018 | } |
659 | 1019 | ||
660 | agent.ParentUUID = UUID.Zero; | 1020 | if(Scene.PositionIsInCurrentRegion(targetPosition)) |
661 | // agent.Reset(); | 1021 | { |
662 | // else // Not successful | 1022 | if(Scene.InTeleportTargetsCoolDown(UUID, sourceID, 1.0)) |
663 | // agent.RestoreInCurrentScene(); | 1023 | { |
1024 | inTransit = false; | ||
1025 | return -2; | ||
1026 | } | ||
1027 | |||
1028 | Vector3 curPos = AbsolutePosition; | ||
1029 | ILandObject curLand = Scene.LandChannel.GetLandObject(curPos.X, curPos.Y); | ||
1030 | float posX = targetPosition.X; | ||
1031 | float posY = targetPosition.Y; | ||
1032 | ILandObject land = Scene.LandChannel.GetLandObject(posX, posY); | ||
1033 | if(land != null && land != curLand) | ||
1034 | { | ||
1035 | if(!Scene.Permissions.CanObjectEnterWithScripts(this, land)) | ||
1036 | { | ||
1037 | inTransit = false; | ||
1038 | return -3; | ||
1039 | } | ||
1040 | |||
1041 | UUID agentID; | ||
1042 | foreach (ScenePresence av in m_sittingAvatars) | ||
1043 | { | ||
1044 | agentID = av.UUID; | ||
1045 | if(land.IsRestrictedFromLand(agentID) || land.IsBannedFromLand(agentID)) | ||
1046 | { | ||
1047 | inTransit = false; | ||
1048 | return -4; | ||
1049 | } | ||
1050 | } | ||
1051 | } | ||
664 | 1052 | ||
665 | // In any case | 1053 | RootPart.Velocity = vel; |
666 | agent.IsInTransit = false; | 1054 | RootPart.AngularVelocity = avel; |
1055 | RootPart.Acceleration = acc; | ||
1056 | RootPart.RotationOffset = ori; | ||
667 | 1057 | ||
668 | m_log.DebugFormat("[SCENE OBJECT]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname); | 1058 | Vector3 s = RootPart.Scale * RootPart.RotationOffset; |
1059 | float h = Scene.GetGroundHeight(posX, posY) + 0.5f * (float)Math.Abs(s.Z) + 0.01f; | ||
1060 | if(targetPosition.Z < h) | ||
1061 | targetPosition.Z = h; | ||
1062 | |||
1063 | inTransit = false; | ||
1064 | AbsolutePosition = targetPosition; | ||
1065 | RootPart.ScheduleTerseUpdate(); | ||
1066 | return 1; | ||
1067 | } | ||
1068 | |||
1069 | if(Scene.InTeleportTargetsCoolDown(UUID, sourceID, 20.0)) | ||
1070 | { | ||
1071 | inTransit = false; | ||
1072 | return -1; | ||
1073 | } | ||
1074 | |||
1075 | TeleportObjectData tdata = new TeleportObjectData(); | ||
1076 | tdata.flags = flags; | ||
1077 | tdata.vel = vel; | ||
1078 | tdata.avel = avel; | ||
1079 | tdata.acc = acc; | ||
1080 | tdata.ori = ori; | ||
1081 | tdata.sourceID = sourceID; | ||
1082 | |||
1083 | |||
1084 | SOGCrossDelegate d = CrossAsync; | ||
1085 | d.BeginInvoke(this, targetPosition, tdata, CrossAsyncCompleted, d); | ||
1086 | return 0; | ||
1087 | } | ||
1088 | |||
1089 | public override Vector3 Velocity | ||
1090 | { | ||
1091 | get { return RootPart.Velocity; } | ||
1092 | set { RootPart.Velocity = value; } | ||
669 | } | 1093 | } |
670 | 1094 | ||
671 | public override uint LocalId | 1095 | public override uint LocalId |
@@ -677,7 +1101,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
677 | public override UUID UUID | 1101 | public override UUID UUID |
678 | { | 1102 | { |
679 | get { return m_rootPart.UUID; } | 1103 | get { return m_rootPart.UUID; } |
680 | set | 1104 | set |
681 | { | 1105 | { |
682 | lock (m_parts.SyncRoot) | 1106 | lock (m_parts.SyncRoot) |
683 | { | 1107 | { |
@@ -694,6 +1118,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
694 | set { m_rootPart.LastOwnerID = value; } | 1118 | set { m_rootPart.LastOwnerID = value; } |
695 | } | 1119 | } |
696 | 1120 | ||
1121 | public UUID RezzerID | ||
1122 | { | ||
1123 | get { return m_rootPart.RezzerID; } | ||
1124 | set { m_rootPart.RezzerID = value; } | ||
1125 | } | ||
1126 | |||
697 | public UUID OwnerID | 1127 | public UUID OwnerID |
698 | { | 1128 | { |
699 | get { return m_rootPart.OwnerID; } | 1129 | get { return m_rootPart.OwnerID; } |
@@ -733,7 +1163,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
733 | { | 1163 | { |
734 | get { return true; } | 1164 | get { return true; } |
735 | } | 1165 | } |
736 | 1166 | ||
737 | public bool IsSelected | 1167 | public bool IsSelected |
738 | { | 1168 | { |
739 | get { return m_isSelected; } | 1169 | get { return m_isSelected; } |
@@ -742,6 +1172,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
742 | m_isSelected = value; | 1172 | m_isSelected = value; |
743 | // Tell physics engine that group is selected | 1173 | // Tell physics engine that group is selected |
744 | 1174 | ||
1175 | // this is not right | ||
1176 | // but ode engines should only really need to know about root part | ||
1177 | // so they can put entire object simulation on hold and not colliding | ||
1178 | // keep as was for now | ||
1179 | |||
745 | PhysicsActor pa = m_rootPart.PhysActor; | 1180 | PhysicsActor pa = m_rootPart.PhysActor; |
746 | if (pa != null) | 1181 | if (pa != null) |
747 | { | 1182 | { |
@@ -763,13 +1198,47 @@ namespace OpenSim.Region.Framework.Scenes | |||
763 | } | 1198 | } |
764 | } | 1199 | } |
765 | 1200 | ||
1201 | public void PartSelectChanged(bool partSelect) | ||
1202 | { | ||
1203 | // any part selected makes group selected | ||
1204 | if (m_isSelected == partSelect) | ||
1205 | return; | ||
1206 | |||
1207 | if (partSelect) | ||
1208 | { | ||
1209 | IsSelected = partSelect; | ||
1210 | // if (!IsAttachment) | ||
1211 | // ScheduleGroupForFullUpdate(); | ||
1212 | } | ||
1213 | else | ||
1214 | { | ||
1215 | // bad bad bad 2 heavy for large linksets | ||
1216 | // since viewer does send lot of (un)selects | ||
1217 | // this needs to be replaced by a specific list or count ? | ||
1218 | // but that will require extra code in several places | ||
1219 | |||
1220 | SceneObjectPart[] parts = m_parts.GetArray(); | ||
1221 | for (int i = 0; i < parts.Length; i++) | ||
1222 | { | ||
1223 | SceneObjectPart part = parts[i]; | ||
1224 | if (part.IsSelected) | ||
1225 | return; | ||
1226 | } | ||
1227 | IsSelected = partSelect; | ||
1228 | // if (!IsAttachment) | ||
1229 | // { | ||
1230 | // ScheduleGroupForFullUpdate(); | ||
1231 | // } | ||
1232 | } | ||
1233 | } | ||
1234 | // PlaySoundMasterPrim no longer in use to remove | ||
766 | private SceneObjectPart m_PlaySoundMasterPrim = null; | 1235 | private SceneObjectPart m_PlaySoundMasterPrim = null; |
767 | public SceneObjectPart PlaySoundMasterPrim | 1236 | public SceneObjectPart PlaySoundMasterPrim |
768 | { | 1237 | { |
769 | get { return m_PlaySoundMasterPrim; } | 1238 | get { return m_PlaySoundMasterPrim; } |
770 | set { m_PlaySoundMasterPrim = value; } | 1239 | set { m_PlaySoundMasterPrim = value; } |
771 | } | 1240 | } |
772 | 1241 | // PlaySoundSlavePrims no longer in use to remove | |
773 | private List<SceneObjectPart> m_PlaySoundSlavePrims = new List<SceneObjectPart>(); | 1242 | private List<SceneObjectPart> m_PlaySoundSlavePrims = new List<SceneObjectPart>(); |
774 | public List<SceneObjectPart> PlaySoundSlavePrims | 1243 | public List<SceneObjectPart> PlaySoundSlavePrims |
775 | { | 1244 | { |
@@ -777,6 +1246,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
777 | set { m_PlaySoundSlavePrims = value; } | 1246 | set { m_PlaySoundSlavePrims = value; } |
778 | } | 1247 | } |
779 | 1248 | ||
1249 | // LoopSoundMasterPrim no longer in use to remove | ||
780 | private SceneObjectPart m_LoopSoundMasterPrim = null; | 1250 | private SceneObjectPart m_LoopSoundMasterPrim = null; |
781 | public SceneObjectPart LoopSoundMasterPrim | 1251 | public SceneObjectPart LoopSoundMasterPrim |
782 | { | 1252 | { |
@@ -784,6 +1254,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
784 | set { m_LoopSoundMasterPrim = value; } | 1254 | set { m_LoopSoundMasterPrim = value; } |
785 | } | 1255 | } |
786 | 1256 | ||
1257 | // m_LoopSoundSlavePrims no longer in use to remove | ||
787 | private List<SceneObjectPart> m_LoopSoundSlavePrims = new List<SceneObjectPart>(); | 1258 | private List<SceneObjectPart> m_LoopSoundSlavePrims = new List<SceneObjectPart>(); |
788 | public List<SceneObjectPart> LoopSoundSlavePrims | 1259 | public List<SceneObjectPart> LoopSoundSlavePrims |
789 | { | 1260 | { |
@@ -791,6 +1262,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
791 | set { m_LoopSoundSlavePrims = value; } | 1262 | set { m_LoopSoundSlavePrims = value; } |
792 | } | 1263 | } |
793 | 1264 | ||
1265 | private double m_lastCollisionSoundMS; | ||
1266 | |||
794 | /// <summary> | 1267 | /// <summary> |
795 | /// The UUID for the region this object is in. | 1268 | /// The UUID for the region this object is in. |
796 | /// </summary> | 1269 | /// </summary> |
@@ -820,7 +1293,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
820 | /// <remarks> | 1293 | /// <remarks> |
821 | /// If not applicable will be UUID.Zero | 1294 | /// If not applicable will be UUID.Zero |
822 | /// </remarks> | 1295 | /// </remarks> |
823 | public UUID FromPartID { get; set; } | 1296 | /// obsolete use RezzerID |
1297 | public UUID FromPartID | ||
1298 | { | ||
1299 | get { return RezzerID; } | ||
1300 | set {RezzerID = value; } | ||
1301 | } | ||
824 | 1302 | ||
825 | /// <summary> | 1303 | /// <summary> |
826 | /// The folder ID that this object was rezzed from, if applicable. | 1304 | /// The folder ID that this object was rezzed from, if applicable. |
@@ -863,6 +1341,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
863 | /// </summary> | 1341 | /// </summary> |
864 | public SceneObjectGroup() | 1342 | public SceneObjectGroup() |
865 | { | 1343 | { |
1344 | m_lastCollisionSoundMS = Util.GetTimeStampMS() + 1000.0; | ||
866 | } | 1345 | } |
867 | 1346 | ||
868 | /// <summary> | 1347 | /// <summary> |
@@ -880,8 +1359,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
880 | /// Constructor. This object is added to the scene later via AttachToScene() | 1359 | /// Constructor. This object is added to the scene later via AttachToScene() |
881 | /// </summary> | 1360 | /// </summary> |
882 | public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) | 1361 | public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) |
883 | :this(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)) | 1362 | { |
884 | { | 1363 | SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)); |
885 | } | 1364 | } |
886 | 1365 | ||
887 | /// <summary> | 1366 | /// <summary> |
@@ -907,7 +1386,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
907 | if (itemid != UUID.Zero) | 1386 | if (itemid != UUID.Zero) |
908 | m_savedScriptState[itemid] = node.InnerXml; | 1387 | m_savedScriptState[itemid] = node.InnerXml; |
909 | } | 1388 | } |
910 | } | 1389 | } |
911 | } | 1390 | } |
912 | } | 1391 | } |
913 | 1392 | ||
@@ -940,7 +1419,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
940 | } | 1419 | } |
941 | else | 1420 | else |
942 | { | 1421 | { |
943 | m_log.WarnFormat("[SCENE OBJECT GROUP]: SavedScriptState element had no UUID in object {0}", Name); | 1422 | m_log.WarnFormat("[SCENE OBJECT GROUP]: SavedScriptState element had no UUID in object {0} id: {1}", Name,UUID); |
944 | } | 1423 | } |
945 | } | 1424 | } |
946 | else | 1425 | else |
@@ -956,18 +1435,21 @@ namespace OpenSim.Region.Framework.Scenes | |||
956 | /// </summary> | 1435 | /// </summary> |
957 | public virtual void AttachToBackup() | 1436 | public virtual void AttachToBackup() |
958 | { | 1437 | { |
959 | if (CanBeBackedUp) | 1438 | if (IsAttachment) return; |
1439 | m_scene.SceneGraph.FireAttachToBackup(this); | ||
1440 | |||
1441 | // if (InSceneBackup) | ||
960 | { | 1442 | { |
961 | // m_log.DebugFormat( | 1443 | // m_log.DebugFormat( |
962 | // "[SCENE OBJECT GROUP]: Attaching object {0} {1} to scene presistence sweep", Name, UUID); | 1444 | // "[SCENE OBJECT GROUP]: Attaching object {0} {1} to scene presistence sweep", Name, UUID); |
963 | 1445 | ||
964 | if (!Backup) | 1446 | if (!Backup) |
965 | m_scene.EventManager.OnBackup += ProcessBackup; | 1447 | m_scene.EventManager.OnBackup += ProcessBackup; |
966 | 1448 | ||
967 | Backup = true; | 1449 | Backup = true; |
968 | } | 1450 | } |
969 | } | 1451 | } |
970 | 1452 | ||
971 | /// <summary> | 1453 | /// <summary> |
972 | /// Attach this object to a scene. It will also now appear to agents. | 1454 | /// Attach this object to a scene. It will also now appear to agents. |
973 | /// </summary> | 1455 | /// </summary> |
@@ -1018,6 +1500,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
1018 | EntityIntersection result = new EntityIntersection(); | 1500 | EntityIntersection result = new EntityIntersection(); |
1019 | 1501 | ||
1020 | SceneObjectPart[] parts = m_parts.GetArray(); | 1502 | SceneObjectPart[] parts = m_parts.GetArray(); |
1503 | |||
1504 | // Find closest hit here | ||
1505 | float idist = float.MaxValue; | ||
1506 | |||
1021 | for (int i = 0; i < parts.Length; i++) | 1507 | for (int i = 0; i < parts.Length; i++) |
1022 | { | 1508 | { |
1023 | SceneObjectPart part = parts[i]; | 1509 | SceneObjectPart part = parts[i]; |
@@ -1032,11 +1518,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
1032 | 1518 | ||
1033 | EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters); | 1519 | EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters); |
1034 | 1520 | ||
1035 | // This may need to be updated to the maximum draw distance possible.. | ||
1036 | // We might (and probably will) be checking for prim creation from other sims | ||
1037 | // when the camera crosses the border. | ||
1038 | float idist = Constants.RegionSize; | ||
1039 | |||
1040 | if (inter.HitTF) | 1521 | if (inter.HitTF) |
1041 | { | 1522 | { |
1042 | // We need to find the closest prim to return to the testcaller along the ray | 1523 | // We need to find the closest prim to return to the testcaller along the ray |
@@ -1047,10 +1528,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
1047 | result.obj = part; | 1528 | result.obj = part; |
1048 | result.normal = inter.normal; | 1529 | result.normal = inter.normal; |
1049 | result.distance = inter.distance; | 1530 | result.distance = inter.distance; |
1531 | |||
1532 | idist = inter.distance; | ||
1050 | } | 1533 | } |
1051 | } | 1534 | } |
1052 | } | 1535 | } |
1053 | |||
1054 | return result; | 1536 | return result; |
1055 | } | 1537 | } |
1056 | 1538 | ||
@@ -1062,25 +1544,27 @@ namespace OpenSim.Region.Framework.Scenes | |||
1062 | /// <returns></returns> | 1544 | /// <returns></returns> |
1063 | public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ) | 1545 | public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ) |
1064 | { | 1546 | { |
1065 | maxX = -256f; | 1547 | maxX = float.MinValue; |
1066 | maxY = -256f; | 1548 | maxY = float.MinValue; |
1067 | maxZ = -256f; | 1549 | maxZ = float.MinValue; |
1068 | minX = 10000f; | 1550 | minX = float.MaxValue; |
1069 | minY = 10000f; | 1551 | minY = float.MaxValue; |
1070 | minZ = 10000f; | 1552 | minZ = float.MaxValue; |
1071 | 1553 | ||
1072 | SceneObjectPart[] parts = m_parts.GetArray(); | 1554 | SceneObjectPart[] parts = m_parts.GetArray(); |
1073 | for (int i = 0; i < parts.Length; i++) | 1555 | foreach (SceneObjectPart part in parts) |
1074 | { | 1556 | { |
1075 | SceneObjectPart part = parts[i]; | ||
1076 | |||
1077 | Vector3 worldPos = part.GetWorldPosition(); | 1557 | Vector3 worldPos = part.GetWorldPosition(); |
1078 | Vector3 offset = worldPos - AbsolutePosition; | 1558 | Vector3 offset = worldPos - AbsolutePosition; |
1079 | Quaternion worldRot; | 1559 | Quaternion worldRot; |
1080 | if (part.ParentID == 0) | 1560 | if (part.ParentID == 0) |
1561 | { | ||
1081 | worldRot = part.RotationOffset; | 1562 | worldRot = part.RotationOffset; |
1563 | } | ||
1082 | else | 1564 | else |
1565 | { | ||
1083 | worldRot = part.GetWorldRotation(); | 1566 | worldRot = part.GetWorldRotation(); |
1567 | } | ||
1084 | 1568 | ||
1085 | Vector3 frontTopLeft; | 1569 | Vector3 frontTopLeft; |
1086 | Vector3 frontTopRight; | 1570 | Vector3 frontTopRight; |
@@ -1092,6 +1576,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
1092 | Vector3 backBottomLeft; | 1576 | Vector3 backBottomLeft; |
1093 | Vector3 backBottomRight; | 1577 | Vector3 backBottomRight; |
1094 | 1578 | ||
1579 | // Vector3[] corners = new Vector3[8]; | ||
1580 | |||
1095 | Vector3 orig = Vector3.Zero; | 1581 | Vector3 orig = Vector3.Zero; |
1096 | 1582 | ||
1097 | frontTopLeft.X = orig.X - (part.Scale.X / 2); | 1583 | frontTopLeft.X = orig.X - (part.Scale.X / 2); |
@@ -1126,6 +1612,38 @@ namespace OpenSim.Region.Framework.Scenes | |||
1126 | backBottomRight.Y = orig.Y + (part.Scale.Y / 2); | 1612 | backBottomRight.Y = orig.Y + (part.Scale.Y / 2); |
1127 | backBottomRight.Z = orig.Z - (part.Scale.Z / 2); | 1613 | backBottomRight.Z = orig.Z - (part.Scale.Z / 2); |
1128 | 1614 | ||
1615 | |||
1616 | |||
1617 | //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z); | ||
1618 | //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z); | ||
1619 | //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z); | ||
1620 | //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z); | ||
1621 | //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z); | ||
1622 | //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z); | ||
1623 | //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z); | ||
1624 | //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z); | ||
1625 | |||
1626 | //for (int i = 0; i < 8; i++) | ||
1627 | //{ | ||
1628 | // corners[i] = corners[i] * worldRot; | ||
1629 | // corners[i] += offset; | ||
1630 | |||
1631 | // if (corners[i].X > maxX) | ||
1632 | // maxX = corners[i].X; | ||
1633 | // if (corners[i].X < minX) | ||
1634 | // minX = corners[i].X; | ||
1635 | |||
1636 | // if (corners[i].Y > maxY) | ||
1637 | // maxY = corners[i].Y; | ||
1638 | // if (corners[i].Y < minY) | ||
1639 | // minY = corners[i].Y; | ||
1640 | |||
1641 | // if (corners[i].Z > maxZ) | ||
1642 | // maxZ = corners[i].Y; | ||
1643 | // if (corners[i].Z < minZ) | ||
1644 | // minZ = corners[i].Z; | ||
1645 | //} | ||
1646 | |||
1129 | frontTopLeft = frontTopLeft * worldRot; | 1647 | frontTopLeft = frontTopLeft * worldRot; |
1130 | frontTopRight = frontTopRight * worldRot; | 1648 | frontTopRight = frontTopRight * worldRot; |
1131 | frontBottomLeft = frontBottomLeft * worldRot; | 1649 | frontBottomLeft = frontBottomLeft * worldRot; |
@@ -1147,6 +1665,15 @@ namespace OpenSim.Region.Framework.Scenes | |||
1147 | backTopLeft += offset; | 1665 | backTopLeft += offset; |
1148 | backTopRight += offset; | 1666 | backTopRight += offset; |
1149 | 1667 | ||
1668 | //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z); | ||
1669 | //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z); | ||
1670 | //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z); | ||
1671 | //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z); | ||
1672 | //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z); | ||
1673 | //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z); | ||
1674 | //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z); | ||
1675 | //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z); | ||
1676 | |||
1150 | if (frontTopRight.X > maxX) | 1677 | if (frontTopRight.X > maxX) |
1151 | maxX = frontTopRight.X; | 1678 | maxX = frontTopRight.X; |
1152 | if (frontTopLeft.X > maxX) | 1679 | if (frontTopLeft.X > maxX) |
@@ -1290,17 +1817,192 @@ namespace OpenSim.Region.Framework.Scenes | |||
1290 | 1817 | ||
1291 | #endregion | 1818 | #endregion |
1292 | 1819 | ||
1820 | private float? m_boundsRadius = null; | ||
1821 | public void InvalidBoundsRadius() | ||
1822 | { | ||
1823 | m_boundsRadius = null; | ||
1824 | } | ||
1825 | |||
1826 | private Vector3 m_boundsCenter; | ||
1827 | public Vector3 getBoundsCenter() | ||
1828 | { | ||
1829 | // math is done in GetBoundsRadius(); | ||
1830 | if(m_boundsRadius == null) | ||
1831 | GetBoundsRadius(); | ||
1832 | return m_boundsCenter; | ||
1833 | } | ||
1834 | |||
1835 | private float m_areaFactor; | ||
1836 | public float getAreaFactor() | ||
1837 | { | ||
1838 | // math is done in GetBoundsRadius(); | ||
1839 | if(m_boundsRadius == null) | ||
1840 | GetBoundsRadius(); | ||
1841 | return m_areaFactor; | ||
1842 | } | ||
1843 | |||
1844 | public float GetBoundsRadius() | ||
1845 | { | ||
1846 | // this may need more threading work | ||
1847 | if(m_boundsRadius == null) | ||
1848 | { | ||
1849 | float res = 0; | ||
1850 | float areaF = 0; | ||
1851 | SceneObjectPart p; | ||
1852 | SceneObjectPart[] parts; | ||
1853 | float partR; | ||
1854 | Vector3 offset = Vector3.Zero; | ||
1855 | lock (m_parts) | ||
1856 | { | ||
1857 | parts = m_parts.GetArray(); | ||
1858 | } | ||
1859 | |||
1860 | int nparts = parts.Length; | ||
1861 | for (int i = 0; i < nparts; i++) | ||
1862 | { | ||
1863 | p = parts[i]; | ||
1864 | partR = 0.5f * p.Scale.Length(); | ||
1865 | if(p != RootPart) | ||
1866 | { | ||
1867 | partR += p.OffsetPosition.Length(); | ||
1868 | offset += p.OffsetPosition; | ||
1869 | } | ||
1870 | if(partR > res) | ||
1871 | res = partR; | ||
1872 | if(p.maxSimpleArea() > areaF) | ||
1873 | areaF = p.maxSimpleArea(); | ||
1874 | } | ||
1875 | if(parts.Length > 1) | ||
1876 | { | ||
1877 | offset /= parts.Length; // basicly geometric center | ||
1878 | offset = offset * RootPart.RotationOffset; | ||
1879 | } | ||
1880 | |||
1881 | areaF = 10.0f / areaF; // scale it | ||
1882 | areaF = Util.Clamp(areaF, 0.001f, 1000f); // clamp it | ||
1883 | |||
1884 | m_areaFactor = (float)Math.Sqrt(areaF); | ||
1885 | m_boundsCenter = offset; | ||
1886 | m_boundsRadius = res; | ||
1887 | return res; | ||
1888 | } | ||
1889 | |||
1890 | return m_boundsRadius.Value; | ||
1891 | } | ||
1892 | |||
1893 | public void GetResourcesCosts(SceneObjectPart apart, | ||
1894 | out float linksetResCost, out float linksetPhysCost, out float partCost, out float partPhysCost) | ||
1895 | { | ||
1896 | // this information may need to be cached | ||
1897 | |||
1898 | float cost; | ||
1899 | float tmpcost; | ||
1900 | |||
1901 | bool ComplexCost = false; | ||
1902 | |||
1903 | SceneObjectPart p; | ||
1904 | SceneObjectPart[] parts; | ||
1905 | |||
1906 | lock (m_parts) | ||
1907 | { | ||
1908 | parts = m_parts.GetArray(); | ||
1909 | } | ||
1910 | |||
1911 | int nparts = parts.Length; | ||
1912 | |||
1913 | |||
1914 | for (int i = 0; i < nparts; i++) | ||
1915 | { | ||
1916 | p = parts[i]; | ||
1917 | |||
1918 | if (p.UsesComplexCost) | ||
1919 | { | ||
1920 | ComplexCost = true; | ||
1921 | break; | ||
1922 | } | ||
1923 | } | ||
1924 | |||
1925 | if (ComplexCost) | ||
1926 | { | ||
1927 | linksetResCost = 0; | ||
1928 | linksetPhysCost = 0; | ||
1929 | partCost = 0; | ||
1930 | partPhysCost = 0; | ||
1931 | |||
1932 | for (int i = 0; i < nparts; i++) | ||
1933 | { | ||
1934 | p = parts[i]; | ||
1935 | |||
1936 | cost = p.StreamingCost; | ||
1937 | tmpcost = p.SimulationCost; | ||
1938 | if (tmpcost > cost) | ||
1939 | cost = tmpcost; | ||
1940 | tmpcost = p.PhysicsCost; | ||
1941 | if (tmpcost > cost) | ||
1942 | cost = tmpcost; | ||
1943 | |||
1944 | linksetPhysCost += tmpcost; | ||
1945 | linksetResCost += cost; | ||
1946 | |||
1947 | if (p == apart) | ||
1948 | { | ||
1949 | partCost = cost; | ||
1950 | partPhysCost = tmpcost; | ||
1951 | } | ||
1952 | } | ||
1953 | } | ||
1954 | else | ||
1955 | { | ||
1956 | partPhysCost = 1.0f; | ||
1957 | partCost = 1.0f; | ||
1958 | linksetResCost = (float)nparts; | ||
1959 | linksetPhysCost = linksetResCost; | ||
1960 | } | ||
1961 | } | ||
1962 | |||
1963 | public void GetSelectedCosts(out float PhysCost, out float StreamCost, out float SimulCost) | ||
1964 | { | ||
1965 | SceneObjectPart p; | ||
1966 | SceneObjectPart[] parts; | ||
1967 | |||
1968 | lock (m_parts) | ||
1969 | { | ||
1970 | parts = m_parts.GetArray(); | ||
1971 | } | ||
1972 | |||
1973 | int nparts = parts.Length; | ||
1974 | |||
1975 | PhysCost = 0; | ||
1976 | StreamCost = 0; | ||
1977 | SimulCost = 0; | ||
1978 | |||
1979 | for (int i = 0; i < nparts; i++) | ||
1980 | { | ||
1981 | p = parts[i]; | ||
1982 | |||
1983 | StreamCost += p.StreamingCost; | ||
1984 | SimulCost += p.SimulationCost; | ||
1985 | PhysCost += p.PhysicsCost; | ||
1986 | } | ||
1987 | } | ||
1988 | |||
1293 | public void SaveScriptedState(XmlTextWriter writer) | 1989 | public void SaveScriptedState(XmlTextWriter writer) |
1294 | { | 1990 | { |
1991 | SaveScriptedState(writer, false); | ||
1992 | } | ||
1993 | |||
1994 | public void SaveScriptedState(XmlTextWriter writer, bool oldIDs) | ||
1995 | { | ||
1295 | XmlDocument doc = new XmlDocument(); | 1996 | XmlDocument doc = new XmlDocument(); |
1997 | doc.XmlResolver=null; | ||
1296 | Dictionary<UUID,string> states = new Dictionary<UUID,string>(); | 1998 | Dictionary<UUID,string> states = new Dictionary<UUID,string>(); |
1297 | 1999 | ||
1298 | SceneObjectPart[] parts = m_parts.GetArray(); | 2000 | SceneObjectPart[] parts = m_parts.GetArray(); |
1299 | for (int i = 0; i < parts.Length; i++) | 2001 | for (int i = 0; i < parts.Length; i++) |
1300 | { | 2002 | { |
1301 | Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); | 2003 | Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs); |
1302 | foreach (KeyValuePair<UUID, string> kvp in pstates) | 2004 | foreach (KeyValuePair<UUID, string> kvp in pstates) |
1303 | states.Add(kvp.Key, kvp.Value); | 2005 | states[kvp.Key] = kvp.Value; |
1304 | } | 2006 | } |
1305 | 2007 | ||
1306 | if (states.Count > 0) | 2008 | if (states.Count > 0) |
@@ -1319,6 +2021,73 @@ namespace OpenSim.Region.Framework.Scenes | |||
1319 | } | 2021 | } |
1320 | } | 2022 | } |
1321 | 2023 | ||
2024 | public byte GetAttachmentPoint() | ||
2025 | { | ||
2026 | return m_rootPart.Shape.State; | ||
2027 | } | ||
2028 | |||
2029 | public void DetachToGround() | ||
2030 | { | ||
2031 | ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar); | ||
2032 | if (avatar == null) | ||
2033 | return; | ||
2034 | m_rootPart.Shape.LastAttachPoint = m_rootPart.Shape.State; | ||
2035 | m_rootPart.AttachedPos = m_rootPart.OffsetPosition; | ||
2036 | avatar.RemoveAttachment(this); | ||
2037 | |||
2038 | Vector3 detachedpos = new Vector3(127f,127f,127f); | ||
2039 | if (avatar == null) | ||
2040 | return; | ||
2041 | |||
2042 | detachedpos = avatar.AbsolutePosition; | ||
2043 | FromItemID = UUID.Zero; | ||
2044 | |||
2045 | AbsolutePosition = detachedpos; | ||
2046 | AttachedAvatar = UUID.Zero; | ||
2047 | |||
2048 | //SceneObjectPart[] parts = m_parts.GetArray(); | ||
2049 | //for (int i = 0; i < parts.Length; i++) | ||
2050 | // parts[i].AttachedAvatar = UUID.Zero; | ||
2051 | |||
2052 | m_rootPart.SetParentLocalId(0); | ||
2053 | AttachmentPoint = (byte)0; | ||
2054 | // must check if buildind should be true or false here | ||
2055 | // m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive,false); | ||
2056 | ApplyPhysics(); | ||
2057 | |||
2058 | HasGroupChanged = true; | ||
2059 | RootPart.Rezzed = DateTime.Now; | ||
2060 | RootPart.RemFlag(PrimFlags.TemporaryOnRez); | ||
2061 | AttachToBackup(); | ||
2062 | m_scene.EventManager.TriggerParcelPrimCountTainted(); | ||
2063 | m_rootPart.ScheduleFullUpdate(); | ||
2064 | m_rootPart.ClearUndoState(); | ||
2065 | } | ||
2066 | |||
2067 | public void DetachToInventoryPrep() | ||
2068 | { | ||
2069 | ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar); | ||
2070 | //Vector3 detachedpos = new Vector3(127f, 127f, 127f); | ||
2071 | if (avatar != null) | ||
2072 | { | ||
2073 | //detachedpos = avatar.AbsolutePosition; | ||
2074 | avatar.RemoveAttachment(this); | ||
2075 | } | ||
2076 | |||
2077 | AttachedAvatar = UUID.Zero; | ||
2078 | |||
2079 | /*SceneObjectPart[] parts = m_parts.GetArray(); | ||
2080 | for (int i = 0; i < parts.Length; i++) | ||
2081 | parts[i].AttachedAvatar = UUID.Zero;*/ | ||
2082 | |||
2083 | m_rootPart.SetParentLocalId(0); | ||
2084 | //m_rootPart.SetAttachmentPoint((byte)0); | ||
2085 | IsAttachment = false; | ||
2086 | AbsolutePosition = m_rootPart.AttachedPos; | ||
2087 | //m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_scene.m_physicalPrim); | ||
2088 | //AttachToBackup(); | ||
2089 | //m_rootPart.ScheduleFullUpdate(); | ||
2090 | } | ||
1322 | 2091 | ||
1323 | /// <summary> | 2092 | /// <summary> |
1324 | /// | 2093 | /// |
@@ -1334,7 +2103,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1334 | { | 2103 | { |
1335 | return Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f); | 2104 | return Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f); |
1336 | } | 2105 | } |
1337 | 2106 | ||
1338 | /// <summary> | 2107 | /// <summary> |
1339 | /// Set a part to act as the root part for this scene object | 2108 | /// Set a part to act as the root part for this scene object |
1340 | /// </summary> | 2109 | /// </summary> |
@@ -1349,7 +2118,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1349 | if (!IsAttachment) | 2118 | if (!IsAttachment) |
1350 | part.ParentID = 0; | 2119 | part.ParentID = 0; |
1351 | part.LinkNum = 0; | 2120 | part.LinkNum = 0; |
1352 | 2121 | ||
1353 | m_parts.Add(m_rootPart.UUID, m_rootPart); | 2122 | m_parts.Add(m_rootPart.UUID, m_rootPart); |
1354 | } | 2123 | } |
1355 | 2124 | ||
@@ -1360,9 +2129,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
1360 | public void AddPart(SceneObjectPart part) | 2129 | public void AddPart(SceneObjectPart part) |
1361 | { | 2130 | { |
1362 | part.SetParent(this); | 2131 | part.SetParent(this); |
1363 | part.LinkNum = m_parts.Add(part.UUID, part); | 2132 | m_parts.Add(part.UUID, part); |
2133 | |||
2134 | part.LinkNum = m_parts.Count; | ||
2135 | |||
1364 | if (part.LinkNum == 2) | 2136 | if (part.LinkNum == 2) |
1365 | RootPart.LinkNum = 1; | 2137 | RootPart.LinkNum = 1; |
2138 | InvalidatePartsLinkMaps(); | ||
1366 | } | 2139 | } |
1367 | 2140 | ||
1368 | /// <summary> | 2141 | /// <summary> |
@@ -1386,32 +2159,50 @@ namespace OpenSim.Region.Framework.Scenes | |||
1386 | parts[i].UUID = UUID.Random(); | 2159 | parts[i].UUID = UUID.Random(); |
1387 | } | 2160 | } |
1388 | 2161 | ||
2162 | // helper provided for parts. | ||
2163 | public int GetSceneMaxUndo() | ||
2164 | { | ||
2165 | if (m_scene != null) | ||
2166 | return m_scene.MaxUndoCount; | ||
2167 | return 5; | ||
2168 | } | ||
2169 | |||
1389 | // justincc: I don't believe this hack is needed any longer, especially since the physics | 2170 | // justincc: I don't believe this hack is needed any longer, especially since the physics |
1390 | // parts of set AbsolutePosition were already commented out. By changing HasGroupChanged to false | 2171 | // parts of set AbsolutePosition were already commented out. By changing HasGroupChanged to false |
1391 | // this method was preventing proper reload of scene objects. | 2172 | // this method was preventing proper reload of scene objects. |
1392 | 2173 | ||
1393 | // dahlia: I had to uncomment it, without it meshing was failing on some prims and objects | 2174 | // dahlia: I had to uncomment it, without it meshing was failing on some prims and objects |
1394 | // at region startup | 2175 | // at region startup |
1395 | 2176 | ||
1396 | // teravus: After this was removed from the linking algorithm, Linked prims no longer collided | 2177 | // teravus: After this was removed from the linking algorithm, Linked prims no longer collided |
1397 | // properly when non-physical if they havn't been moved. This breaks ALL builds. | 2178 | // properly when non-physical if they havn't been moved. This breaks ALL builds. |
1398 | // see: http://opensimulator.org/mantis/view.php?id=3108 | 2179 | // see: http://opensimulator.org/mantis/view.php?id=3108 |
1399 | 2180 | ||
1400 | // Here's the deal, this is ABSOLUTELY CRITICAL so the physics scene gets the update about the | 2181 | // Here's the deal, this is ABSOLUTELY CRITICAL so the physics scene gets the update about the |
1401 | // position of linkset prims. IF YOU CHANGE THIS, YOU MUST TEST colliding with just linked and | 2182 | // position of linkset prims. IF YOU CHANGE THIS, YOU MUST TEST colliding with just linked and |
1402 | // unmoved prims! As soon as you move a Prim/group, it will collide properly because Absolute | 2183 | // unmoved prims! As soon as you move a Prim/group, it will collide properly because Absolute |
1403 | // Position has been set! | 2184 | // Position has been set! |
1404 | 2185 | ||
1405 | public void ResetChildPrimPhysicsPositions() | 2186 | public void ResetChildPrimPhysicsPositions() |
1406 | { | 2187 | { |
1407 | // Setting this SOG's absolute position also loops through and sets the positions | 2188 | // Setting this SOG's absolute position also loops through and sets the positions |
1408 | // of the SOP's in this SOG's linkset. This has the side affect of making sure | 2189 | // of the SOP's in this SOG's linkset. This has the side affect of making sure |
1409 | // the physics world matches the simulated world. | 2190 | // the physics world matches the simulated world. |
1410 | AbsolutePosition = AbsolutePosition; // could someone in the know please explain how this works? | 2191 | // AbsolutePosition = AbsolutePosition; // could someone in the know please explain how this works? |
1411 | 2192 | ||
1412 | // teravus: AbsolutePosition is NOT a normal property! | 2193 | // teravus: AbsolutePosition is NOT a normal property! |
1413 | // the code in the getter of AbsolutePosition is significantly different then the code in the setter! | 2194 | // the code in the getter of AbsolutePosition is significantly different then the code in the setter! |
1414 | // jhurliman: Then why is it a property instead of two methods? | 2195 | // jhurliman: Then why is it a property instead of two methods? |
2196 | |||
2197 | // do only what is supposed to do | ||
2198 | Vector3 groupPosition = m_rootPart.GroupPosition; | ||
2199 | SceneObjectPart[] parts = m_parts.GetArray(); | ||
2200 | |||
2201 | foreach (SceneObjectPart part in parts) | ||
2202 | { | ||
2203 | if (part != m_rootPart) | ||
2204 | part.GroupPosition = groupPosition; | ||
2205 | } | ||
1415 | } | 2206 | } |
1416 | 2207 | ||
1417 | public UUID GetPartsFullID(uint localID) | 2208 | public UUID GetPartsFullID(uint localID) |
@@ -1443,7 +2234,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1443 | // "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}", | 2234 | // "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}", |
1444 | // remoteClient.Name, part.Name, part.LocalId, offsetPos); | 2235 | // remoteClient.Name, part.Name, part.LocalId, offsetPos); |
1445 | 2236 | ||
1446 | part.StoreUndoState(); | 2237 | // part.StoreUndoState(); |
1447 | part.OnGrab(offsetPos, remoteClient); | 2238 | part.OnGrab(offsetPos, remoteClient); |
1448 | } | 2239 | } |
1449 | 2240 | ||
@@ -1463,15 +2254,23 @@ namespace OpenSim.Region.Framework.Scenes | |||
1463 | /// <param name="silent">If true then deletion is not broadcast to clients</param> | 2254 | /// <param name="silent">If true then deletion is not broadcast to clients</param> |
1464 | public void DeleteGroupFromScene(bool silent) | 2255 | public void DeleteGroupFromScene(bool silent) |
1465 | { | 2256 | { |
2257 | // We need to keep track of this state in case this group is still queued for backup. | ||
2258 | IsDeleted = true; | ||
2259 | |||
2260 | DetachFromBackup(); | ||
2261 | |||
2262 | if(Scene == null) // should not happen unless restart/shutdown ? | ||
2263 | return; | ||
2264 | |||
1466 | SceneObjectPart[] parts = m_parts.GetArray(); | 2265 | SceneObjectPart[] parts = m_parts.GetArray(); |
1467 | for (int i = 0; i < parts.Length; i++) | 2266 | for (int i = 0; i < parts.Length; i++) |
1468 | { | 2267 | { |
1469 | SceneObjectPart part = parts[i]; | 2268 | SceneObjectPart part = parts[i]; |
1470 | 2269 | ||
1471 | Scene.ForEachScenePresence(sp => | 2270 | Scene.ForEachScenePresence(delegate(ScenePresence avatar) |
1472 | { | 2271 | { |
1473 | if (!sp.IsChildAgent && sp.ParentID == part.LocalId) | 2272 | if (!avatar.IsChildAgent && avatar.ParentID == part.LocalId && avatar.ParentUUID == UUID.Zero) |
1474 | sp.StandUp(); | 2273 | avatar.StandUp(); |
1475 | 2274 | ||
1476 | if (!silent) | 2275 | if (!silent) |
1477 | { | 2276 | { |
@@ -1479,9 +2278,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
1479 | if (part == m_rootPart) | 2278 | if (part == m_rootPart) |
1480 | { | 2279 | { |
1481 | if (!IsAttachment | 2280 | if (!IsAttachment |
1482 | || AttachedAvatar == sp.UUID | 2281 | || AttachedAvatar == avatar.ControllingClient.AgentId |
1483 | || !HasPrivateAttachmentPoint) | 2282 | || !HasPrivateAttachmentPoint) |
1484 | sp.ControllingClient.SendKillObject(new List<uint> { part.LocalId }); | 2283 | { |
2284 | // Send a kill object immediately | ||
2285 | avatar.ControllingClient.SendKillObject(new List<uint> { part.LocalId }); | ||
2286 | //direct enqueue another delayed kill | ||
2287 | avatar.ControllingClient.SendEntityUpdate(part,PrimUpdateFlags.Kill); | ||
2288 | } | ||
1485 | } | 2289 | } |
1486 | } | 2290 | } |
1487 | }); | 2291 | }); |
@@ -1499,6 +2303,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
1499 | d.AddActiveScripts(count); | 2303 | d.AddActiveScripts(count); |
1500 | } | 2304 | } |
1501 | 2305 | ||
2306 | private const scriptEvents PhysicsNeeedSubsEvents = ( | ||
2307 | scriptEvents.collision | scriptEvents.collision_start | scriptEvents.collision_end | | ||
2308 | scriptEvents.land_collision | scriptEvents.land_collision_start | scriptEvents.land_collision_end); | ||
2309 | |||
2310 | private scriptEvents lastRootPartPhysEvents = 0; | ||
2311 | |||
1502 | public void aggregateScriptEvents() | 2312 | public void aggregateScriptEvents() |
1503 | { | 2313 | { |
1504 | PrimFlags objectflagupdate = (PrimFlags)RootPart.GetEffectiveObjectFlags(); | 2314 | PrimFlags objectflagupdate = (PrimFlags)RootPart.GetEffectiveObjectFlags(); |
@@ -1535,6 +2345,20 @@ namespace OpenSim.Region.Framework.Scenes | |||
1535 | m_scene.RemoveGroupTarget(this); | 2345 | m_scene.RemoveGroupTarget(this); |
1536 | } | 2346 | } |
1537 | 2347 | ||
2348 | scriptEvents rootPartPhysEvents = RootPart.AggregateScriptEvents; | ||
2349 | rootPartPhysEvents &= PhysicsNeeedSubsEvents; | ||
2350 | if (rootPartPhysEvents != lastRootPartPhysEvents) | ||
2351 | { | ||
2352 | lastRootPartPhysEvents = rootPartPhysEvents; | ||
2353 | for (int i = 0; i < parts.Length; i++) | ||
2354 | { | ||
2355 | SceneObjectPart part = parts[i]; | ||
2356 | if (part == null) | ||
2357 | continue; | ||
2358 | part.UpdatePhysicsSubscribedEvents(); | ||
2359 | } | ||
2360 | } | ||
2361 | |||
1538 | ScheduleGroupForFullUpdate(); | 2362 | ScheduleGroupForFullUpdate(); |
1539 | } | 2363 | } |
1540 | 2364 | ||
@@ -1555,28 +2379,44 @@ namespace OpenSim.Region.Framework.Scenes | |||
1555 | /// </summary> | 2379 | /// </summary> |
1556 | public void ApplyPhysics() | 2380 | public void ApplyPhysics() |
1557 | { | 2381 | { |
1558 | // Apply physics to the root prim | ||
1559 | m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive); | ||
1560 | |||
1561 | // Apply physics to child prims | ||
1562 | SceneObjectPart[] parts = m_parts.GetArray(); | 2382 | SceneObjectPart[] parts = m_parts.GetArray(); |
1563 | if (parts.Length > 1) | 2383 | if (parts.Length > 1) |
1564 | { | 2384 | { |
2385 | ResetChildPrimPhysicsPositions(); | ||
2386 | |||
2387 | // Apply physics to the root prim | ||
2388 | m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, true); | ||
2389 | |||
1565 | for (int i = 0; i < parts.Length; i++) | 2390 | for (int i = 0; i < parts.Length; i++) |
1566 | { | 2391 | { |
1567 | SceneObjectPart part = parts[i]; | 2392 | SceneObjectPart part = parts[i]; |
1568 | if (part.LocalId != m_rootPart.LocalId) | 2393 | if (part.LocalId != m_rootPart.LocalId) |
1569 | part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive); | 2394 | part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, true); |
1570 | } | 2395 | } |
1571 | |||
1572 | // Hack to get the physics scene geometries in the right spot | 2396 | // Hack to get the physics scene geometries in the right spot |
1573 | ResetChildPrimPhysicsPositions(); | 2397 | // ResetChildPrimPhysicsPositions(); |
2398 | |||
2399 | if (m_rootPart.PhysActor != null) | ||
2400 | m_rootPart.PhysActor.Building = false; | ||
2401 | } | ||
2402 | else | ||
2403 | { | ||
2404 | // Apply physics to the root prim | ||
2405 | m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, false); | ||
1574 | } | 2406 | } |
1575 | } | 2407 | } |
1576 | 2408 | ||
1577 | public void SetOwnerId(UUID userId) | 2409 | public void SetOwnerId(UUID userId) |
1578 | { | 2410 | { |
1579 | ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); | 2411 | ForEachPart(delegate(SceneObjectPart part) |
2412 | { | ||
2413 | if (part.OwnerID != userId) | ||
2414 | { | ||
2415 | if(part.GroupID != part.OwnerID) | ||
2416 | part.LastOwnerID = part.OwnerID; | ||
2417 | part.OwnerID = userId; | ||
2418 | } | ||
2419 | }); | ||
1580 | } | 2420 | } |
1581 | 2421 | ||
1582 | public void ForEachPart(Action<SceneObjectPart> whatToDo) | 2422 | public void ForEachPart(Action<SceneObjectPart> whatToDo) |
@@ -1601,18 +2441,24 @@ namespace OpenSim.Region.Framework.Scenes | |||
1601 | return; | 2441 | return; |
1602 | } | 2442 | } |
1603 | 2443 | ||
1604 | if (IsDeleted || UUID == UUID.Zero) | 2444 | if (IsDeleted || inTransit || UUID == UUID.Zero) |
1605 | { | 2445 | { |
1606 | // m_log.DebugFormat( | 2446 | // m_log.DebugFormat( |
1607 | // "[WATER WARS]: Ignoring backup of {0} {1} since object is marked as already deleted", Name, UUID); | 2447 | // "[WATER WARS]: Ignoring backup of {0} {1} since object is marked as already deleted", Name, UUID); |
1608 | return; | 2448 | return; |
1609 | } | 2449 | } |
1610 | 2450 | ||
2451 | if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0) | ||
2452 | return; | ||
2453 | |||
1611 | // Since this is the top of the section of call stack for backing up a particular scene object, don't let | 2454 | // Since this is the top of the section of call stack for backing up a particular scene object, don't let |
1612 | // any exception propogate upwards. | 2455 | // any exception propogate upwards. |
1613 | try | 2456 | try |
1614 | { | 2457 | { |
1615 | if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart | 2458 | // if shutting down then there will be nothing to handle the return so leave till next restart |
2459 | if (!m_scene.ShuttingDown && | ||
2460 | m_scene.LoginsEnabled && // We're starting up or doing maintenance, don't mess with things | ||
2461 | !m_scene.LoadingPrims) // Land may not be valid yet | ||
1616 | { | 2462 | { |
1617 | ILandObject parcel = m_scene.LandChannel.GetLandObject( | 2463 | ILandObject parcel = m_scene.LandChannel.GetLandObject( |
1618 | m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); | 2464 | m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); |
@@ -1627,18 +2473,33 @@ namespace OpenSim.Region.Framework.Scenes | |||
1627 | if ((DateTime.UtcNow - RootPart.Rezzed).TotalMinutes > | 2473 | if ((DateTime.UtcNow - RootPart.Rezzed).TotalMinutes > |
1628 | parcel.LandData.OtherCleanTime) | 2474 | parcel.LandData.OtherCleanTime) |
1629 | { | 2475 | { |
2476 | // don't autoreturn if we have a sitting avatar | ||
2477 | // mantis 7828 (but none the provided patchs) | ||
2478 | |||
2479 | if(GetSittingAvatarsCount() > 0) | ||
2480 | { | ||
2481 | // do not respect npcs | ||
2482 | List<ScenePresence> sitters = GetSittingAvatars(); | ||
2483 | foreach(ScenePresence sp in sitters) | ||
2484 | { | ||
2485 | if(!sp.IsDeleted && !sp.IsNPC && sp.IsSatOnObject) | ||
2486 | return; | ||
2487 | } | ||
2488 | } | ||
2489 | |||
1630 | DetachFromBackup(); | 2490 | DetachFromBackup(); |
1631 | m_log.DebugFormat( | 2491 | m_log.DebugFormat( |
1632 | "[SCENE OBJECT GROUP]: Returning object {0} due to parcel autoreturn", | 2492 | "[SCENE OBJECT GROUP]: Returning object {0} due to parcel autoreturn", |
1633 | RootPart.UUID); | 2493 | RootPart.UUID); |
1634 | m_scene.AddReturn(OwnerID == GroupID ? LastOwnerID : OwnerID, Name, AbsolutePosition, "parcel autoreturn"); | 2494 | m_scene.AddReturn(OwnerID == GroupID ? LastOwnerID : OwnerID, Name, AbsolutePosition, "parcel autoreturn"); |
1635 | m_scene.DeRezObjects(null, new List<uint>() { RootPart.LocalId }, UUID.Zero, | 2495 | m_scene.DeRezObjects(null, new List<uint>() { RootPart.LocalId }, UUID.Zero, |
1636 | DeRezAction.Return, UUID.Zero); | 2496 | DeRezAction.Return, UUID.Zero, false); |
1637 | 2497 | ||
1638 | return; | 2498 | return; |
1639 | } | 2499 | } |
1640 | } | 2500 | } |
1641 | } | 2501 | } |
2502 | |||
1642 | } | 2503 | } |
1643 | 2504 | ||
1644 | if (m_scene.UseBackup && HasGroupChanged) | 2505 | if (m_scene.UseBackup && HasGroupChanged) |
@@ -1646,10 +2507,31 @@ namespace OpenSim.Region.Framework.Scenes | |||
1646 | // don't backup while it's selected or you're asking for changes mid stream. | 2507 | // don't backup while it's selected or you're asking for changes mid stream. |
1647 | if (isTimeToPersist() || forcedBackup) | 2508 | if (isTimeToPersist() || forcedBackup) |
1648 | { | 2509 | { |
2510 | if (m_rootPart.PhysActor != null && | ||
2511 | (!m_rootPart.PhysActor.IsPhysical)) | ||
2512 | { | ||
2513 | // Possible ghost prim | ||
2514 | if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition) | ||
2515 | { | ||
2516 | foreach (SceneObjectPart part in m_parts.GetArray()) | ||
2517 | { | ||
2518 | // Re-set physics actor positions and | ||
2519 | // orientations | ||
2520 | part.GroupPosition = m_rootPart.GroupPosition; | ||
2521 | } | ||
2522 | } | ||
2523 | } | ||
1649 | // m_log.DebugFormat( | 2524 | // m_log.DebugFormat( |
1650 | // "[SCENE]: Storing {0}, {1} in {2}", | 2525 | // "[SCENE]: Storing {0}, {1} in {2}", |
1651 | // Name, UUID, m_scene.RegionInfo.RegionName); | 2526 | // Name, UUID, m_scene.RegionInfo.RegionName); |
1652 | 2527 | ||
2528 | if (RootPart.Shape.PCode == 9 && RootPart.Shape.State != 0) | ||
2529 | { | ||
2530 | RootPart.Shape.LastAttachPoint = RootPart.Shape.State; | ||
2531 | RootPart.Shape.State = 0; | ||
2532 | ScheduleGroupForFullUpdate(); | ||
2533 | } | ||
2534 | |||
1653 | SceneObjectGroup backup_group = Copy(false); | 2535 | SceneObjectGroup backup_group = Copy(false); |
1654 | backup_group.RootPart.Velocity = RootPart.Velocity; | 2536 | backup_group.RootPart.Velocity = RootPart.Velocity; |
1655 | backup_group.RootPart.Acceleration = RootPart.Acceleration; | 2537 | backup_group.RootPart.Acceleration = RootPart.Acceleration; |
@@ -1659,13 +2541,21 @@ namespace OpenSim.Region.Framework.Scenes | |||
1659 | GroupContainsForeignPrims = false; | 2541 | GroupContainsForeignPrims = false; |
1660 | 2542 | ||
1661 | m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this); | 2543 | m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this); |
2544 | |||
1662 | datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID); | 2545 | datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID); |
1663 | 2546 | ||
1664 | backup_group.ForEachPart(delegate(SceneObjectPart part) | 2547 | backup_group.ForEachPart(delegate(SceneObjectPart part) |
1665 | { | 2548 | { |
1666 | part.Inventory.ProcessInventoryBackup(datastore); | 2549 | part.Inventory.ProcessInventoryBackup(datastore); |
2550 | |||
2551 | if(part.KeyframeMotion != null) | ||
2552 | { | ||
2553 | part.KeyframeMotion.Delete(); | ||
2554 | part.KeyframeMotion = null; | ||
2555 | } | ||
1667 | }); | 2556 | }); |
1668 | 2557 | ||
2558 | backup_group.Clear(); | ||
1669 | backup_group = null; | 2559 | backup_group = null; |
1670 | } | 2560 | } |
1671 | // else | 2561 | // else |
@@ -1679,7 +2569,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1679 | catch (Exception e) | 2569 | catch (Exception e) |
1680 | { | 2570 | { |
1681 | m_log.ErrorFormat( | 2571 | m_log.ErrorFormat( |
1682 | "[SCENE]: Storing of {0}, {1} in {2} failed with exception {3}{4}", | 2572 | "[SCENE]: Storing of {0}, {1} in {2} failed with exception {3}{4}", |
1683 | Name, UUID, m_scene.RegionInfo.RegionName, e.Message, e.StackTrace); | 2573 | Name, UUID, m_scene.RegionInfo.RegionName, e.Message, e.StackTrace); |
1684 | } | 2574 | } |
1685 | } | 2575 | } |
@@ -1715,14 +2605,21 @@ namespace OpenSim.Region.Framework.Scenes | |||
1715 | /// <returns></returns> | 2605 | /// <returns></returns> |
1716 | public SceneObjectGroup Copy(bool userExposed) | 2606 | public SceneObjectGroup Copy(bool userExposed) |
1717 | { | 2607 | { |
1718 | // FIXME: This is dangerous since it's easy to forget to reset some references when necessary and end up | 2608 | m_dupeInProgress = true; |
1719 | // with bugs that only occur in some circumstances (e.g. crossing between regions on the same simulator | ||
1720 | // but not between regions on different simulators). Really, all copying should be done explicitly. | ||
1721 | SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); | 2609 | SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); |
1722 | 2610 | ||
1723 | dupe.Backup = false; | ||
1724 | dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); | 2611 | dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); |
2612 | |||
2613 | // a copy isnt backedup | ||
2614 | dupe.Backup = false; | ||
2615 | dupe.InvalidBoundsRadius(); | ||
2616 | |||
2617 | // a copy is not in transit hopefully | ||
2618 | dupe.inTransit = false; | ||
2619 | |||
2620 | // new group as no sitting avatars | ||
1725 | dupe.m_sittingAvatars = new List<ScenePresence>(); | 2621 | dupe.m_sittingAvatars = new List<ScenePresence>(); |
2622 | |||
1726 | dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed); | 2623 | dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed); |
1727 | dupe.m_rootPart.LinkNum = m_rootPart.LinkNum; | 2624 | dupe.m_rootPart.LinkNum = m_rootPart.LinkNum; |
1728 | 2625 | ||
@@ -1730,12 +2627,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
1730 | dupe.m_rootPart.TrimPermissions(); | 2627 | dupe.m_rootPart.TrimPermissions(); |
1731 | 2628 | ||
1732 | List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); | 2629 | List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); |
1733 | 2630 | ||
1734 | partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) | 2631 | partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) |
1735 | { | 2632 | { |
1736 | return p1.LinkNum.CompareTo(p2.LinkNum); | 2633 | return p1.LinkNum.CompareTo(p2.LinkNum); |
1737 | } | 2634 | } |
1738 | ); | 2635 | ); |
1739 | 2636 | ||
1740 | foreach (SceneObjectPart part in partList) | 2637 | foreach (SceneObjectPart part in partList) |
1741 | { | 2638 | { |
@@ -1744,43 +2641,59 @@ namespace OpenSim.Region.Framework.Scenes | |||
1744 | { | 2641 | { |
1745 | newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); | 2642 | newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); |
1746 | newPart.LinkNum = part.LinkNum; | 2643 | newPart.LinkNum = part.LinkNum; |
1747 | } | 2644 | // if (userExposed) |
2645 | newPart.ParentID = dupe.m_rootPart.LocalId; | ||
2646 | } | ||
1748 | else | 2647 | else |
1749 | { | 2648 | { |
1750 | newPart = dupe.m_rootPart; | 2649 | newPart = dupe.m_rootPart; |
1751 | } | 2650 | } |
2651 | /* | ||
2652 | bool isphys = ((newPart.Flags & PrimFlags.Physics) != 0); | ||
2653 | bool isphan = ((newPart.Flags & PrimFlags.Phantom) != 0); | ||
1752 | 2654 | ||
1753 | // Need to duplicate the physics actor as well | 2655 | // Need to duplicate the physics actor as well |
1754 | PhysicsActor originalPartPa = part.PhysActor; | 2656 | if (userExposed && (isphys || !isphan || newPart.VolumeDetectActive)) |
1755 | if (originalPartPa != null && userExposed) | ||
1756 | { | 2657 | { |
1757 | PrimitiveBaseShape pbs = newPart.Shape; | 2658 | PrimitiveBaseShape pbs = newPart.Shape; |
1758 | |||
1759 | newPart.PhysActor | 2659 | newPart.PhysActor |
1760 | = m_scene.PhysicsScene.AddPrimShape( | 2660 | = m_scene.PhysicsScene.AddPrimShape( |
1761 | string.Format("{0}/{1}", newPart.Name, newPart.UUID), | 2661 | string.Format("{0}/{1}", newPart.Name, newPart.UUID), |
1762 | pbs, | 2662 | pbs, |
1763 | newPart.AbsolutePosition, | 2663 | newPart.AbsolutePosition, |
1764 | newPart.Scale, | 2664 | newPart.Scale, |
1765 | newPart.RotationOffset, | 2665 | newPart.GetWorldRotation(), |
1766 | originalPartPa.IsPhysical, | 2666 | isphys, |
2667 | isphan, | ||
1767 | newPart.LocalId); | 2668 | newPart.LocalId); |
1768 | 2669 | ||
1769 | newPart.DoPhysicsPropertyUpdate(originalPartPa.IsPhysical, true); | 2670 | newPart.DoPhysicsPropertyUpdate(isphys, true); |
1770 | } | 2671 | */ |
2672 | if (userExposed) | ||
2673 | newPart.ApplyPhysics((uint)newPart.Flags,newPart.VolumeDetectActive,true); | ||
2674 | // } | ||
2675 | // copy keyframemotion | ||
1771 | if (part.KeyframeMotion != null) | 2676 | if (part.KeyframeMotion != null) |
1772 | newPart.KeyframeMotion = part.KeyframeMotion.Copy(dupe); | 2677 | newPart.KeyframeMotion = part.KeyframeMotion.Copy(dupe); |
1773 | } | 2678 | } |
1774 | 2679 | ||
1775 | if (userExposed) | 2680 | if (userExposed) |
1776 | { | 2681 | { |
1777 | dupe.UpdateParentIDs(); | 2682 | // done above dupe.UpdateParentIDs(); |
2683 | |||
2684 | if (dupe.m_rootPart.PhysActor != null) | ||
2685 | dupe.m_rootPart.PhysActor.Building = false; // tell physics to finish building | ||
2686 | |||
2687 | dupe.InvalidateDeepEffectivePerms(); | ||
2688 | |||
1778 | dupe.HasGroupChanged = true; | 2689 | dupe.HasGroupChanged = true; |
1779 | dupe.AttachToBackup(); | 2690 | dupe.AttachToBackup(); |
1780 | 2691 | ||
1781 | ScheduleGroupForFullUpdate(); | 2692 | dupe.ScheduleGroupForFullUpdate(); |
1782 | } | 2693 | } |
1783 | 2694 | ||
2695 | dupe.InvalidatePartsLinkMaps(); | ||
2696 | m_dupeInProgress = false; | ||
1784 | return dupe; | 2697 | return dupe; |
1785 | } | 2698 | } |
1786 | 2699 | ||
@@ -1792,7 +2705,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
1792 | /// <param name="cGroupID"></param> | 2705 | /// <param name="cGroupID"></param> |
1793 | public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) | 2706 | public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) |
1794 | { | 2707 | { |
1795 | SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed)); | 2708 | SceneObjectPart newpart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed); |
2709 | // SceneObjectPart newpart = part.Copy(part.LocalId, OwnerID, GroupID, 0, userExposed); | ||
2710 | // newpart.LocalId = m_scene.AllocateLocalId(); | ||
2711 | |||
2712 | SetRootPart(newpart); | ||
2713 | if (userExposed) | ||
2714 | RootPart.Velocity = Vector3.Zero; // In case source is moving | ||
1796 | } | 2715 | } |
1797 | 2716 | ||
1798 | public void ScriptSetPhysicsStatus(bool usePhysics) | 2717 | public void ScriptSetPhysicsStatus(bool usePhysics) |
@@ -1803,35 +2722,22 @@ namespace OpenSim.Region.Framework.Scenes | |||
1803 | RootPart.KeyframeMotion.Stop(); | 2722 | RootPart.KeyframeMotion.Stop(); |
1804 | RootPart.KeyframeMotion = null; | 2723 | RootPart.KeyframeMotion = null; |
1805 | } | 2724 | } |
1806 | UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect); | 2725 | UpdateFlags(usePhysics, IsTemporary, IsPhantom, IsVolumeDetect); |
1807 | } | 2726 | } |
1808 | 2727 | ||
1809 | public void ScriptSetTemporaryStatus(bool makeTemporary) | 2728 | public void ScriptSetTemporaryStatus(bool makeTemporary) |
1810 | { | 2729 | { |
1811 | UpdatePrimFlags(RootPart.LocalId, UsesPhysics, makeTemporary, IsPhantom, IsVolumeDetect); | 2730 | UpdateFlags(UsesPhysics, makeTemporary, IsPhantom, IsVolumeDetect); |
1812 | } | 2731 | } |
1813 | 2732 | ||
1814 | public void ScriptSetPhantomStatus(bool makePhantom) | 2733 | public void ScriptSetPhantomStatus(bool makePhantom) |
1815 | { | 2734 | { |
1816 | UpdatePrimFlags(RootPart.LocalId, UsesPhysics, IsTemporary, makePhantom, IsVolumeDetect); | 2735 | UpdateFlags(UsesPhysics, IsTemporary, makePhantom, IsVolumeDetect); |
1817 | } | 2736 | } |
1818 | 2737 | ||
1819 | public void ScriptSetVolumeDetect(bool makeVolumeDetect) | 2738 | public void ScriptSetVolumeDetect(bool makeVolumeDetect) |
1820 | { | 2739 | { |
1821 | UpdatePrimFlags(RootPart.LocalId, UsesPhysics, IsTemporary, IsPhantom, makeVolumeDetect); | 2740 | UpdateFlags(UsesPhysics, IsTemporary, IsPhantom, makeVolumeDetect); |
1822 | |||
1823 | /* | ||
1824 | ScriptSetPhantomStatus(false); // What ever it was before, now it's not phantom anymore | ||
1825 | |||
1826 | if (PhysActor != null) // Should always be the case now | ||
1827 | { | ||
1828 | PhysActor.SetVolumeDetect(param); | ||
1829 | } | ||
1830 | if (param != 0) | ||
1831 | AddFlag(PrimFlags.Phantom); | ||
1832 | |||
1833 | ScheduleFullUpdate(); | ||
1834 | */ | ||
1835 | } | 2741 | } |
1836 | 2742 | ||
1837 | public void applyImpulse(Vector3 impulse) | 2743 | public void applyImpulse(Vector3 impulse) |
@@ -1850,13 +2756,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
1850 | 2756 | ||
1851 | if (pa != null) | 2757 | if (pa != null) |
1852 | { | 2758 | { |
1853 | pa.AddForce(impulse, true); | 2759 | // false to be applied as a impulse |
2760 | pa.AddForce(impulse, false); | ||
1854 | m_scene.PhysicsScene.AddPhysicsActorTaint(pa); | 2761 | m_scene.PhysicsScene.AddPhysicsActorTaint(pa); |
1855 | } | 2762 | } |
1856 | } | 2763 | } |
1857 | } | 2764 | } |
1858 | 2765 | ||
1859 | public void applyAngularImpulse(Vector3 impulse) | 2766 | public void ApplyAngularImpulse(Vector3 impulse) |
1860 | { | 2767 | { |
1861 | PhysicsActor pa = RootPart.PhysActor; | 2768 | PhysicsActor pa = RootPart.PhysActor; |
1862 | 2769 | ||
@@ -1864,21 +2771,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
1864 | { | 2771 | { |
1865 | if (!IsAttachment) | 2772 | if (!IsAttachment) |
1866 | { | 2773 | { |
1867 | pa.AddAngularForce(impulse, true); | 2774 | // false to be applied as a impulse |
1868 | m_scene.PhysicsScene.AddPhysicsActorTaint(pa); | 2775 | pa.AddAngularForce(impulse, false); |
1869 | } | ||
1870 | } | ||
1871 | } | ||
1872 | |||
1873 | public void setAngularImpulse(Vector3 impulse) | ||
1874 | { | ||
1875 | PhysicsActor pa = RootPart.PhysActor; | ||
1876 | |||
1877 | if (pa != null) | ||
1878 | { | ||
1879 | if (!IsAttachment) | ||
1880 | { | ||
1881 | pa.Torque = impulse; | ||
1882 | m_scene.PhysicsScene.AddPhysicsActorTaint(pa); | 2776 | m_scene.PhysicsScene.AddPhysicsActorTaint(pa); |
1883 | } | 2777 | } |
1884 | } | 2778 | } |
@@ -1886,20 +2780,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
1886 | 2780 | ||
1887 | public Vector3 GetTorque() | 2781 | public Vector3 GetTorque() |
1888 | { | 2782 | { |
1889 | PhysicsActor pa = RootPart.PhysActor; | 2783 | return RootPart.Torque; |
1890 | |||
1891 | if (pa != null) | ||
1892 | { | ||
1893 | if (!IsAttachment) | ||
1894 | { | ||
1895 | Vector3 torque = pa.Torque; | ||
1896 | return torque; | ||
1897 | } | ||
1898 | } | ||
1899 | |||
1900 | return Vector3.Zero; | ||
1901 | } | 2784 | } |
1902 | 2785 | ||
2786 | // This is used by llMoveToTarget() in an attached object | ||
1903 | public void MoveToTarget(Vector3 target, float tau) | 2787 | public void MoveToTarget(Vector3 target, float tau) |
1904 | { | 2788 | { |
1905 | if (IsAttachment) | 2789 | if (IsAttachment) |
@@ -1907,7 +2791,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1907 | ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar); | 2791 | ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar); |
1908 | 2792 | ||
1909 | if (avatar != null) | 2793 | if (avatar != null) |
1910 | avatar.MoveToTarget(target, false, false); | 2794 | avatar.MoveToTarget(target, false, false, tau); |
1911 | } | 2795 | } |
1912 | else | 2796 | else |
1913 | { | 2797 | { |
@@ -1929,21 +2813,73 @@ namespace OpenSim.Region.Framework.Scenes | |||
1929 | ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar); | 2813 | ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar); |
1930 | 2814 | ||
1931 | if (avatar != null) | 2815 | if (avatar != null) |
2816 | { | ||
1932 | avatar.ResetMoveToTarget(); | 2817 | avatar.ResetMoveToTarget(); |
2818 | } | ||
1933 | } | 2819 | } |
1934 | else | 2820 | else |
1935 | { | 2821 | { |
1936 | PhysicsActor pa = RootPart.PhysActor; | 2822 | PhysicsActor pa = RootPart.PhysActor; |
1937 | 2823 | ||
1938 | if (pa != null && pa.PIDActive) | 2824 | if (pa != null) |
1939 | { | ||
1940 | pa.PIDActive = false; | 2825 | pa.PIDActive = false; |
1941 | 2826 | ||
1942 | ScheduleGroupForTerseUpdate(); | 2827 | RootPart.ScheduleTerseUpdate(); // send a stop information |
2828 | } | ||
2829 | } | ||
2830 | |||
2831 | public void RotLookAt(Quaternion target, float strength, float damping) | ||
2832 | { | ||
2833 | if(IsDeleted) | ||
2834 | return; | ||
2835 | |||
2836 | // non physical is handle in LSL api | ||
2837 | if(!UsesPhysics || IsAttachment) | ||
2838 | return; | ||
2839 | |||
2840 | SceneObjectPart rootpart = m_rootPart; | ||
2841 | if (rootpart != null) | ||
2842 | { | ||
2843 | /* physics still doesnt suport this | ||
2844 | if (rootpart.PhysActor != null) | ||
2845 | { | ||
2846 | rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W); | ||
2847 | rootpart.PhysActor.APIDStrength = strength; | ||
2848 | rootpart.PhysActor.APIDDamping = damping; | ||
2849 | rootpart.PhysActor.APIDActive = true; | ||
1943 | } | 2850 | } |
2851 | */ | ||
2852 | // so do it in rootpart | ||
2853 | rootpart.RotLookAt(target, strength, damping); | ||
2854 | } | ||
2855 | } | ||
2856 | |||
2857 | public void StartLookAt(Quaternion target, float strength, float damping) | ||
2858 | { | ||
2859 | if(IsDeleted) | ||
2860 | return; | ||
2861 | |||
2862 | // non physical is done by LSL APi | ||
2863 | if(!UsesPhysics || IsAttachment) | ||
2864 | return; | ||
2865 | |||
2866 | if (m_rootPart != null) | ||
2867 | m_rootPart.RotLookAt(target, strength, damping); | ||
2868 | } | ||
2869 | |||
2870 | public void StopLookAt() | ||
2871 | { | ||
2872 | SceneObjectPart rootpart = m_rootPart; | ||
2873 | if (rootpart != null) | ||
2874 | { | ||
2875 | if (rootpart.PhysActor != null) | ||
2876 | { | ||
2877 | rootpart.PhysActor.APIDActive = false; | ||
2878 | } | ||
2879 | |||
2880 | rootpart.StopLookAt(); | ||
1944 | } | 2881 | } |
1945 | } | 2882 | } |
1946 | |||
1947 | /// <summary> | 2883 | /// <summary> |
1948 | /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds. | 2884 | /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds. |
1949 | /// </summary> | 2885 | /// </summary> |
@@ -1952,7 +2888,15 @@ namespace OpenSim.Region.Framework.Scenes | |||
1952 | /// <param name="tau">Number of seconds over which to reach target</param> | 2888 | /// <param name="tau">Number of seconds over which to reach target</param> |
1953 | public void SetHoverHeight(float height, PIDHoverType hoverType, float tau) | 2889 | public void SetHoverHeight(float height, PIDHoverType hoverType, float tau) |
1954 | { | 2890 | { |
1955 | PhysicsActor pa = RootPart.PhysActor; | 2891 | PhysicsActor pa = null; |
2892 | if(IsAttachment) | ||
2893 | { | ||
2894 | ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar); | ||
2895 | if (avatar != null) | ||
2896 | pa = avatar.PhysicsActor; | ||
2897 | } | ||
2898 | else | ||
2899 | pa = RootPart.PhysActor; | ||
1956 | 2900 | ||
1957 | if (pa != null) | 2901 | if (pa != null) |
1958 | { | 2902 | { |
@@ -1960,7 +2904,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1960 | { | 2904 | { |
1961 | pa.PIDHoverHeight = height; | 2905 | pa.PIDHoverHeight = height; |
1962 | pa.PIDHoverType = hoverType; | 2906 | pa.PIDHoverType = hoverType; |
1963 | pa.PIDTau = tau; | 2907 | pa.PIDHoverTau = tau; |
1964 | pa.PIDHoverActive = true; | 2908 | pa.PIDHoverActive = true; |
1965 | } | 2909 | } |
1966 | else | 2910 | else |
@@ -1971,25 +2915,33 @@ namespace OpenSim.Region.Framework.Scenes | |||
1971 | } | 2915 | } |
1972 | 2916 | ||
1973 | /// <summary> | 2917 | /// <summary> |
1974 | /// Set the owner of the root part. | 2918 | /// Set the owner of all linkset. |
1975 | /// </summary> | 2919 | /// </summary> |
1976 | /// <param name="part"></param> | ||
1977 | /// <param name="cAgentID"></param> | 2920 | /// <param name="cAgentID"></param> |
1978 | /// <param name="cGroupID"></param> | 2921 | /// <param name="cGroupID"></param> |
1979 | public void SetRootPartOwner(SceneObjectPart part, UUID cAgentID, UUID cGroupID) | 2922 | public void SetOwner(UUID cAgentID, UUID cGroupID) |
1980 | { | 2923 | { |
1981 | part.LastOwnerID = part.OwnerID; | 2924 | SceneObjectPart rpart = RootPart; |
1982 | part.OwnerID = cAgentID; | 2925 | UUID oldowner = rpart.OwnerID; |
1983 | part.GroupID = cGroupID; | 2926 | ForEachPart(delegate(SceneObjectPart part) |
2927 | { | ||
2928 | if(part.GroupID != part.OwnerID) | ||
2929 | part.LastOwnerID = part.OwnerID; | ||
2930 | part.OwnerID = cAgentID; | ||
2931 | part.GroupID = cGroupID; | ||
2932 | }); | ||
1984 | 2933 | ||
1985 | if (part.OwnerID != cAgentID) | 2934 | if (oldowner != cAgentID) |
1986 | { | 2935 | { |
1987 | // Apply Next Owner Permissions if we're not bypassing permissions | 2936 | // Apply Next Owner Permissions if we're not bypassing permissions |
1988 | if (!m_scene.Permissions.BypassPermissions()) | 2937 | if (!m_scene.Permissions.BypassPermissions()) |
2938 | { | ||
1989 | ApplyNextOwnerPermissions(); | 2939 | ApplyNextOwnerPermissions(); |
2940 | InvalidateEffectivePerms(); | ||
2941 | } | ||
1990 | } | 2942 | } |
1991 | 2943 | ||
1992 | part.ScheduleFullUpdate(); | 2944 | rpart.ScheduleFullUpdate(); |
1993 | } | 2945 | } |
1994 | 2946 | ||
1995 | /// <summary> | 2947 | /// <summary> |
@@ -2001,6 +2953,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
2001 | public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) | 2953 | public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) |
2002 | { | 2954 | { |
2003 | SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); | 2955 | SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); |
2956 | // SceneObjectPart newPart = part.Copy(part.LocalId, OwnerID, GroupID, m_parts.Count, userExposed); | ||
2957 | // newPart.LocalId = m_scene.AllocateLocalId(); | ||
2958 | |||
2004 | AddPart(newPart); | 2959 | AddPart(newPart); |
2005 | 2960 | ||
2006 | SetPartAsNonRoot(newPart); | 2961 | SetPartAsNonRoot(newPart); |
@@ -2035,7 +2990,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2035 | public void ServiceObjectPropertiesFamilyRequest(IClientAPI remoteClient, UUID AgentID, uint RequestFlags) | 2990 | public void ServiceObjectPropertiesFamilyRequest(IClientAPI remoteClient, UUID AgentID, uint RequestFlags) |
2036 | { | 2991 | { |
2037 | remoteClient.SendObjectPropertiesFamilyData(RootPart, RequestFlags); | 2992 | remoteClient.SendObjectPropertiesFamilyData(RootPart, RequestFlags); |
2038 | 2993 | ||
2039 | // remoteClient.SendObjectPropertiesFamilyData(RequestFlags, RootPart.UUID, RootPart.OwnerID, RootPart.GroupID, RootPart.BaseMask, | 2994 | // remoteClient.SendObjectPropertiesFamilyData(RequestFlags, RootPart.UUID, RootPart.OwnerID, RootPart.GroupID, RootPart.BaseMask, |
2040 | // RootPart.OwnerMask, RootPart.GroupMask, RootPart.EveryoneMask, RootPart.NextOwnerMask, | 2995 | // RootPart.OwnerMask, RootPart.GroupMask, RootPart.EveryoneMask, RootPart.NextOwnerMask, |
2041 | // RootPart.OwnershipCost, RootPart.ObjectSaleType, RootPart.SalePrice, RootPart.Category, | 2996 | // RootPart.OwnershipCost, RootPart.ObjectSaleType, RootPart.SalePrice, RootPart.Category, |
@@ -2050,6 +3005,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2050 | 3005 | ||
2051 | #endregion | 3006 | #endregion |
2052 | 3007 | ||
3008 | |||
2053 | public override void Update() | 3009 | public override void Update() |
2054 | { | 3010 | { |
2055 | // Check that the group was not deleted before the scheduled update | 3011 | // Check that the group was not deleted before the scheduled update |
@@ -2057,7 +3013,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2057 | // an object has been deleted from a scene before update was processed. | 3013 | // an object has been deleted from a scene before update was processed. |
2058 | // A more fundamental overhaul of the update mechanism is required to eliminate all | 3014 | // A more fundamental overhaul of the update mechanism is required to eliminate all |
2059 | // the race conditions. | 3015 | // the race conditions. |
2060 | if (IsDeleted) | 3016 | if (IsDeleted || inTransit) |
2061 | return; | 3017 | return; |
2062 | 3018 | ||
2063 | // Even temporary objects take part in physics (e.g. temp-on-rez bullets) | 3019 | // Even temporary objects take part in physics (e.g. temp-on-rez bullets) |
@@ -2065,31 +3021,36 @@ namespace OpenSim.Region.Framework.Scenes | |||
2065 | // return; | 3021 | // return; |
2066 | 3022 | ||
2067 | // If we somehow got here to updating the SOG and its root part is not scheduled for update, | 3023 | // If we somehow got here to updating the SOG and its root part is not scheduled for update, |
2068 | // check to see if the physical position or rotation warrant an update. | 3024 | // check to see if the physical position or rotation warrant an update. |
3025 | /* | ||
2069 | if (m_rootPart.UpdateFlag == UpdateRequired.NONE) | 3026 | if (m_rootPart.UpdateFlag == UpdateRequired.NONE) |
2070 | { | 3027 | { |
2071 | bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0); | 3028 | // rootpart SendScheduledUpdates will check if a update is needed |
2072 | 3029 | m_rootPart.UpdateFlag = UpdateRequired.TERSE; | |
2073 | if (UsePhysics && !AbsolutePosition.ApproxEquals(lastPhysGroupPos, 0.02f)) | 3030 | } |
2074 | { | 3031 | */ |
2075 | m_rootPart.UpdateFlag = UpdateRequired.TERSE; | 3032 | if (IsAttachment) |
2076 | lastPhysGroupPos = AbsolutePosition; | 3033 | { |
2077 | } | 3034 | ScenePresence sp = m_scene.GetScenePresence(AttachedAvatar); |
2078 | 3035 | if (sp != null) | |
2079 | if (UsePhysics && !GroupRotation.ApproxEquals(lastPhysGroupRot, 0.1f)) | ||
2080 | { | 3036 | { |
2081 | m_rootPart.UpdateFlag = UpdateRequired.TERSE; | 3037 | sp.SendAttachmentScheduleUpdate(this); |
2082 | lastPhysGroupRot = GroupRotation; | 3038 | return; |
2083 | } | 3039 | } |
2084 | } | 3040 | } |
2085 | 3041 | ||
3042 | // while physics doesn't suports LookAt, we do it in RootPart | ||
3043 | if (!IsSelected) | ||
3044 | RootPart.UpdateLookAt(); | ||
3045 | |||
3046 | double now = Util.GetTimeStampMS(); | ||
3047 | RootPart.SendScheduledUpdates(now); | ||
2086 | SceneObjectPart[] parts = m_parts.GetArray(); | 3048 | SceneObjectPart[] parts = m_parts.GetArray(); |
2087 | for (int i = 0; i < parts.Length; i++) | 3049 | for (int i = 0; i < parts.Length; i++) |
2088 | { | 3050 | { |
2089 | SceneObjectPart part = parts[i]; | 3051 | SceneObjectPart part = parts[i]; |
2090 | if (!IsSelected) | 3052 | if(part != RootPart) |
2091 | part.UpdateLookAt(); | 3053 | part.SendScheduledUpdates(now); |
2092 | part.SendScheduledUpdates(); | ||
2093 | } | 3054 | } |
2094 | } | 3055 | } |
2095 | 3056 | ||
@@ -2105,7 +3066,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2105 | { | 3066 | { |
2106 | // if (IsAttachment) | 3067 | // if (IsAttachment) |
2107 | // m_log.DebugFormat("[SOG]: Scheduling full update for {0} {1}", Name, LocalId); | 3068 | // m_log.DebugFormat("[SOG]: Scheduling full update for {0} {1}", Name, LocalId); |
2108 | 3069 | ||
2109 | checkAtTargets(); | 3070 | checkAtTargets(); |
2110 | RootPart.ScheduleFullUpdate(); | 3071 | RootPart.ScheduleFullUpdate(); |
2111 | 3072 | ||
@@ -2144,15 +3105,24 @@ namespace OpenSim.Region.Framework.Scenes | |||
2144 | return; | 3105 | return; |
2145 | 3106 | ||
2146 | // m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); | 3107 | // m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); |
2147 | |||
2148 | RootPart.SendFullUpdateToAllClients(); | ||
2149 | 3108 | ||
3109 | if (IsAttachment) | ||
3110 | { | ||
3111 | ScenePresence sp = m_scene.GetScenePresence(AttachedAvatar); | ||
3112 | if (sp != null) | ||
3113 | { | ||
3114 | sp.SendAttachmentUpdate(this,UpdateRequired.FULL); | ||
3115 | return; | ||
3116 | } | ||
3117 | } | ||
3118 | |||
3119 | RootPart.SendFullUpdateToAllClientsInternal(); | ||
2150 | SceneObjectPart[] parts = m_parts.GetArray(); | 3120 | SceneObjectPart[] parts = m_parts.GetArray(); |
2151 | for (int i = 0; i < parts.Length; i++) | 3121 | for (int i = 0; i < parts.Length; i++) |
2152 | { | 3122 | { |
2153 | SceneObjectPart part = parts[i]; | 3123 | SceneObjectPart part = parts[i]; |
2154 | if (part != RootPart) | 3124 | if (part != RootPart) |
2155 | part.SendFullUpdateToAllClients(); | 3125 | part.SendFullUpdateToAllClientsInternal(); |
2156 | } | 3126 | } |
2157 | } | 3127 | } |
2158 | 3128 | ||
@@ -2164,7 +3134,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2164 | /// </summary> | 3134 | /// </summary> |
2165 | public void SendGroupRootTerseUpdate() | 3135 | public void SendGroupRootTerseUpdate() |
2166 | { | 3136 | { |
2167 | if (IsDeleted) | 3137 | if (IsDeleted || inTransit) |
2168 | return; | 3138 | return; |
2169 | 3139 | ||
2170 | RootPart.SendTerseUpdateToAllClients(); | 3140 | RootPart.SendTerseUpdateToAllClients(); |
@@ -2174,7 +3144,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2174 | { | 3144 | { |
2175 | if (m_scene == null) // Need to check here as it's null during object creation | 3145 | if (m_scene == null) // Need to check here as it's null during object creation |
2176 | return; | 3146 | return; |
2177 | 3147 | ||
2178 | m_scene.SceneGraph.AddToUpdateList(this); | 3148 | m_scene.SceneGraph.AddToUpdateList(this); |
2179 | } | 3149 | } |
2180 | 3150 | ||
@@ -2183,12 +3153,22 @@ namespace OpenSim.Region.Framework.Scenes | |||
2183 | /// </summary> | 3153 | /// </summary> |
2184 | public void SendGroupTerseUpdate() | 3154 | public void SendGroupTerseUpdate() |
2185 | { | 3155 | { |
2186 | if (IsDeleted) | 3156 | if (IsDeleted || inTransit) |
2187 | return; | 3157 | return; |
2188 | 3158 | ||
3159 | if (IsAttachment) | ||
3160 | { | ||
3161 | ScenePresence sp = m_scene.GetScenePresence(AttachedAvatar); | ||
3162 | if (sp != null) | ||
3163 | { | ||
3164 | sp.SendAttachmentUpdate(this, UpdateRequired.TERSE); | ||
3165 | return; | ||
3166 | } | ||
3167 | } | ||
3168 | |||
2189 | SceneObjectPart[] parts = m_parts.GetArray(); | 3169 | SceneObjectPart[] parts = m_parts.GetArray(); |
2190 | for (int i = 0; i < parts.Length; i++) | 3170 | for (int i = 0; i < parts.Length; i++) |
2191 | parts[i].SendTerseUpdateToAllClients(); | 3171 | parts[i].SendTerseUpdateToAllClientsInternal(); |
2192 | } | 3172 | } |
2193 | 3173 | ||
2194 | /// <summary> | 3174 | /// <summary> |
@@ -2296,9 +3276,41 @@ namespace OpenSim.Region.Framework.Scenes | |||
2296 | return; | 3276 | return; |
2297 | } | 3277 | } |
2298 | 3278 | ||
3279 | // physical prims count limit | ||
3280 | // not very eficient :( | ||
3281 | |||
3282 | if (UsesPhysics && m_scene.m_linksetPhysCapacity > 0 && (PrimCount + objectGroup.PrimCount) > | ||
3283 | m_scene.m_linksetPhysCapacity) | ||
3284 | { | ||
3285 | int cntr = 0; | ||
3286 | foreach (SceneObjectPart part in Parts) | ||
3287 | { | ||
3288 | if (part.PhysicsShapeType != (byte)PhysicsShapeType.None) | ||
3289 | cntr++; | ||
3290 | } | ||
3291 | foreach (SceneObjectPart part in objectGroup.Parts) | ||
3292 | { | ||
3293 | if (part.PhysicsShapeType != (byte)PhysicsShapeType.None) | ||
3294 | cntr++; | ||
3295 | } | ||
3296 | |||
3297 | if (cntr > m_scene.m_linksetPhysCapacity) | ||
3298 | { | ||
3299 | // cancel physics | ||
3300 | RootPart.Flags &= ~PrimFlags.Physics; | ||
3301 | ApplyPhysics(); | ||
3302 | } | ||
3303 | } | ||
3304 | |||
3305 | |||
2299 | // 'linkPart' == the root of the group being linked into this group | 3306 | // 'linkPart' == the root of the group being linked into this group |
2300 | SceneObjectPart linkPart = objectGroup.m_rootPart; | 3307 | SceneObjectPart linkPart = objectGroup.m_rootPart; |
2301 | 3308 | ||
3309 | if (m_rootPart.PhysActor != null) | ||
3310 | m_rootPart.PhysActor.Building = true; | ||
3311 | if (linkPart.PhysActor != null) | ||
3312 | linkPart.PhysActor.Building = true; | ||
3313 | |||
2302 | // physics flags from group to be applied to linked parts | 3314 | // physics flags from group to be applied to linked parts |
2303 | bool grpusephys = UsesPhysics; | 3315 | bool grpusephys = UsesPhysics; |
2304 | bool grptemporary = IsTemporary; | 3316 | bool grptemporary = IsTemporary; |
@@ -2307,7 +3319,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2307 | Vector3 oldGroupPosition = linkPart.GroupPosition; | 3319 | Vector3 oldGroupPosition = linkPart.GroupPosition; |
2308 | Quaternion oldRootRotation = linkPart.RotationOffset; | 3320 | Quaternion oldRootRotation = linkPart.RotationOffset; |
2309 | 3321 | ||
2310 | // A linked SOP remembers its location and rotation relative to the root of a group. | 3322 | // A linked SOP remembers its location and rotation relative to the root of a group. |
2311 | // Convert the root of the group being linked to be relative to the | 3323 | // Convert the root of the group being linked to be relative to the |
2312 | // root of the group being linked to. | 3324 | // root of the group being linked to. |
2313 | // Note: Some of the assignments have complex side effects. | 3325 | // Note: Some of the assignments have complex side effects. |
@@ -2315,22 +3327,24 @@ namespace OpenSim.Region.Framework.Scenes | |||
2315 | // First move the new group's root SOP's position to be relative to ours | 3327 | // First move the new group's root SOP's position to be relative to ours |
2316 | // (radams1: Not sure if the multiple setting of OffsetPosition is required. If not, | 3328 | // (radams1: Not sure if the multiple setting of OffsetPosition is required. If not, |
2317 | // this code can be reordered to have a more logical flow.) | 3329 | // this code can be reordered to have a more logical flow.) |
2318 | linkPart.OffsetPosition = linkPart.GroupPosition - AbsolutePosition; | 3330 | linkPart.setOffsetPosition(linkPart.GroupPosition - AbsolutePosition); |
2319 | // Assign the new parent to the root of the old group | 3331 | // Assign the new parent to the root of the old group |
2320 | linkPart.ParentID = m_rootPart.LocalId; | 3332 | linkPart.ParentID = m_rootPart.LocalId; |
2321 | // Now that it's a child, it's group position is our root position | 3333 | // Now that it's a child, it's group position is our root position |
2322 | linkPart.GroupPosition = AbsolutePosition; | 3334 | linkPart.setGroupPosition(AbsolutePosition); |
2323 | 3335 | ||
2324 | Vector3 axPos = linkPart.OffsetPosition; | ||
2325 | // Rotate the linking root SOP's position to be relative to the new root prim | 3336 | // Rotate the linking root SOP's position to be relative to the new root prim |
2326 | Quaternion parentRot = m_rootPart.RotationOffset; | 3337 | Quaternion parentRot = m_rootPart.RotationOffset; |
2327 | axPos *= Quaternion.Inverse(parentRot); | ||
2328 | linkPart.OffsetPosition = axPos; | ||
2329 | 3338 | ||
2330 | // Make the linking root SOP's rotation relative to the new root prim | 3339 | // Make the linking root SOP's rotation relative to the new root prim |
2331 | Quaternion oldRot = linkPart.RotationOffset; | 3340 | Quaternion oldRot = linkPart.RotationOffset; |
2332 | Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; | 3341 | Quaternion newRot = Quaternion.Conjugate(parentRot) * oldRot; |
2333 | linkPart.RotationOffset = newRot; | 3342 | linkPart.setRotationOffset(newRot); |
3343 | |||
3344 | Vector3 axPos = linkPart.OffsetPosition; | ||
3345 | axPos *= Quaternion.Conjugate(parentRot); | ||
3346 | linkPart.OffsetPosition = axPos; | ||
3347 | |||
2334 | 3348 | ||
2335 | // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset. | 3349 | // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset. |
2336 | // Now that we know this SOG has at least two SOPs in it, the new root | 3350 | // Now that we know this SOG has at least two SOPs in it, the new root |
@@ -2345,10 +3359,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
2345 | if (insert) | 3359 | if (insert) |
2346 | { | 3360 | { |
2347 | linkNum = 2; | 3361 | linkNum = 2; |
3362 | int insertSize = objectGroup.PrimCount; | ||
2348 | foreach (SceneObjectPart part in Parts) | 3363 | foreach (SceneObjectPart part in Parts) |
2349 | { | 3364 | { |
2350 | if (part.LinkNum > 1) | 3365 | if (part.LinkNum > 1) |
2351 | part.LinkNum++; | 3366 | part.LinkNum += insertSize; |
2352 | } | 3367 | } |
2353 | } | 3368 | } |
2354 | else | 3369 | else |
@@ -2360,10 +3375,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
2360 | m_parts.Add(linkPart.UUID, linkPart); | 3375 | m_parts.Add(linkPart.UUID, linkPart); |
2361 | 3376 | ||
2362 | linkPart.SetParent(this); | 3377 | linkPart.SetParent(this); |
3378 | m_scene.updateScenePartGroup(linkPart, this); | ||
3379 | |||
2363 | linkPart.CreateSelected = true; | 3380 | linkPart.CreateSelected = true; |
2364 | 3381 | ||
2365 | // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now | 3382 | // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now |
2366 | linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive); | 3383 | linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive, true); |
2367 | 3384 | ||
2368 | // If the added SOP is physical, also tell the physics engine about the link relationship. | 3385 | // If the added SOP is physical, also tell the physics engine about the link relationship. |
2369 | if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) | 3386 | if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) |
@@ -2373,15 +3390,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
2373 | } | 3390 | } |
2374 | 3391 | ||
2375 | linkPart.LinkNum = linkNum++; | 3392 | linkPart.LinkNum = linkNum++; |
3393 | linkPart.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false); | ||
2376 | 3394 | ||
2377 | // Get a list of the SOP's in the old group in order of their linknum's. | 3395 | // Get a list of the SOP's in the source group in order of their linknum's. |
2378 | SceneObjectPart[] ogParts = objectGroup.Parts; | 3396 | SceneObjectPart[] ogParts = objectGroup.Parts; |
2379 | Array.Sort(ogParts, delegate(SceneObjectPart a, SceneObjectPart b) | 3397 | Array.Sort(ogParts, delegate(SceneObjectPart a, SceneObjectPart b) |
2380 | { | 3398 | { |
2381 | return a.LinkNum - b.LinkNum; | 3399 | return a.LinkNum - b.LinkNum; |
2382 | }); | 3400 | }); |
2383 | 3401 | ||
2384 | // Add each of the SOP's from the old linkset to our linkset | 3402 | // Add each of the SOP's from the source linkset to our linkset |
2385 | for (int i = 0; i < ogParts.Length; i++) | 3403 | for (int i = 0; i < ogParts.Length; i++) |
2386 | { | 3404 | { |
2387 | SceneObjectPart part = ogParts[i]; | 3405 | SceneObjectPart part = ogParts[i]; |
@@ -2391,7 +3409,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2391 | 3409 | ||
2392 | // Update the physics flags for the newly added SOP | 3410 | // Update the physics flags for the newly added SOP |
2393 | // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??) | 3411 | // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??) |
2394 | part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive); | 3412 | part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive, true); |
2395 | 3413 | ||
2396 | // If the added SOP is physical, also tell the physics engine about the link relationship. | 3414 | // If the added SOP is physical, also tell the physics engine about the link relationship. |
2397 | if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) | 3415 | if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) |
@@ -2420,11 +3438,17 @@ namespace OpenSim.Region.Framework.Scenes | |||
2420 | 3438 | ||
2421 | AttachToBackup(); | 3439 | AttachToBackup(); |
2422 | 3440 | ||
2423 | // Here's the deal, this is ABSOLUTELY CRITICAL so the physics scene gets the update about the | 3441 | // Here's the deal, this is ABSOLUTELY CRITICAL so the physics scene gets the update about the |
2424 | // position of linkset prims. IF YOU CHANGE THIS, YOU MUST TEST colliding with just linked and | 3442 | // position of linkset prims. IF YOU CHANGE THIS, YOU MUST TEST colliding with just linked and |
2425 | // unmoved prims! | 3443 | // unmoved prims! |
2426 | ResetChildPrimPhysicsPositions(); | 3444 | ResetChildPrimPhysicsPositions(); |
2427 | 3445 | ||
3446 | InvalidBoundsRadius(); | ||
3447 | InvalidatePartsLinkMaps(); | ||
3448 | |||
3449 | if (m_rootPart.PhysActor != null) | ||
3450 | m_rootPart.PhysActor.Building = false; | ||
3451 | |||
2428 | //HasGroupChanged = true; | 3452 | //HasGroupChanged = true; |
2429 | //ScheduleGroupForFullUpdate(); | 3453 | //ScheduleGroupForFullUpdate(); |
2430 | } | 3454 | } |
@@ -2492,7 +3516,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
2492 | // m_log.DebugFormat( | 3516 | // m_log.DebugFormat( |
2493 | // "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", | 3517 | // "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", |
2494 | // linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); | 3518 | // linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); |
2495 | 3519 | ||
3520 | if (m_rootPart.PhysActor != null) | ||
3521 | m_rootPart.PhysActor.Building = true; | ||
3522 | |||
2496 | linkPart.ClearUndoState(); | 3523 | linkPart.ClearUndoState(); |
2497 | 3524 | ||
2498 | Vector3 worldPos = linkPart.GetWorldPosition(); | 3525 | Vector3 worldPos = linkPart.GetWorldPosition(); |
@@ -2533,7 +3560,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
2533 | // engine about the delink. Someday, linksets should be made first | 3560 | // engine about the delink. Someday, linksets should be made first |
2534 | // class objects in the physics engine interface). | 3561 | // class objects in the physics engine interface). |
2535 | if (linkPartPa != null) | 3562 | if (linkPartPa != null) |
3563 | { | ||
2536 | m_scene.PhysicsScene.RemovePrim(linkPartPa); | 3564 | m_scene.PhysicsScene.RemovePrim(linkPartPa); |
3565 | linkPart.PhysActor = null; | ||
3566 | } | ||
2537 | 3567 | ||
2538 | // We need to reset the child part's position | 3568 | // We need to reset the child part's position |
2539 | // ready for life as a separate object after being a part of another object | 3569 | // ready for life as a separate object after being a part of another object |
@@ -2547,43 +3577,155 @@ namespace OpenSim.Region.Framework.Scenes | |||
2547 | linkPart.GroupPosition = AbsolutePosition + linkPart.OffsetPosition; | 3577 | linkPart.GroupPosition = AbsolutePosition + linkPart.OffsetPosition; |
2548 | linkPart.OffsetPosition = new Vector3(0, 0, 0); | 3578 | linkPart.OffsetPosition = new Vector3(0, 0, 0); |
2549 | */ | 3579 | */ |
2550 | linkPart.GroupPosition = worldPos; | 3580 | linkPart.setGroupPosition(worldPos); |
2551 | linkPart.OffsetPosition = Vector3.Zero; | 3581 | linkPart.setOffsetPosition(Vector3.Zero); |
2552 | linkPart.RotationOffset = worldRot; | 3582 | linkPart.setRotationOffset(worldRot); |
2553 | 3583 | ||
2554 | // Create a new SOG to go around this unlinked and unattached SOP | 3584 | // Create a new SOG to go around this unlinked and unattached SOP |
2555 | SceneObjectGroup objectGroup = new SceneObjectGroup(linkPart); | 3585 | SceneObjectGroup objectGroup = new SceneObjectGroup(linkPart); |
2556 | 3586 | ||
2557 | m_scene.AddNewSceneObject(objectGroup, true); | 3587 | m_scene.AddNewSceneObject(objectGroup, true); |
2558 | 3588 | ||
2559 | if (sendEvents) | ||
2560 | linkPart.TriggerScriptChangedEvent(Changed.LINK); | ||
2561 | |||
2562 | linkPart.Rezzed = RootPart.Rezzed; | 3589 | linkPart.Rezzed = RootPart.Rezzed; |
2563 | 3590 | ||
2564 | // We must persist the delinked group to the database immediately, for safety. The problem | 3591 | // When we delete a group, we currently have to force persist to the database if the object id has changed |
2565 | // is that although in memory the new group has a new SceneGroupID, in the database it | 3592 | // (since delete works by deleting all rows which have a given object id) |
2566 | // still has the parent group's SceneGroupID (until the next backup). This means that if the | 3593 | |
2567 | // parent group is deleted then the delinked group will also be deleted from the database. | 3594 | // this is as it seems to be in sl now |
2568 | // This problem will disappear if the region remains alive long enough for another backup, | 3595 | if(linkPart.PhysicsShapeType == (byte)PhysShapeType.none) |
2569 | // since at that time the delinked group's new SceneGroupID will be written to the database. | 3596 | linkPart.PhysicsShapeType = linkPart.DefaultPhysicsShapeType(); // root prims can't have type none for now |
2570 | // But if the region crashes before that then the prims will be permanently gone, and this must | 3597 | |
2571 | // not happen. (We can't use a just-in-time trick like GroupContainsForeignPrims in this case | 3598 | if (m_rootPart.PhysActor != null) |
2572 | // because the delinked group doesn't know when the source group is deleted.) | 3599 | m_rootPart.PhysActor.Building = false; |
2573 | m_scene.ForceSceneObjectBackup(objectGroup); | 3600 | |
3601 | objectGroup.HasGroupChangedDueToDelink = true; | ||
3602 | |||
3603 | InvalidBoundsRadius(); | ||
3604 | InvalidatePartsLinkMaps(); | ||
3605 | objectGroup.InvalidateEffectivePerms(); | ||
3606 | |||
3607 | if (sendEvents) | ||
3608 | linkPart.TriggerScriptChangedEvent(Changed.LINK); | ||
2574 | 3609 | ||
2575 | return objectGroup; | 3610 | return objectGroup; |
2576 | } | 3611 | } |
2577 | 3612 | ||
3613 | /* working on it | ||
3614 | public void DelinkFromGroup(List<SceneObjectPart> linkParts, bool sendEvents) | ||
3615 | { | ||
3616 | // m_log.DebugFormat( | ||
3617 | // "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", | ||
3618 | // linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); | ||
3619 | |||
3620 | if(PrimCount == 1) | ||
3621 | return; | ||
3622 | |||
3623 | if (m_rootPart.PhysActor != null) | ||
3624 | m_rootPart.PhysActor.Building = true; | ||
3625 | |||
3626 | bool unlinkroot = false; | ||
3627 | foreach(SceneObjectPart linkPart in linkParts) | ||
3628 | { | ||
3629 | // first we only remove child parts | ||
3630 | if(linkPart.LocalId == m_rootPart.LocalId) | ||
3631 | { | ||
3632 | unlinkroot = true; | ||
3633 | continue; | ||
3634 | } | ||
3635 | |||
3636 | lock (m_parts.SyncRoot) | ||
3637 | if(!m_parts.Remove(linkPart.UUID)) | ||
3638 | continue; | ||
3639 | |||
3640 | linkPart.ClearUndoState(); | ||
3641 | |||
3642 | Vector3 worldPos = linkPart.GetWorldPosition(); | ||
3643 | Quaternion worldRot = linkPart.GetWorldRotation(); | ||
3644 | |||
3645 | linkPart.ParentID = 0; | ||
3646 | linkPart.LinkNum = 0; | ||
3647 | |||
3648 | PhysicsActor linkPartPa = linkPart.PhysActor; | ||
3649 | |||
3650 | // Remove the SOP from the physical scene. | ||
3651 | // If the new SOG is physical, it is re-created later. | ||
3652 | // (There is a problem here in that we have not yet told the physics | ||
3653 | // engine about the delink. Someday, linksets should be made first | ||
3654 | // class objects in the physics engine interface). | ||
3655 | if (linkPartPa != null) | ||
3656 | { | ||
3657 | m_scene.PhysicsScene.RemovePrim(linkPartPa); | ||
3658 | linkPart.PhysActor = null; | ||
3659 | } | ||
3660 | |||
3661 | linkPart.setGroupPosition(worldPos); | ||
3662 | linkPart.setOffsetPosition(Vector3.Zero); | ||
3663 | linkPart.setRotationOffset(worldRot); | ||
3664 | |||
3665 | // Create a new SOG to go around this unlinked and unattached SOP | ||
3666 | SceneObjectGroup objectGroup = new SceneObjectGroup(linkPart); | ||
3667 | |||
3668 | m_scene.AddNewSceneObject(objectGroup, true); | ||
3669 | |||
3670 | linkPart.Rezzed = RootPart.Rezzed; | ||
3671 | |||
3672 | // this is as it seems to be in sl now | ||
3673 | if(linkPart.PhysicsShapeType == (byte)PhysShapeType.none) | ||
3674 | linkPart.PhysicsShapeType = linkPart.DefaultPhysicsShapeType(); // root prims can't have type none for now | ||
3675 | |||
3676 | objectGroup.HasGroupChangedDueToDelink = true; | ||
3677 | if (sendEvents) | ||
3678 | linkPart.TriggerScriptChangedEvent(Changed.LINK); | ||
3679 | } | ||
3680 | |||
3681 | if(unlinkroot) | ||
3682 | { | ||
3683 | //TODO | ||
3684 | } | ||
3685 | |||
3686 | lock (m_parts.SyncRoot) | ||
3687 | { | ||
3688 | SceneObjectPart[] parts = m_parts.GetArray(); | ||
3689 | if (parts.Length == 1) | ||
3690 | { | ||
3691 | // Single prim left | ||
3692 | m_rootPart.LinkNum = 0; | ||
3693 | } | ||
3694 | else | ||
3695 | { | ||
3696 | m_rootPart.LinkNum = 1; | ||
3697 | int linknum = 2; | ||
3698 | for (int i = 1; i < parts.Length; i++) | ||
3699 | parts[i].LinkNum = linknum++; | ||
3700 | } | ||
3701 | } | ||
3702 | |||
3703 | InvalidBoundsRadius(); | ||
3704 | |||
3705 | if (m_rootPart.PhysActor != null) | ||
3706 | m_rootPart.PhysActor.Building = false; | ||
3707 | |||
3708 | // When we delete a group, we currently have to force persist to the database if the object id has changed | ||
3709 | // (since delete works by deleting all rows which have a given object id) | ||
3710 | |||
3711 | Scene.SimulationDataService.RemoveObject(UUID, Scene.RegionInfo.RegionID); | ||
3712 | HasGroupChangedDueToDelink = true; | ||
3713 | TriggerScriptChangedEvent(Changed.LINK); | ||
3714 | return; | ||
3715 | } | ||
3716 | */ | ||
2578 | /// <summary> | 3717 | /// <summary> |
2579 | /// Stop this object from being persisted over server restarts. | 3718 | /// Stop this object from being persisted over server restarts. |
2580 | /// </summary> | 3719 | /// </summary> |
2581 | /// <param name="objectGroup"></param> | 3720 | /// <param name="objectGroup"></param> |
2582 | public virtual void DetachFromBackup() | 3721 | public virtual void DetachFromBackup() |
2583 | { | 3722 | { |
2584 | if (Backup && Scene != null) | 3723 | if (m_scene != null) |
2585 | m_scene.EventManager.OnBackup -= ProcessBackup; | 3724 | { |
2586 | 3725 | m_scene.SceneGraph.FireDetachFromBackup(this); | |
3726 | if (Backup) | ||
3727 | m_scene.EventManager.OnBackup -= ProcessBackup; | ||
3728 | } | ||
2587 | Backup = false; | 3729 | Backup = false; |
2588 | } | 3730 | } |
2589 | 3731 | ||
@@ -2597,14 +3739,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
2597 | Quaternion parentRot = oldGroupRotation; | 3739 | Quaternion parentRot = oldGroupRotation; |
2598 | Quaternion oldRot = part.RotationOffset; | 3740 | Quaternion oldRot = part.RotationOffset; |
2599 | 3741 | ||
2600 | // Move our position to not be relative to the old parent | 3742 | // Move our position in world |
2601 | Vector3 axPos = part.OffsetPosition; | 3743 | Vector3 axPos = part.OffsetPosition; |
2602 | axPos *= parentRot; | 3744 | axPos *= parentRot; |
2603 | part.OffsetPosition = axPos; | 3745 | Vector3 newPos = oldGroupPosition + axPos; |
2604 | part.GroupPosition = oldGroupPosition + part.OffsetPosition; | 3746 | part.setGroupPosition(newPos); |
2605 | part.OffsetPosition = Vector3.Zero; | 3747 | part.setOffsetPosition(Vector3.Zero); |
2606 | 3748 | ||
2607 | // Compution our rotation to be not relative to the old parent | 3749 | // Compution our rotation in world |
2608 | Quaternion worldRot = parentRot * oldRot; | 3750 | Quaternion worldRot = parentRot * oldRot; |
2609 | part.RotationOffset = worldRot; | 3751 | part.RotationOffset = worldRot; |
2610 | 3752 | ||
@@ -2615,29 +3757,32 @@ namespace OpenSim.Region.Framework.Scenes | |||
2615 | 3757 | ||
2616 | part.LinkNum = linkNum; | 3758 | part.LinkNum = linkNum; |
2617 | 3759 | ||
3760 | m_scene.updateScenePartGroup(part, this); | ||
3761 | |||
2618 | // Compute the new position of this SOP relative to the group position | 3762 | // Compute the new position of this SOP relative to the group position |
2619 | part.OffsetPosition = part.GroupPosition - AbsolutePosition; | 3763 | part.setOffsetPosition(newPos - AbsolutePosition); |
2620 | 3764 | ||
2621 | // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times. | 3765 | // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times. |
2622 | // It would have the affect of setting the physics engine position multiple | 3766 | // It would have the affect of setting the physics engine position multiple |
2623 | // times. In theory, that is not necessary but I don't have a good linkset | 3767 | // times. In theory, that is not necessary but I don't have a good linkset |
2624 | // test to know that cleaning up this code wouldn't break things.) | 3768 | // test to know that cleaning up this code wouldn't break things.) |
2625 | 3769 | ||
2626 | // Rotate the relative position by the rotation of the group | ||
2627 | Quaternion rootRotation = m_rootPart.RotationOffset; | ||
2628 | Vector3 pos = part.OffsetPosition; | ||
2629 | pos *= Quaternion.Inverse(rootRotation); | ||
2630 | part.OffsetPosition = pos; | ||
2631 | |||
2632 | // Compute the SOP's rotation relative to the rotation of the group. | 3770 | // Compute the SOP's rotation relative to the rotation of the group. |
2633 | parentRot = m_rootPart.RotationOffset; | 3771 | parentRot = m_rootPart.RotationOffset; |
3772 | |||
2634 | oldRot = part.RotationOffset; | 3773 | oldRot = part.RotationOffset; |
2635 | Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; | 3774 | Quaternion newRot = Quaternion.Conjugate(parentRot) * worldRot; |
2636 | part.RotationOffset = newRot; | 3775 | part.setRotationOffset(newRot); |
3776 | |||
3777 | Vector3 pos = part.OffsetPosition; | ||
3778 | pos *= Quaternion.Conjugate(parentRot); | ||
3779 | |||
3780 | part.OffsetPosition = pos; // update position and orientation on physics also | ||
2637 | 3781 | ||
2638 | // Since this SOP's state has changed, push those changes into the physics engine | 3782 | // Since this SOP's state has changed, push those changes into the physics engine |
2639 | // and the simulator. | 3783 | // and the simulator. |
2640 | part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect); | 3784 | // done on caller |
3785 | // part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false); | ||
2641 | } | 3786 | } |
2642 | 3787 | ||
2643 | /// <summary> | 3788 | /// <summary> |
@@ -2652,30 +3797,26 @@ namespace OpenSim.Region.Framework.Scenes | |||
2652 | { | 3797 | { |
2653 | if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) | 3798 | if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) |
2654 | { | 3799 | { |
3800 | if (BlockGrabOverride) | ||
3801 | return; | ||
3802 | |||
2655 | SceneObjectPart part = GetPart(partID); | 3803 | SceneObjectPart part = GetPart(partID); |
2656 | 3804 | ||
2657 | if (part == null) | 3805 | if (part == null) |
2658 | return; | 3806 | return; |
2659 | 3807 | ||
3808 | if (part.BlockGrab) | ||
3809 | return; | ||
3810 | |||
2660 | PhysicsActor pa = m_rootPart.PhysActor; | 3811 | PhysicsActor pa = m_rootPart.PhysActor; |
2661 | 3812 | ||
2662 | if (pa != null) | 3813 | if (pa != null && pa.IsPhysical) |
2663 | { | 3814 | { |
2664 | if (pa.IsPhysical) | 3815 | // empirically convert distance diference to a impulse |
2665 | { | 3816 | Vector3 grabforce = pos - AbsolutePosition; |
2666 | if (!BlockGrabOverride && !part.BlockGrab) | 3817 | grabforce = grabforce * (pa.Mass * 0.1f); |
2667 | { | 3818 | pa.AddForce(grabforce, false); |
2668 | Vector3 llmoveforce = pos - AbsolutePosition; | 3819 | m_scene.PhysicsScene.AddPhysicsActorTaint(pa); |
2669 | Vector3 grabforce = llmoveforce; | ||
2670 | grabforce = (grabforce / 10) * pa.Mass; | ||
2671 | pa.AddForce(grabforce, true); | ||
2672 | m_scene.PhysicsScene.AddPhysicsActorTaint(pa); | ||
2673 | } | ||
2674 | } | ||
2675 | else | ||
2676 | { | ||
2677 | NonPhysicalGrabMovement(pos); | ||
2678 | } | ||
2679 | } | 3820 | } |
2680 | else | 3821 | else |
2681 | { | 3822 | { |
@@ -2704,6 +3845,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
2704 | /// <param name="remoteClient"></param> | 3845 | /// <param name="remoteClient"></param> |
2705 | public void SpinStart(IClientAPI remoteClient) | 3846 | public void SpinStart(IClientAPI remoteClient) |
2706 | { | 3847 | { |
3848 | if (BlockGrabOverride || m_rootPart.BlockGrab) | ||
3849 | return; | ||
2707 | if (m_scene.EventManager.TriggerGroupSpinStart(UUID)) | 3850 | if (m_scene.EventManager.TriggerGroupSpinStart(UUID)) |
2708 | { | 3851 | { |
2709 | PhysicsActor pa = m_rootPart.PhysActor; | 3852 | PhysicsActor pa = m_rootPart.PhysActor; |
@@ -2725,72 +3868,74 @@ namespace OpenSim.Region.Framework.Scenes | |||
2725 | /// <param name="remoteClient"></param> | 3868 | /// <param name="remoteClient"></param> |
2726 | public void SpinMovement(Quaternion newOrientation, IClientAPI remoteClient) | 3869 | public void SpinMovement(Quaternion newOrientation, IClientAPI remoteClient) |
2727 | { | 3870 | { |
2728 | // The incoming newOrientation, sent by the client, "seems" to be the | 3871 | // The incoming newOrientation, sent by the client, "seems" to be the |
2729 | // desired target orientation. This needs further verification; in particular, | 3872 | // desired target orientation. This needs further verification; in particular, |
2730 | // one would expect that the initial incoming newOrientation should be | 3873 | // one would expect that the initial incoming newOrientation should be |
2731 | // fairly close to the original prim's physical orientation, | 3874 | // fairly close to the original prim's physical orientation, |
2732 | // m_rootPart.PhysActor.Orientation. This however does not seem to be the | 3875 | // m_rootPart.PhysActor.Orientation. This however does not seem to be the |
2733 | // case (might just be an issue with different quaternions representing the | 3876 | // case (might just be an issue with different quaternions representing the |
2734 | // same rotation, or it might be a coordinate system issue). | 3877 | // same rotation, or it might be a coordinate system issue). |
2735 | // | 3878 | // |
2736 | // Since it's not clear what the relationship is between the PhysActor.Orientation | 3879 | // Since it's not clear what the relationship is between the PhysActor.Orientation |
2737 | // and the incoming orientations sent by the client, we take an alternative approach | 3880 | // and the incoming orientations sent by the client, we take an alternative approach |
2738 | // of calculating the delta rotation between the orientations being sent by the | 3881 | // of calculating the delta rotation between the orientations being sent by the |
2739 | // client. (Since a spin is invoked by ctrl+shift+drag in the client, we expect | 3882 | // client. (Since a spin is invoked by ctrl+shift+drag in the client, we expect |
2740 | // a steady stream of several new orientations coming in from the client.) | 3883 | // a steady stream of several new orientations coming in from the client.) |
2741 | // This ensures that the delta rotations are being calculated from self-consistent | 3884 | // This ensures that the delta rotations are being calculated from self-consistent |
2742 | // pairs of old/new rotations. Given the delta rotation, we apply a torque around | 3885 | // pairs of old/new rotations. Given the delta rotation, we apply a torque around |
2743 | // the delta rotation axis, scaled by the object mass times an arbitrary scaling | 3886 | // the delta rotation axis, scaled by the object mass times an arbitrary scaling |
2744 | // factor (to ensure the resulting torque is not "too strong" or "too weak"). | 3887 | // factor (to ensure the resulting torque is not "too strong" or "too weak"). |
2745 | // | 3888 | // |
2746 | // Ideally we need to calculate (probably iteratively) the exact torque or series | 3889 | // Ideally we need to calculate (probably iteratively) the exact torque or series |
2747 | // of torques needed to arrive exactly at the destination orientation. However, since | 3890 | // of torques needed to arrive exactly at the destination orientation. However, since |
2748 | // it is not yet clear how to map the destination orientation (provided by the viewer) | 3891 | // it is not yet clear how to map the destination orientation (provided by the viewer) |
2749 | // into PhysActor orientations (needed by the physics engine), we omit this step. | 3892 | // into PhysActor orientations (needed by the physics engine), we omit this step. |
2750 | // This means that the resulting torque will at least be in the correct direction, | 3893 | // This means that the resulting torque will at least be in the correct direction, |
2751 | // but it will result in over-shoot or under-shoot of the target orientation. | 3894 | // but it will result in over-shoot or under-shoot of the target orientation. |
2752 | // For the end user, this means that ctrl+shift+drag can be used for relative, | 3895 | // For the end user, this means that ctrl+shift+drag can be used for relative, |
2753 | // but not absolute, adjustments of orientation for physical prims. | 3896 | // but not absolute, adjustments of orientation for physical prims. |
3897 | |||
3898 | if (BlockGrabOverride || m_rootPart.BlockGrab) | ||
3899 | return; | ||
3900 | |||
2754 | if (m_scene.EventManager.TriggerGroupSpin(UUID, newOrientation)) | 3901 | if (m_scene.EventManager.TriggerGroupSpin(UUID, newOrientation)) |
2755 | { | 3902 | { |
2756 | PhysicsActor pa = m_rootPart.PhysActor; | 3903 | PhysicsActor pa = m_rootPart.PhysActor; |
2757 | 3904 | ||
2758 | if (pa != null) | 3905 | if (pa != null && pa.IsPhysical) |
2759 | { | 3906 | { |
2760 | if (pa.IsPhysical) | 3907 | if (m_rootPart.IsWaitingForFirstSpinUpdatePacket) |
2761 | { | 3908 | { |
2762 | if (m_rootPart.IsWaitingForFirstSpinUpdatePacket) | 3909 | // first time initialization of "old" orientation for calculation of delta rotations |
2763 | { | 3910 | m_rootPart.SpinOldOrientation = newOrientation; |
2764 | // first time initialization of "old" orientation for calculation of delta rotations | 3911 | m_rootPart.IsWaitingForFirstSpinUpdatePacket = false; |
2765 | m_rootPart.SpinOldOrientation = newOrientation; | ||
2766 | m_rootPart.IsWaitingForFirstSpinUpdatePacket = false; | ||
2767 | } | ||
2768 | else | ||
2769 | { | ||
2770 | // save and update old orientation | ||
2771 | Quaternion old = m_rootPart.SpinOldOrientation; | ||
2772 | m_rootPart.SpinOldOrientation = newOrientation; | ||
2773 | //m_log.Error("[SCENE OBJECT GROUP]: Old orientation is " + old); | ||
2774 | //m_log.Error("[SCENE OBJECT GROUP]: Incoming new orientation is " + newOrientation); | ||
2775 | |||
2776 | // compute difference between previous old rotation and new incoming rotation | ||
2777 | Quaternion minimalRotationFromQ1ToQ2 = Quaternion.Inverse(old) * newOrientation; | ||
2778 | |||
2779 | float rotationAngle; | ||
2780 | Vector3 rotationAxis; | ||
2781 | minimalRotationFromQ1ToQ2.GetAxisAngle(out rotationAxis, out rotationAngle); | ||
2782 | rotationAxis.Normalize(); | ||
2783 | |||
2784 | //m_log.Error("SCENE OBJECT GROUP]: rotation axis is " + rotationAxis); | ||
2785 | Vector3 spinforce = new Vector3(rotationAxis.X, rotationAxis.Y, rotationAxis.Z); | ||
2786 | spinforce = (spinforce/8) * pa.Mass; // 8 is an arbitrary torque scaling factor | ||
2787 | pa.AddAngularForce(spinforce,true); | ||
2788 | m_scene.PhysicsScene.AddPhysicsActorTaint(pa); | ||
2789 | } | ||
2790 | } | 3912 | } |
2791 | else | 3913 | else |
2792 | { | 3914 | { |
2793 | NonPhysicalSpinMovement(newOrientation); | 3915 | // save and update old orientation |
3916 | Quaternion old = m_rootPart.SpinOldOrientation; | ||
3917 | m_rootPart.SpinOldOrientation = newOrientation; | ||
3918 | //m_log.Error("[SCENE OBJECT GROUP]: Old orientation is " + old); | ||
3919 | //m_log.Error("[SCENE OBJECT GROUP]: Incoming new orientation is " + newOrientation); | ||
3920 | |||
3921 | // compute difference between previous old rotation and new incoming rotation | ||
3922 | Quaternion minimalRotationFromQ1ToQ2 = newOrientation * Quaternion.Inverse(old); | ||
3923 | |||
3924 | float rotationAngle; | ||
3925 | Vector3 spinforce; | ||
3926 | minimalRotationFromQ1ToQ2.GetAxisAngle(out spinforce, out rotationAngle); | ||
3927 | if(Math.Abs(rotationAngle)< 0.001) | ||
3928 | return; | ||
3929 | |||
3930 | spinforce.Normalize(); | ||
3931 | |||
3932 | //m_log.Error("SCENE OBJECT GROUP]: rotation axis is " + rotationAxis); | ||
3933 | if(rotationAngle > 0) | ||
3934 | spinforce = spinforce * pa.Mass * 0.1f; // 0.1 is an arbitrary torque scaling factor | ||
3935 | else | ||
3936 | spinforce = spinforce * pa.Mass * -0.1f; // 0.1 is an arbitrary torque scaling | ||
3937 | pa.AddAngularForce(spinforce,true); | ||
3938 | m_scene.PhysicsScene.AddPhysicsActorTaint(pa); | ||
2794 | } | 3939 | } |
2795 | } | 3940 | } |
2796 | else | 3941 | else |
@@ -2880,51 +4025,80 @@ namespace OpenSim.Region.Framework.Scenes | |||
2880 | /// <param name="SetTemporary"></param> | 4025 | /// <param name="SetTemporary"></param> |
2881 | /// <param name="SetPhantom"></param> | 4026 | /// <param name="SetPhantom"></param> |
2882 | /// <param name="SetVolumeDetect"></param> | 4027 | /// <param name="SetVolumeDetect"></param> |
2883 | public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect) | 4028 | public void UpdateFlags(bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect) |
2884 | { | 4029 | { |
2885 | SceneObjectPart selectionPart = GetPart(localID); | 4030 | if (m_scene == null || IsDeleted) |
4031 | return; | ||
2886 | 4032 | ||
2887 | if (Scene != null) | 4033 | HasGroupChanged = true; |
2888 | { | ||
2889 | if (SetTemporary) | ||
2890 | { | ||
2891 | DetachFromBackup(); | ||
2892 | // Remove from database and parcel prim count | ||
2893 | // | ||
2894 | m_scene.DeleteFromStorage(UUID); | ||
2895 | } | ||
2896 | else if (!Backup) | ||
2897 | { | ||
2898 | // Previously been temporary now switching back so make it | ||
2899 | // available for persisting again | ||
2900 | AttachToBackup(); | ||
2901 | } | ||
2902 | 4034 | ||
2903 | m_scene.EventManager.TriggerParcelPrimCountTainted(); | 4035 | if (SetTemporary) |
4036 | { | ||
4037 | DetachFromBackup(); | ||
4038 | // Remove from database and parcel prim count | ||
4039 | // | ||
4040 | m_scene.DeleteFromStorage(UUID); | ||
4041 | } | ||
4042 | else if (!Backup) | ||
4043 | { | ||
4044 | // Previously been temporary now switching back so make it | ||
4045 | // available for persisting again | ||
4046 | AttachToBackup(); | ||
2904 | } | 4047 | } |
2905 | 4048 | ||
2906 | if (selectionPart != null) | 4049 | |
4050 | SceneObjectPart[] parts = m_parts.GetArray(); | ||
4051 | |||
4052 | if (UsePhysics) | ||
2907 | { | 4053 | { |
2908 | SceneObjectPart[] parts = m_parts.GetArray(); | 4054 | int maxprims = m_scene.m_linksetPhysCapacity; |
2909 | 4055 | bool checkShape = (maxprims > 0 && | |
2910 | if (Scene != null) | 4056 | parts.Length > maxprims); |
4057 | |||
4058 | for (int i = 0; i < parts.Length; i++) | ||
2911 | { | 4059 | { |
2912 | for (int i = 0; i < parts.Length; i++) | 4060 | SceneObjectPart part = parts[i]; |
4061 | |||
4062 | if(part.PhysicsShapeType == (byte)PhysicsShapeType.None) | ||
4063 | continue; // assuming root type was checked elsewhere | ||
4064 | |||
4065 | if (checkShape) | ||
2913 | { | 4066 | { |
2914 | SceneObjectPart part = parts[i]; | 4067 | if (--maxprims < 0) |
2915 | if (part.Scale.X > m_scene.m_maxPhys || | ||
2916 | part.Scale.Y > m_scene.m_maxPhys || | ||
2917 | part.Scale.Z > m_scene.m_maxPhys ) | ||
2918 | { | 4068 | { |
2919 | UsePhysics = false; // Reset physics | 4069 | UsePhysics = false; |
2920 | break; | 4070 | break; |
2921 | } | 4071 | } |
2922 | } | 4072 | } |
4073 | |||
4074 | if (part.Scale.X > m_scene.m_maxPhys || | ||
4075 | part.Scale.Y > m_scene.m_maxPhys || | ||
4076 | part.Scale.Z > m_scene.m_maxPhys ) | ||
4077 | { | ||
4078 | UsePhysics = false; // Reset physics | ||
4079 | break; | ||
4080 | } | ||
2923 | } | 4081 | } |
4082 | } | ||
4083 | |||
4084 | if (parts.Length > 1) | ||
4085 | { | ||
4086 | m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true); | ||
2924 | 4087 | ||
2925 | for (int i = 0; i < parts.Length; i++) | 4088 | for (int i = 0; i < parts.Length; i++) |
2926 | parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); | 4089 | { |
4090 | |||
4091 | if (parts[i].UUID != m_rootPart.UUID) | ||
4092 | parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true); | ||
4093 | } | ||
4094 | |||
4095 | if (m_rootPart.PhysActor != null) | ||
4096 | m_rootPart.PhysActor.Building = false; | ||
2927 | } | 4097 | } |
4098 | else | ||
4099 | m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, false); | ||
4100 | |||
4101 | m_scene.EventManager.TriggerParcelPrimCountTainted(); | ||
2928 | } | 4102 | } |
2929 | 4103 | ||
2930 | public void UpdateExtraParam(uint localID, ushort type, bool inUse, byte[] data) | 4104 | public void UpdateExtraParam(uint localID, ushort type, bool inUse, byte[] data) |
@@ -2936,24 +4110,21 @@ namespace OpenSim.Region.Framework.Scenes | |||
2936 | } | 4110 | } |
2937 | } | 4111 | } |
2938 | 4112 | ||
4113 | |||
4114 | |||
2939 | /// <summary> | 4115 | /// <summary> |
2940 | /// Update the texture entry for this part | 4116 | /// Gets the number of parts |
2941 | /// </summary> | 4117 | /// </summary> |
2942 | /// <param name="localID"></param> | 4118 | /// <returns></returns> |
2943 | /// <param name="textureEntry"></param> | 4119 | public int GetPartCount() |
2944 | public void UpdateTextureEntry(uint localID, byte[] textureEntry) | ||
2945 | { | 4120 | { |
2946 | SceneObjectPart part = GetPart(localID); | 4121 | return Parts.Count(); |
2947 | if (part != null) | ||
2948 | { | ||
2949 | part.UpdateTextureEntry(textureEntry); | ||
2950 | } | ||
2951 | } | 4122 | } |
2952 | 4123 | ||
2953 | public void AdjustChildPrimPermissions(bool forceTaskInventoryPermissive) | 4124 | public void AdjustChildPrimPermissions(bool forceTaskInventoryPermissive) |
2954 | { | 4125 | { |
2955 | uint newOwnerMask = (uint)(PermissionMask.All | PermissionMask.Export) & 0xfffffff8; // Mask folded bits | 4126 | uint newOwnerMask = (uint)(PermissionMask.All | PermissionMask.Export) & 0xfffffff0; // Mask folded bits |
2956 | uint foldedPerms = RootPart.OwnerMask & 3; | 4127 | uint foldedPerms = RootPart.OwnerMask & (uint)PermissionMask.FoldedMask; |
2957 | 4128 | ||
2958 | ForEachPart(part => | 4129 | ForEachPart(part => |
2959 | { | 4130 | { |
@@ -2964,14 +4135,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
2964 | part.Inventory.ApplyGodPermissions(part.BaseMask); | 4135 | part.Inventory.ApplyGodPermissions(part.BaseMask); |
2965 | }); | 4136 | }); |
2966 | 4137 | ||
2967 | uint lockMask = ~(uint)(PermissionMask.Move | PermissionMask.Modify); | 4138 | uint lockMask = ~(uint)(PermissionMask.Move); |
2968 | uint lockBit = RootPart.OwnerMask & (uint)(PermissionMask.Move | PermissionMask.Modify); | 4139 | uint lockBit = RootPart.OwnerMask & (uint)(PermissionMask.Move); |
2969 | RootPart.OwnerMask = (RootPart.OwnerMask & lockBit) | ((newOwnerMask | foldedPerms) & lockMask); | 4140 | RootPart.OwnerMask = (RootPart.OwnerMask & lockBit) | ((newOwnerMask | foldedPerms) & lockMask); |
2970 | 4141 | ||
2971 | // m_log.DebugFormat( | 4142 | // m_log.DebugFormat( |
2972 | // "[SCENE OBJECT GROUP]: RootPart.OwnerMask now {0} for {1} in {2}", | 4143 | // "[SCENE OBJECT GROUP]: RootPart.OwnerMask now {0} for {1} in {2}", |
2973 | // (OpenMetaverse.PermissionMask)RootPart.OwnerMask, Name, Scene.Name); | 4144 | // (OpenMetaverse.PermissionMask)RootPart.OwnerMask, Name, Scene.Name); |
2974 | 4145 | InvalidateEffectivePerms(); | |
2975 | RootPart.ScheduleFullUpdate(); | 4146 | RootPart.ScheduleFullUpdate(); |
2976 | } | 4147 | } |
2977 | 4148 | ||
@@ -2980,7 +4151,24 @@ namespace OpenSim.Region.Framework.Scenes | |||
2980 | { | 4151 | { |
2981 | RootPart.UpdatePermissions(AgentID, field, localID, mask, addRemTF); | 4152 | RootPart.UpdatePermissions(AgentID, field, localID, mask, addRemTF); |
2982 | 4153 | ||
2983 | AdjustChildPrimPermissions(Scene.Permissions.IsGod(AgentID)); | 4154 | bool god = Scene.Permissions.IsGod(AgentID); |
4155 | |||
4156 | if (field == 1 && god) | ||
4157 | { | ||
4158 | ForEachPart(part => | ||
4159 | { | ||
4160 | part.BaseMask = RootPart.BaseMask; | ||
4161 | }); | ||
4162 | } | ||
4163 | |||
4164 | AdjustChildPrimPermissions(false); | ||
4165 | |||
4166 | if (field == 1 && god) // Base mask was set. Update all child part inventories | ||
4167 | { | ||
4168 | foreach (SceneObjectPart part in Parts) | ||
4169 | part.Inventory.ApplyGodPermissions(RootPart.BaseMask); | ||
4170 | InvalidateEffectivePerms(); | ||
4171 | } | ||
2984 | 4172 | ||
2985 | HasGroupChanged = true; | 4173 | HasGroupChanged = true; |
2986 | 4174 | ||
@@ -3010,6 +4198,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3010 | if (pa != null) | 4198 | if (pa != null) |
3011 | m_scene.PhysicsScene.AddPhysicsActorTaint(pa); | 4199 | m_scene.PhysicsScene.AddPhysicsActorTaint(pa); |
3012 | } | 4200 | } |
4201 | InvalidBoundsRadius(); | ||
3013 | } | 4202 | } |
3014 | 4203 | ||
3015 | #endregion | 4204 | #endregion |
@@ -3025,163 +4214,101 @@ namespace OpenSim.Region.Framework.Scenes | |||
3025 | // m_log.DebugFormat( | 4214 | // m_log.DebugFormat( |
3026 | // "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale); | 4215 | // "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale); |
3027 | 4216 | ||
4217 | if (Scene == null) | ||
4218 | return; | ||
4219 | |||
3028 | PhysicsActor pa = m_rootPart.PhysActor; | 4220 | PhysicsActor pa = m_rootPart.PhysActor; |
3029 | 4221 | ||
3030 | RootPart.StoreUndoState(true); | 4222 | float minsize = Scene.m_minNonphys; |
4223 | float maxsize = Scene.m_maxNonphys; | ||
3031 | 4224 | ||
3032 | if (Scene != null) | 4225 | if (pa != null && pa.IsPhysical) |
3033 | { | 4226 | { |
3034 | scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X)); | 4227 | minsize = Scene.m_minPhys; |
3035 | scale.Y = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.Y)); | 4228 | maxsize = Scene.m_maxPhys; |
3036 | scale.Z = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.Z)); | ||
3037 | |||
3038 | if (pa != null && pa.IsPhysical) | ||
3039 | { | ||
3040 | scale.X = Math.Max(Scene.m_minPhys, Math.Min(Scene.m_maxPhys, scale.X)); | ||
3041 | scale.Y = Math.Max(Scene.m_minPhys, Math.Min(Scene.m_maxPhys, scale.Y)); | ||
3042 | scale.Z = Math.Max(Scene.m_minPhys, Math.Min(Scene.m_maxPhys, scale.Z)); | ||
3043 | } | ||
3044 | } | 4229 | } |
3045 | 4230 | ||
4231 | scale.X = Util.Clamp(scale.X, minsize, maxsize); | ||
4232 | scale.Y = Util.Clamp(scale.Y, minsize, maxsize); | ||
4233 | scale.Z = Util.Clamp(scale.Z, minsize, maxsize); | ||
4234 | |||
4235 | // requested scaling factors | ||
3046 | float x = (scale.X / RootPart.Scale.X); | 4236 | float x = (scale.X / RootPart.Scale.X); |
3047 | float y = (scale.Y / RootPart.Scale.Y); | 4237 | float y = (scale.Y / RootPart.Scale.Y); |
3048 | float z = (scale.Z / RootPart.Scale.Z); | 4238 | float z = (scale.Z / RootPart.Scale.Z); |
3049 | 4239 | ||
3050 | SceneObjectPart[] parts = m_parts.GetArray(); | 4240 | SceneObjectPart[] parts = m_parts.GetArray(); |
3051 | 4241 | ||
3052 | if (Scene != null & (x > 1.0f || y > 1.0f || z > 1.0f)) | 4242 | // fix scaling factors so parts don't violate dimensions |
4243 | for(int i = 0;i < parts.Length;i++) | ||
3053 | { | 4244 | { |
3054 | for (int i = 0; i < parts.Length; i++) | 4245 | SceneObjectPart obPart = parts[i]; |
4246 | if(obPart.UUID != m_rootPart.UUID) | ||
3055 | { | 4247 | { |
3056 | SceneObjectPart obPart = parts[i]; | 4248 | Vector3 oldSize = new Vector3(obPart.Scale); |
3057 | if (obPart.UUID != m_rootPart.UUID) | ||
3058 | { | ||
3059 | // obPart.IgnoreUndoUpdate = true; | ||
3060 | Vector3 oldSize = new Vector3(obPart.Scale); | ||
3061 | 4249 | ||
3062 | float f = 1.0f; | 4250 | float f = 1.0f; |
3063 | float a = 1.0f; | 4251 | float a = 1.0f; |
3064 | |||
3065 | if (pa != null && pa.IsPhysical) | ||
3066 | { | ||
3067 | if (oldSize.X * x > Scene.m_maxPhys) | ||
3068 | { | ||
3069 | f = m_scene.m_maxPhys / oldSize.X; | ||
3070 | a = f / x; | ||
3071 | x *= a; | ||
3072 | y *= a; | ||
3073 | z *= a; | ||
3074 | } | ||
3075 | else if (oldSize.X * x < Scene.m_minPhys) | ||
3076 | { | ||
3077 | f = m_scene.m_minPhys / oldSize.X; | ||
3078 | a = f / x; | ||
3079 | x *= a; | ||
3080 | y *= a; | ||
3081 | z *= a; | ||
3082 | } | ||
3083 | 4252 | ||
3084 | if (oldSize.Y * y > Scene.m_maxPhys) | 4253 | if(oldSize.X * x > maxsize) |
3085 | { | 4254 | { |
3086 | f = m_scene.m_maxPhys / oldSize.Y; | 4255 | f = maxsize / oldSize.X; |
3087 | a = f / y; | 4256 | a = f / x; |
3088 | x *= a; | 4257 | x *= a; |
3089 | y *= a; | 4258 | y *= a; |
3090 | z *= a; | 4259 | z *= a; |
3091 | } | 4260 | } |
3092 | else if (oldSize.Y * y < Scene.m_minPhys) | 4261 | else if(oldSize.X * x < minsize) |
3093 | { | 4262 | { |
3094 | f = m_scene.m_minPhys / oldSize.Y; | 4263 | f = minsize / oldSize.X; |
3095 | a = f / y; | 4264 | a = f / x; |
3096 | x *= a; | 4265 | x *= a; |
3097 | y *= a; | 4266 | y *= a; |
3098 | z *= a; | 4267 | z *= a; |
3099 | } | 4268 | } |
3100 | |||
3101 | if (oldSize.Z * z > Scene.m_maxPhys) | ||
3102 | { | ||
3103 | f = m_scene.m_maxPhys / oldSize.Z; | ||
3104 | a = f / z; | ||
3105 | x *= a; | ||
3106 | y *= a; | ||
3107 | z *= a; | ||
3108 | } | ||
3109 | else if (oldSize.Z * z < Scene.m_minPhys) | ||
3110 | { | ||
3111 | f = m_scene.m_minPhys / oldSize.Z; | ||
3112 | a = f / z; | ||
3113 | x *= a; | ||
3114 | y *= a; | ||
3115 | z *= a; | ||
3116 | } | ||
3117 | } | ||
3118 | else | ||
3119 | { | ||
3120 | if (oldSize.X * x > Scene.m_maxNonphys) | ||
3121 | { | ||
3122 | f = m_scene.m_maxNonphys / oldSize.X; | ||
3123 | a = f / x; | ||
3124 | x *= a; | ||
3125 | y *= a; | ||
3126 | z *= a; | ||
3127 | } | ||
3128 | else if (oldSize.X * x < Scene.m_minNonphys) | ||
3129 | { | ||
3130 | f = m_scene.m_minNonphys / oldSize.X; | ||
3131 | a = f / x; | ||
3132 | x *= a; | ||
3133 | y *= a; | ||
3134 | z *= a; | ||
3135 | } | ||
3136 | |||
3137 | if (oldSize.Y * y > Scene.m_maxNonphys) | ||
3138 | { | ||
3139 | f = m_scene.m_maxNonphys / oldSize.Y; | ||
3140 | a = f / y; | ||
3141 | x *= a; | ||
3142 | y *= a; | ||
3143 | z *= a; | ||
3144 | } | ||
3145 | else if (oldSize.Y * y < Scene.m_minNonphys) | ||
3146 | { | ||
3147 | f = m_scene.m_minNonphys / oldSize.Y; | ||
3148 | a = f / y; | ||
3149 | x *= a; | ||
3150 | y *= a; | ||
3151 | z *= a; | ||
3152 | } | ||
3153 | 4269 | ||
3154 | if (oldSize.Z * z > Scene.m_maxNonphys) | 4270 | if(oldSize.Y * y > maxsize) |
3155 | { | 4271 | { |
3156 | f = m_scene.m_maxNonphys / oldSize.Z; | 4272 | f = maxsize / oldSize.Y; |
3157 | a = f / z; | 4273 | a = f / y; |
3158 | x *= a; | 4274 | x *= a; |
3159 | y *= a; | 4275 | y *= a; |
3160 | z *= a; | 4276 | z *= a; |
3161 | } | 4277 | } |
3162 | else if (oldSize.Z * z < Scene.m_minNonphys) | 4278 | else if(oldSize.Y * y < minsize) |
3163 | { | 4279 | { |
3164 | f = m_scene.m_minNonphys / oldSize.Z; | 4280 | f = minsize / oldSize.Y; |
3165 | a = f / z; | 4281 | a = f / y; |
3166 | x *= a; | 4282 | x *= a; |
3167 | y *= a; | 4283 | y *= a; |
3168 | z *= a; | 4284 | z *= a; |
3169 | } | 4285 | } |
3170 | } | ||
3171 | 4286 | ||
3172 | // obPart.IgnoreUndoUpdate = false; | 4287 | if(oldSize.Z * z > maxsize) |
4288 | { | ||
4289 | f = maxsize / oldSize.Z; | ||
4290 | a = f / z; | ||
4291 | x *= a; | ||
4292 | y *= a; | ||
4293 | z *= a; | ||
4294 | } | ||
4295 | else if(oldSize.Z * z < minsize) | ||
4296 | { | ||
4297 | f = minsize / oldSize.Z; | ||
4298 | a = f / z; | ||
4299 | x *= a; | ||
4300 | y *= a; | ||
4301 | z *= a; | ||
3173 | } | 4302 | } |
3174 | } | 4303 | } |
3175 | } | 4304 | } |
3176 | 4305 | ||
3177 | Vector3 prevScale = RootPart.Scale; | 4306 | Vector3 rootScale = RootPart.Scale; |
3178 | prevScale.X *= x; | 4307 | rootScale.X *= x; |
3179 | prevScale.Y *= y; | 4308 | rootScale.Y *= y; |
3180 | prevScale.Z *= z; | 4309 | rootScale.Z *= z; |
3181 | 4310 | ||
3182 | // RootPart.IgnoreUndoUpdate = true; | 4311 | RootPart.Scale = rootScale; |
3183 | RootPart.Resize(prevScale); | ||
3184 | // RootPart.IgnoreUndoUpdate = false; | ||
3185 | 4312 | ||
3186 | for (int i = 0; i < parts.Length; i++) | 4313 | for (int i = 0; i < parts.Length; i++) |
3187 | { | 4314 | { |
@@ -3189,8 +4316,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
3189 | 4316 | ||
3190 | if (obPart.UUID != m_rootPart.UUID) | 4317 | if (obPart.UUID != m_rootPart.UUID) |
3191 | { | 4318 | { |
3192 | obPart.IgnoreUndoUpdate = true; | ||
3193 | |||
3194 | Vector3 currentpos = new Vector3(obPart.OffsetPosition); | 4319 | Vector3 currentpos = new Vector3(obPart.OffsetPosition); |
3195 | currentpos.X *= x; | 4320 | currentpos.X *= x; |
3196 | currentpos.Y *= y; | 4321 | currentpos.Y *= y; |
@@ -3201,18 +4326,190 @@ namespace OpenSim.Region.Framework.Scenes | |||
3201 | newSize.Y *= y; | 4326 | newSize.Y *= y; |
3202 | newSize.Z *= z; | 4327 | newSize.Z *= z; |
3203 | 4328 | ||
3204 | obPart.Resize(newSize); | 4329 | obPart.Scale = newSize; |
3205 | obPart.UpdateOffSet(currentpos); | 4330 | obPart.UpdateOffSet(currentpos); |
4331 | } | ||
4332 | } | ||
4333 | |||
4334 | InvalidBoundsRadius(); | ||
4335 | HasGroupChanged = true; | ||
4336 | m_rootPart.TriggerScriptChangedEvent(Changed.SCALE); | ||
4337 | ScheduleGroupForFullUpdate(); | ||
4338 | |||
4339 | } | ||
4340 | |||
4341 | public bool GroupResize(double fscale) | ||
4342 | { | ||
4343 | // m_log.DebugFormat( | ||
4344 | // "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, fscale); | ||
4345 | |||
4346 | if (Scene == null || IsDeleted || inTransit || fscale < 0) | ||
4347 | return false; | ||
4348 | |||
4349 | // ignore lsl restrictions. let them be done a LSL | ||
4350 | PhysicsActor pa = m_rootPart.PhysActor; | ||
4351 | |||
4352 | if(RootPart.KeyframeMotion != null) | ||
4353 | RootPart.KeyframeMotion.Suspend(); | ||
4354 | |||
4355 | float minsize = Scene.m_minNonphys; | ||
4356 | float maxsize = Scene.m_maxNonphys; | ||
3206 | 4357 | ||
3207 | obPart.IgnoreUndoUpdate = false; | 4358 | // assuming physics is more restrictive |
4359 | if (pa != null && pa.IsPhysical) | ||
4360 | { | ||
4361 | minsize = Scene.m_minPhys; | ||
4362 | maxsize = Scene.m_maxPhys; | ||
4363 | } | ||
4364 | |||
4365 | SceneObjectPart[] parts = m_parts.GetArray(); | ||
4366 | float tmp; | ||
4367 | // check scaling factor so parts don't violate dimensions | ||
4368 | for(int i = 0; i < parts.Length; i++) | ||
4369 | { | ||
4370 | SceneObjectPart obPart = parts[i]; | ||
4371 | Vector3 oldSize = new Vector3(obPart.Scale); | ||
4372 | tmp = (float)(oldSize.X * fscale); | ||
4373 | if(tmp > maxsize) | ||
4374 | return false; | ||
4375 | if(tmp < minsize) | ||
4376 | return false; | ||
4377 | |||
4378 | tmp = (float)(oldSize.Y * fscale); | ||
4379 | if(tmp > maxsize) | ||
4380 | return false; | ||
4381 | if(tmp < minsize) | ||
4382 | return false; | ||
4383 | |||
4384 | tmp = (float)(oldSize.Z * fscale); | ||
4385 | if(tmp > maxsize) | ||
4386 | return false; | ||
4387 | if(tmp < minsize) | ||
4388 | return false; | ||
4389 | } | ||
4390 | |||
4391 | Vector3 newSize = RootPart.Scale; | ||
4392 | newSize.X = (float)(newSize.X * fscale); | ||
4393 | newSize.Y = (float)(newSize.Y * fscale); | ||
4394 | newSize.Z = (float)(newSize.Z * fscale); | ||
4395 | |||
4396 | if(pa != null) | ||
4397 | pa.Building = true; | ||
4398 | |||
4399 | RootPart.Scale = newSize; | ||
4400 | |||
4401 | Vector3 currentpos; | ||
4402 | for (int i = 0; i < parts.Length; i++) | ||
4403 | { | ||
4404 | SceneObjectPart obPart = parts[i]; | ||
4405 | |||
4406 | if (obPart.UUID != m_rootPart.UUID) | ||
4407 | { | ||
4408 | currentpos = obPart.OffsetPosition; | ||
4409 | currentpos.X = (float)(currentpos.X * fscale); | ||
4410 | currentpos.Y = (float)(currentpos.Y * fscale); | ||
4411 | currentpos.Z = (float)(currentpos.Z * fscale); | ||
4412 | |||
4413 | newSize = obPart.Scale; | ||
4414 | newSize.X = (float)(newSize.X * fscale); | ||
4415 | newSize.Y = (float)(newSize.Y * fscale); | ||
4416 | newSize.Z = (float)(newSize.Z * fscale); | ||
4417 | |||
4418 | obPart.Scale = newSize; | ||
4419 | obPart.UpdateOffSet(currentpos); | ||
3208 | } | 4420 | } |
4421 | } | ||
4422 | |||
4423 | if(pa != null) | ||
4424 | pa.Building = false; | ||
4425 | |||
4426 | InvalidBoundsRadius(); | ||
4427 | |||
4428 | HasGroupChanged = true; | ||
4429 | m_rootPart.TriggerScriptChangedEvent(Changed.SCALE); | ||
4430 | ScheduleGroupForFullUpdate(); | ||
4431 | |||
4432 | if(RootPart.KeyframeMotion != null) | ||
4433 | RootPart.KeyframeMotion.Resume(); | ||
4434 | |||
4435 | return true; | ||
4436 | } | ||
4437 | |||
4438 | public float GetMaxGroupResizeScale() | ||
4439 | { | ||
4440 | if (Scene == null || IsDeleted || inTransit) | ||
4441 | return 1.0f; | ||
4442 | |||
4443 | float maxsize = Scene.m_maxNonphys; | ||
4444 | PhysicsActor pa = m_rootPart.PhysActor; | ||
4445 | // assuming physics is more restrictive | ||
4446 | if (pa != null && pa.IsPhysical) | ||
4447 | maxsize = Scene.m_maxPhys; | ||
3209 | 4448 | ||
3210 | // obPart.IgnoreUndoUpdate = false; | 4449 | SceneObjectPart[] parts = m_parts.GetArray(); |
3211 | // obPart.StoreUndoState(); | 4450 | float larger = float.MinValue; |
4451 | |||
4452 | for(int i = 0; i < parts.Length; i++) | ||
4453 | { | ||
4454 | SceneObjectPart obPart = parts[i]; | ||
4455 | Vector3 oldSize = new Vector3(obPart.Scale); | ||
4456 | if(larger < oldSize.X) | ||
4457 | larger = oldSize.X; | ||
4458 | |||
4459 | if(larger < oldSize.Y) | ||
4460 | larger = oldSize.Y; | ||
4461 | |||
4462 | if(larger < oldSize.Z) | ||
4463 | larger = oldSize.Z; | ||
3212 | } | 4464 | } |
3213 | 4465 | ||
3214 | // m_log.DebugFormat( | 4466 | if(larger >= maxsize) |
3215 | // "[SCENE OBJECT GROUP]: Finished group resizing {0} {1} to {2}", Name, LocalId, RootPart.Scale); | 4467 | return 1.0f; |
4468 | |||
4469 | larger += 1e-3f; | ||
4470 | float fscale = maxsize / larger; | ||
4471 | |||
4472 | return fscale; | ||
4473 | } | ||
4474 | |||
4475 | public float GetMinGroupResizeScale() | ||
4476 | { | ||
4477 | if (Scene == null || IsDeleted || inTransit) | ||
4478 | return 1.0f; | ||
4479 | |||
4480 | float minsize = Scene.m_minNonphys; | ||
4481 | PhysicsActor pa = m_rootPart.PhysActor; | ||
4482 | // assuming physics is more restrictive | ||
4483 | if (pa != null && pa.IsPhysical) | ||
4484 | minsize = Scene.m_minPhys; | ||
4485 | |||
4486 | SceneObjectPart[] parts = m_parts.GetArray(); | ||
4487 | float smaller = float.MaxValue; | ||
4488 | |||
4489 | for(int i = 0; i < parts.Length; i++) | ||
4490 | { | ||
4491 | SceneObjectPart obPart = parts[i]; | ||
4492 | Vector3 oldSize = new Vector3(obPart.Scale); | ||
4493 | if(smaller > oldSize.X) | ||
4494 | smaller = oldSize.X; | ||
4495 | |||
4496 | if(smaller > oldSize.Y) | ||
4497 | smaller = oldSize.Y; | ||
4498 | |||
4499 | if(smaller > oldSize.Z) | ||
4500 | smaller = oldSize.Z; | ||
4501 | } | ||
4502 | |||
4503 | if(smaller <= minsize) | ||
4504 | return 1.0f; | ||
4505 | |||
4506 | if(smaller > 2e-3f) | ||
4507 | smaller -= 1e-3f; | ||
4508 | float fscale = minsize / smaller; | ||
4509 | if(fscale < 1e-8f) | ||
4510 | fscale = 1e-8f; | ||
4511 | |||
4512 | return fscale; | ||
3216 | } | 4513 | } |
3217 | 4514 | ||
3218 | #endregion | 4515 | #endregion |
@@ -3225,14 +4522,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
3225 | /// <param name="pos"></param> | 4522 | /// <param name="pos"></param> |
3226 | public void UpdateGroupPosition(Vector3 pos) | 4523 | public void UpdateGroupPosition(Vector3 pos) |
3227 | { | 4524 | { |
3228 | // m_log.DebugFormat("[SCENE OBJECT GROUP]: Updating group position on {0} {1} to {2}", Name, LocalId, pos); | ||
3229 | |||
3230 | RootPart.StoreUndoState(true); | ||
3231 | |||
3232 | // SceneObjectPart[] parts = m_parts.GetArray(); | ||
3233 | // for (int i = 0; i < parts.Length; i++) | ||
3234 | // parts[i].StoreUndoState(); | ||
3235 | |||
3236 | if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) | 4525 | if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) |
3237 | { | 4526 | { |
3238 | if (IsAttachment) | 4527 | if (IsAttachment) |
@@ -3265,21 +4554,17 @@ namespace OpenSim.Region.Framework.Scenes | |||
3265 | /// </summary> | 4554 | /// </summary> |
3266 | /// <param name="pos"></param> | 4555 | /// <param name="pos"></param> |
3267 | /// <param name="localID"></param> | 4556 | /// <param name="localID"></param> |
4557 | /// | ||
4558 | |||
3268 | public void UpdateSinglePosition(Vector3 pos, uint localID) | 4559 | public void UpdateSinglePosition(Vector3 pos, uint localID) |
3269 | { | 4560 | { |
3270 | SceneObjectPart part = GetPart(localID); | 4561 | SceneObjectPart part = GetPart(localID); |
3271 | 4562 | ||
3272 | // SceneObjectPart[] parts = m_parts.GetArray(); | ||
3273 | // for (int i = 0; i < parts.Length; i++) | ||
3274 | // parts[i].StoreUndoState(); | ||
3275 | |||
3276 | if (part != null) | 4563 | if (part != null) |
3277 | { | 4564 | { |
3278 | // m_log.DebugFormat( | 4565 | // unlock parts position change |
3279 | // "[SCENE OBJECT GROUP]: Updating single position of {0} {1} to {2}", part.Name, part.LocalId, pos); | 4566 | if (m_rootPart.PhysActor != null) |
3280 | 4567 | m_rootPart.PhysActor.Building = true; | |
3281 | part.StoreUndoState(false); | ||
3282 | part.IgnoreUndoUpdate = true; | ||
3283 | 4568 | ||
3284 | if (part.UUID == m_rootPart.UUID) | 4569 | if (part.UUID == m_rootPart.UUID) |
3285 | { | 4570 | { |
@@ -3290,8 +4575,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
3290 | part.UpdateOffSet(pos); | 4575 | part.UpdateOffSet(pos); |
3291 | } | 4576 | } |
3292 | 4577 | ||
4578 | if (m_rootPart.PhysActor != null) | ||
4579 | m_rootPart.PhysActor.Building = false; | ||
4580 | |||
3293 | HasGroupChanged = true; | 4581 | HasGroupChanged = true; |
3294 | part.IgnoreUndoUpdate = false; | ||
3295 | } | 4582 | } |
3296 | } | 4583 | } |
3297 | 4584 | ||
@@ -3301,13 +4588,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3301 | /// <param name="newPos"></param> | 4588 | /// <param name="newPos"></param> |
3302 | public void UpdateRootPosition(Vector3 newPos) | 4589 | public void UpdateRootPosition(Vector3 newPos) |
3303 | { | 4590 | { |
3304 | // m_log.DebugFormat( | 4591 | // needs to be called with phys building true |
3305 | // "[SCENE OBJECT GROUP]: Updating root position of {0} {1} to {2}", Name, LocalId, pos); | ||
3306 | |||
3307 | // SceneObjectPart[] parts = m_parts.GetArray(); | ||
3308 | // for (int i = 0; i < parts.Length; i++) | ||
3309 | // parts[i].StoreUndoState(); | ||
3310 | |||
3311 | Vector3 oldPos; | 4592 | Vector3 oldPos; |
3312 | 4593 | ||
3313 | if (IsAttachment) | 4594 | if (IsAttachment) |
@@ -3328,12 +4609,19 @@ namespace OpenSim.Region.Framework.Scenes | |||
3328 | } | 4609 | } |
3329 | 4610 | ||
3330 | AbsolutePosition = newPos; | 4611 | AbsolutePosition = newPos; |
3331 | 4612 | ||
3332 | if (IsAttachment) | 4613 | if (IsAttachment) |
3333 | m_rootPart.AttachedPos = newPos; | 4614 | m_rootPart.AttachedPos = newPos; |
3334 | 4615 | ||
3335 | HasGroupChanged = true; | 4616 | HasGroupChanged = true; |
3336 | ScheduleGroupForTerseUpdate(); | 4617 | if (m_rootPart.Undoing) |
4618 | { | ||
4619 | ScheduleGroupForFullUpdate(); | ||
4620 | } | ||
4621 | else | ||
4622 | { | ||
4623 | ScheduleGroupForTerseUpdate(); | ||
4624 | } | ||
3337 | } | 4625 | } |
3338 | 4626 | ||
3339 | #endregion | 4627 | #endregion |
@@ -3346,24 +4634,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
3346 | /// <param name="rot"></param> | 4634 | /// <param name="rot"></param> |
3347 | public void UpdateGroupRotationR(Quaternion rot) | 4635 | public void UpdateGroupRotationR(Quaternion rot) |
3348 | { | 4636 | { |
3349 | // m_log.DebugFormat( | ||
3350 | // "[SCENE OBJECT GROUP]: Updating group rotation R of {0} {1} to {2}", Name, LocalId, rot); | ||
3351 | |||
3352 | // SceneObjectPart[] parts = m_parts.GetArray(); | ||
3353 | // for (int i = 0; i < parts.Length; i++) | ||
3354 | // parts[i].StoreUndoState(); | ||
3355 | |||
3356 | m_rootPart.StoreUndoState(true); | ||
3357 | |||
3358 | m_rootPart.UpdateRotation(rot); | 4637 | m_rootPart.UpdateRotation(rot); |
3359 | 4638 | ||
4639 | /* this is done by rootpart RotationOffset set called by UpdateRotation | ||
3360 | PhysicsActor actor = m_rootPart.PhysActor; | 4640 | PhysicsActor actor = m_rootPart.PhysActor; |
3361 | if (actor != null) | 4641 | if (actor != null) |
3362 | { | 4642 | { |
3363 | actor.Orientation = m_rootPart.RotationOffset; | 4643 | actor.Orientation = m_rootPart.RotationOffset; |
3364 | m_scene.PhysicsScene.AddPhysicsActorTaint(actor); | 4644 | m_scene.PhysicsScene.AddPhysicsActorTaint(actor); |
3365 | } | 4645 | } |
3366 | 4646 | */ | |
3367 | HasGroupChanged = true; | 4647 | HasGroupChanged = true; |
3368 | ScheduleGroupForTerseUpdate(); | 4648 | ScheduleGroupForTerseUpdate(); |
3369 | } | 4649 | } |
@@ -3375,16 +4655,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
3375 | /// <param name="rot"></param> | 4655 | /// <param name="rot"></param> |
3376 | public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) | 4656 | public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) |
3377 | { | 4657 | { |
3378 | // m_log.DebugFormat( | ||
3379 | // "[SCENE OBJECT GROUP]: Updating group rotation PR of {0} {1} to {2}", Name, LocalId, rot); | ||
3380 | |||
3381 | // SceneObjectPart[] parts = m_parts.GetArray(); | ||
3382 | // for (int i = 0; i < parts.Length; i++) | ||
3383 | // parts[i].StoreUndoState(); | ||
3384 | |||
3385 | RootPart.StoreUndoState(true); | ||
3386 | RootPart.IgnoreUndoUpdate = true; | ||
3387 | |||
3388 | m_rootPart.UpdateRotation(rot); | 4658 | m_rootPart.UpdateRotation(rot); |
3389 | 4659 | ||
3390 | PhysicsActor actor = m_rootPart.PhysActor; | 4660 | PhysicsActor actor = m_rootPart.PhysActor; |
@@ -3403,8 +4673,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
3403 | 4673 | ||
3404 | HasGroupChanged = true; | 4674 | HasGroupChanged = true; |
3405 | ScheduleGroupForTerseUpdate(); | 4675 | ScheduleGroupForTerseUpdate(); |
3406 | |||
3407 | RootPart.IgnoreUndoUpdate = false; | ||
3408 | } | 4676 | } |
3409 | 4677 | ||
3410 | /// <summary> | 4678 | /// <summary> |
@@ -3417,13 +4685,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
3417 | SceneObjectPart part = GetPart(localID); | 4685 | SceneObjectPart part = GetPart(localID); |
3418 | 4686 | ||
3419 | SceneObjectPart[] parts = m_parts.GetArray(); | 4687 | SceneObjectPart[] parts = m_parts.GetArray(); |
3420 | for (int i = 0; i < parts.Length; i++) | ||
3421 | parts[i].StoreUndoState(); | ||
3422 | 4688 | ||
3423 | if (part != null) | 4689 | if (part != null) |
3424 | { | 4690 | { |
3425 | // m_log.DebugFormat( | 4691 | if (m_rootPart.PhysActor != null) |
3426 | // "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot); | 4692 | m_rootPart.PhysActor.Building = true; |
3427 | 4693 | ||
3428 | if (part.UUID == m_rootPart.UUID) | 4694 | if (part.UUID == m_rootPart.UUID) |
3429 | { | 4695 | { |
@@ -3433,6 +4699,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
3433 | { | 4699 | { |
3434 | part.UpdateRotation(rot); | 4700 | part.UpdateRotation(rot); |
3435 | } | 4701 | } |
4702 | |||
4703 | if (m_rootPart.PhysActor != null) | ||
4704 | m_rootPart.PhysActor.Building = false; | ||
3436 | } | 4705 | } |
3437 | } | 4706 | } |
3438 | 4707 | ||
@@ -3446,12 +4715,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
3446 | SceneObjectPart part = GetPart(localID); | 4715 | SceneObjectPart part = GetPart(localID); |
3447 | if (part != null) | 4716 | if (part != null) |
3448 | { | 4717 | { |
3449 | // m_log.DebugFormat( | 4718 | if (m_rootPart.PhysActor != null) |
3450 | // "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}", | 4719 | m_rootPart.PhysActor.Building = true; |
3451 | // part.Name, part.LocalId, rot); | ||
3452 | |||
3453 | part.StoreUndoState(); | ||
3454 | part.IgnoreUndoUpdate = true; | ||
3455 | 4720 | ||
3456 | if (part.UUID == m_rootPart.UUID) | 4721 | if (part.UUID == m_rootPart.UUID) |
3457 | { | 4722 | { |
@@ -3464,7 +4729,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
3464 | part.OffsetPosition = pos; | 4729 | part.OffsetPosition = pos; |
3465 | } | 4730 | } |
3466 | 4731 | ||
3467 | part.IgnoreUndoUpdate = false; | 4732 | if (m_rootPart.PhysActor != null) |
4733 | m_rootPart.PhysActor.Building = false; | ||
3468 | } | 4734 | } |
3469 | } | 4735 | } |
3470 | 4736 | ||
@@ -3474,15 +4740,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
3474 | /// <param name="rot"></param> | 4740 | /// <param name="rot"></param> |
3475 | public void UpdateRootRotation(Quaternion rot) | 4741 | public void UpdateRootRotation(Quaternion rot) |
3476 | { | 4742 | { |
3477 | // m_log.DebugFormat( | 4743 | // needs to be called with phys building true |
3478 | // "[SCENE OBJECT GROUP]: Updating root rotation of {0} {1} to {2}", | ||
3479 | // Name, LocalId, rot); | ||
3480 | |||
3481 | Quaternion axRot = rot; | 4744 | Quaternion axRot = rot; |
3482 | Quaternion oldParentRot = m_rootPart.RotationOffset; | 4745 | Quaternion oldParentRot = m_rootPart.RotationOffset; |
3483 | 4746 | ||
3484 | m_rootPart.StoreUndoState(); | 4747 | //Don't use UpdateRotation because it schedules an update prematurely |
3485 | m_rootPart.UpdateRotation(rot); | 4748 | m_rootPart.RotationOffset = rot; |
3486 | 4749 | ||
3487 | PhysicsActor pa = m_rootPart.PhysActor; | 4750 | PhysicsActor pa = m_rootPart.PhysActor; |
3488 | 4751 | ||
@@ -3498,64 +4761,203 @@ namespace OpenSim.Region.Framework.Scenes | |||
3498 | SceneObjectPart prim = parts[i]; | 4761 | SceneObjectPart prim = parts[i]; |
3499 | if (prim.UUID != m_rootPart.UUID) | 4762 | if (prim.UUID != m_rootPart.UUID) |
3500 | { | 4763 | { |
3501 | prim.IgnoreUndoUpdate = true; | 4764 | Quaternion NewRot = oldParentRot * prim.RotationOffset; |
4765 | NewRot = Quaternion.Inverse(axRot) * NewRot; | ||
4766 | prim.RotationOffset = NewRot; | ||
4767 | |||
3502 | Vector3 axPos = prim.OffsetPosition; | 4768 | Vector3 axPos = prim.OffsetPosition; |
4769 | |||
3503 | axPos *= oldParentRot; | 4770 | axPos *= oldParentRot; |
3504 | axPos *= Quaternion.Inverse(axRot); | 4771 | axPos *= Quaternion.Inverse(axRot); |
3505 | prim.OffsetPosition = axPos; | 4772 | prim.OffsetPosition = axPos; |
3506 | Quaternion primsRot = prim.RotationOffset; | ||
3507 | Quaternion newRot = oldParentRot * primsRot; | ||
3508 | newRot = Quaternion.Inverse(axRot) * newRot; | ||
3509 | prim.RotationOffset = newRot; | ||
3510 | prim.ScheduleTerseUpdate(); | ||
3511 | prim.IgnoreUndoUpdate = false; | ||
3512 | } | 4773 | } |
3513 | } | 4774 | } |
3514 | 4775 | ||
3515 | // for (int i = 0; i < parts.Length; i++) | 4776 | HasGroupChanged = true; |
3516 | // { | 4777 | ScheduleGroupForFullUpdate(); |
3517 | // SceneObjectPart childpart = parts[i]; | 4778 | } |
3518 | // if (childpart != m_rootPart) | ||
3519 | // { | ||
3520 | //// childpart.IgnoreUndoUpdate = false; | ||
3521 | //// childpart.StoreUndoState(); | ||
3522 | // } | ||
3523 | // } | ||
3524 | 4779 | ||
3525 | m_rootPart.ScheduleTerseUpdate(); | 4780 | private enum updatetype :int |
4781 | { | ||
4782 | none = 0, | ||
4783 | partterse = 1, | ||
4784 | partfull = 2, | ||
4785 | groupterse = 3, | ||
4786 | groupfull = 4 | ||
4787 | } | ||
3526 | 4788 | ||
3527 | // m_log.DebugFormat( | 4789 | public void doChangeObject(SceneObjectPart part, ObjectChangeData data) |
3528 | // "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", | 4790 | { |
3529 | // Name, LocalId, rot); | 4791 | // TODO this still as excessive *.Schedule*Update()s |
4792 | |||
4793 | if (part != null && part.ParentGroup != null) | ||
4794 | { | ||
4795 | ObjectChangeType change = data.change; | ||
4796 | bool togroup = ((change & ObjectChangeType.Group) != 0); | ||
4797 | // bool uniform = ((what & ObjectChangeType.UniformScale) != 0); not in use | ||
4798 | |||
4799 | SceneObjectGroup group = part.ParentGroup; | ||
4800 | PhysicsActor pha = group.RootPart.PhysActor; | ||
4801 | |||
4802 | updatetype updateType = updatetype.none; | ||
4803 | |||
4804 | if (togroup) | ||
4805 | { | ||
4806 | // related to group | ||
4807 | if ((change & (ObjectChangeType.Rotation | ObjectChangeType.Position)) != 0) | ||
4808 | { | ||
4809 | if ((change & ObjectChangeType.Rotation) != 0) | ||
4810 | { | ||
4811 | group.RootPart.UpdateRotation(data.rotation); | ||
4812 | updateType = updatetype.none; | ||
4813 | } | ||
4814 | if ((change & ObjectChangeType.Position) != 0) | ||
4815 | { | ||
4816 | if (IsAttachment || m_scene.Permissions.CanObjectEntry(group, false, data.position)) | ||
4817 | UpdateGroupPosition(data.position); | ||
4818 | updateType = updatetype.groupterse; | ||
4819 | } | ||
4820 | else | ||
4821 | // ugly rotation update of all parts | ||
4822 | { | ||
4823 | group.ResetChildPrimPhysicsPositions(); | ||
4824 | } | ||
4825 | |||
4826 | } | ||
4827 | if ((change & ObjectChangeType.Scale) != 0) | ||
4828 | { | ||
4829 | if (pha != null) | ||
4830 | pha.Building = true; | ||
4831 | |||
4832 | group.GroupResize(data.scale); | ||
4833 | updateType = updatetype.none; | ||
4834 | |||
4835 | if (pha != null) | ||
4836 | pha.Building = false; | ||
4837 | } | ||
4838 | } | ||
4839 | else | ||
4840 | { | ||
4841 | // related to single prim in a link-set ( ie group) | ||
4842 | if (pha != null) | ||
4843 | pha.Building = true; | ||
4844 | |||
4845 | // root part is special | ||
4846 | // parts offset positions or rotations need to change also | ||
4847 | |||
4848 | if (part == group.RootPart) | ||
4849 | { | ||
4850 | if ((change & ObjectChangeType.Rotation) != 0) | ||
4851 | group.UpdateRootRotation(data.rotation); | ||
4852 | if ((change & ObjectChangeType.Position) != 0) | ||
4853 | group.UpdateRootPosition(data.position); | ||
4854 | if ((change & ObjectChangeType.Scale) != 0) | ||
4855 | part.Resize(data.scale); | ||
4856 | } | ||
4857 | else | ||
4858 | { | ||
4859 | if ((change & ObjectChangeType.Position) != 0) | ||
4860 | { | ||
4861 | part.OffsetPosition = data.position; | ||
4862 | updateType = updatetype.partterse; | ||
4863 | } | ||
4864 | if ((change & ObjectChangeType.Rotation) != 0) | ||
4865 | { | ||
4866 | part.UpdateRotation(data.rotation); | ||
4867 | updateType = updatetype.none; | ||
4868 | } | ||
4869 | if ((change & ObjectChangeType.Scale) != 0) | ||
4870 | { | ||
4871 | part.Resize(data.scale); | ||
4872 | updateType = updatetype.none; | ||
4873 | } | ||
4874 | } | ||
4875 | |||
4876 | if (pha != null) | ||
4877 | pha.Building = false; | ||
4878 | } | ||
4879 | |||
4880 | if (updateType != updatetype.none) | ||
4881 | { | ||
4882 | group.HasGroupChanged = true; | ||
4883 | |||
4884 | switch (updateType) | ||
4885 | { | ||
4886 | case updatetype.partterse: | ||
4887 | part.ScheduleTerseUpdate(); | ||
4888 | break; | ||
4889 | case updatetype.partfull: | ||
4890 | part.ScheduleFullUpdate(); | ||
4891 | break; | ||
4892 | case updatetype.groupterse: | ||
4893 | group.ScheduleGroupForTerseUpdate(); | ||
4894 | break; | ||
4895 | case updatetype.groupfull: | ||
4896 | group.ScheduleGroupForFullUpdate(); | ||
4897 | break; | ||
4898 | default: | ||
4899 | break; | ||
4900 | } | ||
4901 | } | ||
4902 | } | ||
3530 | } | 4903 | } |
3531 | 4904 | ||
3532 | #endregion | 4905 | #endregion |
3533 | 4906 | ||
3534 | internal void SetAxisRotation(int axis, int rotate10) | 4907 | internal void SetAxisRotation(int axis, int rotate10) |
3535 | { | 4908 | { |
3536 | bool setX = false; | 4909 | bool setX = ((axis & (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_X) != 0); |
3537 | bool setY = false; | 4910 | bool setY = ((axis & (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Y) != 0); |
3538 | bool setZ = false; | 4911 | bool setZ = ((axis & (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Z) != 0); |
3539 | 4912 | ||
3540 | int xaxis = 2; | 4913 | if (setX || setY || setZ) |
3541 | int yaxis = 4; | 4914 | { |
3542 | int zaxis = 8; | 4915 | bool lockaxis = (rotate10 == 0); // zero means axis locked |
3543 | 4916 | ||
3544 | setX = ((axis & xaxis) != 0) ? true : false; | 4917 | byte locks = RootPart.RotationAxisLocks; |
3545 | setY = ((axis & yaxis) != 0) ? true : false; | ||
3546 | setZ = ((axis & zaxis) != 0) ? true : false; | ||
3547 | 4918 | ||
3548 | float setval = (rotate10 > 0) ? 1f : 0f; | 4919 | if (setX) |
4920 | { | ||
4921 | if(lockaxis) | ||
4922 | locks |= (byte)SceneObjectGroup.axisSelect.STATUS_ROTATE_X; | ||
4923 | else | ||
4924 | locks &= (byte)SceneObjectGroup.axisSelect.NOT_STATUS_ROTATE_X; | ||
4925 | } | ||
3549 | 4926 | ||
3550 | if (setX) | 4927 | if (setY) |
3551 | RootPart.RotationAxis.X = setval; | 4928 | { |
3552 | if (setY) | 4929 | if(lockaxis) |
3553 | RootPart.RotationAxis.Y = setval; | 4930 | locks |= (byte)SceneObjectGroup.axisSelect.STATUS_ROTATE_Y; |
3554 | if (setZ) | 4931 | else |
3555 | RootPart.RotationAxis.Z = setval; | 4932 | locks &= (byte)SceneObjectGroup.axisSelect.NOT_STATUS_ROTATE_Y; |
4933 | } | ||
3556 | 4934 | ||
3557 | if (setX || setY || setZ) | 4935 | if (setZ) |
4936 | { | ||
4937 | if(lockaxis) | ||
4938 | locks |= (byte)SceneObjectGroup.axisSelect.STATUS_ROTATE_Z; | ||
4939 | else | ||
4940 | locks &= (byte)SceneObjectGroup.axisSelect.NOT_STATUS_ROTATE_Z; | ||
4941 | } | ||
4942 | |||
4943 | RootPart.RotationAxisLocks = locks; | ||
3558 | RootPart.SetPhysicsAxisRotation(); | 4944 | RootPart.SetPhysicsAxisRotation(); |
4945 | } | ||
4946 | } | ||
4947 | |||
4948 | public int GetAxisRotation(int axis) | ||
4949 | { | ||
4950 | byte rotAxislocks = RootPart.RotationAxisLocks; | ||
4951 | |||
4952 | // if multiple return the one with higher id | ||
4953 | if (axis == (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Z) | ||
4954 | return (rotAxislocks & (byte)SceneObjectGroup.axisSelect.STATUS_ROTATE_Z) == 0 ? 1:0; | ||
4955 | if (axis == (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Y) | ||
4956 | return (rotAxislocks & (byte)SceneObjectGroup.axisSelect.STATUS_ROTATE_Y) == 0 ? 1:0; | ||
4957 | if (axis == (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_X) | ||
4958 | return (rotAxislocks & (byte)SceneObjectGroup.axisSelect.STATUS_ROTATE_X) == 0 ? 1:0; | ||
4959 | |||
4960 | return 0; | ||
3559 | } | 4961 | } |
3560 | 4962 | ||
3561 | public int registerRotTargetWaypoint(Quaternion target, float tolerance) | 4963 | public int registerRotTargetWaypoint(Quaternion target, float tolerance) |
@@ -3567,6 +4969,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
3567 | waypoint.handle = handle; | 4969 | waypoint.handle = handle; |
3568 | lock (m_rotTargets) | 4970 | lock (m_rotTargets) |
3569 | { | 4971 | { |
4972 | if (m_rotTargets.Count >= 8) | ||
4973 | m_rotTargets.Remove(m_rotTargets.ElementAt(0).Key); | ||
3570 | m_rotTargets.Add(handle, waypoint); | 4974 | m_rotTargets.Add(handle, waypoint); |
3571 | } | 4975 | } |
3572 | m_scene.AddGroupTarget(this); | 4976 | m_scene.AddGroupTarget(this); |
@@ -3592,12 +4996,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
3592 | waypoint.handle = handle; | 4996 | waypoint.handle = handle; |
3593 | lock (m_targets) | 4997 | lock (m_targets) |
3594 | { | 4998 | { |
4999 | if (m_targets.Count >= 8) | ||
5000 | m_targets.Remove(m_targets.ElementAt(0).Key); | ||
3595 | m_targets.Add(handle, waypoint); | 5001 | m_targets.Add(handle, waypoint); |
3596 | } | 5002 | } |
3597 | m_scene.AddGroupTarget(this); | 5003 | m_scene.AddGroupTarget(this); |
3598 | return (int)handle; | 5004 | return (int)handle; |
3599 | } | 5005 | } |
3600 | 5006 | ||
3601 | public void unregisterTargetWaypoint(int handle) | 5007 | public void unregisterTargetWaypoint(int handle) |
3602 | { | 5008 | { |
3603 | lock (m_targets) | 5009 | lock (m_targets) |
@@ -3625,10 +5031,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
3625 | scriptPosTarget target = m_targets[idx]; | 5031 | scriptPosTarget target = m_targets[idx]; |
3626 | if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance) | 5032 | if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance) |
3627 | { | 5033 | { |
5034 | at_target = true; | ||
5035 | |||
3628 | // trigger at_target | 5036 | // trigger at_target |
3629 | if (m_scriptListens_atTarget) | 5037 | if (m_scriptListens_atTarget) |
3630 | { | 5038 | { |
3631 | at_target = true; | ||
3632 | scriptPosTarget att = new scriptPosTarget(); | 5039 | scriptPosTarget att = new scriptPosTarget(); |
3633 | att.targetPos = target.targetPos; | 5040 | att.targetPos = target.targetPos; |
3634 | att.tolerance = target.tolerance; | 5041 | att.tolerance = target.tolerance; |
@@ -3638,14 +5045,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
3638 | } | 5045 | } |
3639 | } | 5046 | } |
3640 | } | 5047 | } |
3641 | 5048 | ||
3642 | if (atTargets.Count > 0) | 5049 | if (atTargets.Count > 0) |
3643 | { | 5050 | { |
3644 | SceneObjectPart[] parts = m_parts.GetArray(); | 5051 | SceneObjectPart[] parts = m_parts.GetArray(); |
3645 | uint[] localids = new uint[parts.Length]; | 5052 | uint[] localids = new uint[parts.Length]; |
3646 | for (int i = 0; i < parts.Length; i++) | 5053 | for (int i = 0; i < parts.Length; i++) |
3647 | localids[i] = parts[i].LocalId; | 5054 | localids[i] = parts[i].LocalId; |
3648 | 5055 | ||
3649 | for (int ctr = 0; ctr < localids.Length; ctr++) | 5056 | for (int ctr = 0; ctr < localids.Length; ctr++) |
3650 | { | 5057 | { |
3651 | foreach (uint target in atTargets.Keys) | 5058 | foreach (uint target in atTargets.Keys) |
@@ -3655,10 +5062,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
3655 | localids[ctr], att.handle, att.targetPos, m_rootPart.GroupPosition); | 5062 | localids[ctr], att.handle, att.targetPos, m_rootPart.GroupPosition); |
3656 | } | 5063 | } |
3657 | } | 5064 | } |
3658 | 5065 | ||
3659 | return; | 5066 | return; |
3660 | } | 5067 | } |
3661 | 5068 | ||
3662 | if (m_scriptListens_notAtTarget && !at_target) | 5069 | if (m_scriptListens_notAtTarget && !at_target) |
3663 | { | 5070 | { |
3664 | //trigger not_at_target | 5071 | //trigger not_at_target |
@@ -3666,7 +5073,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3666 | uint[] localids = new uint[parts.Length]; | 5073 | uint[] localids = new uint[parts.Length]; |
3667 | for (int i = 0; i < parts.Length; i++) | 5074 | for (int i = 0; i < parts.Length; i++) |
3668 | localids[i] = parts[i].LocalId; | 5075 | localids[i] = parts[i].LocalId; |
3669 | 5076 | ||
3670 | for (int ctr = 0; ctr < localids.Length; ctr++) | 5077 | for (int ctr = 0; ctr < localids.Length; ctr++) |
3671 | { | 5078 | { |
3672 | m_scene.EventManager.TriggerNotAtTargetEvent(localids[ctr]); | 5079 | m_scene.EventManager.TriggerNotAtTargetEvent(localids[ctr]); |
@@ -3746,11 +5153,35 @@ namespace OpenSim.Region.Framework.Scenes | |||
3746 | } | 5153 | } |
3747 | } | 5154 | } |
3748 | } | 5155 | } |
3749 | 5156 | ||
5157 | public Vector3 GetGeometricCenter() | ||
5158 | { | ||
5159 | // this is not real geometric center but a average of positions relative to root prim acording to | ||
5160 | // http://wiki.secondlife.com/wiki/llGetGeometricCenter | ||
5161 | // ignoring tortured prims details since sl also seems to ignore | ||
5162 | // so no real use in doing it on physics | ||
5163 | |||
5164 | Vector3 gc = Vector3.Zero; | ||
5165 | |||
5166 | SceneObjectPart[] parts = m_parts.GetArray(); | ||
5167 | int nparts = parts.Length; | ||
5168 | if (nparts < 2) | ||
5169 | return gc; | ||
5170 | |||
5171 | // average all parts positions | ||
5172 | for (int i = 0; i < nparts; i++) | ||
5173 | { | ||
5174 | if (parts[i] != RootPart) | ||
5175 | gc += parts[i].OffsetPosition; | ||
5176 | } | ||
5177 | gc /= nparts; | ||
5178 | |||
5179 | return gc; | ||
5180 | } | ||
5181 | |||
3750 | public float GetMass() | 5182 | public float GetMass() |
3751 | { | 5183 | { |
3752 | float retmass = 0f; | 5184 | float retmass = 0f; |
3753 | |||
3754 | SceneObjectPart[] parts = m_parts.GetArray(); | 5185 | SceneObjectPart[] parts = m_parts.GetArray(); |
3755 | for (int i = 0; i < parts.Length; i++) | 5186 | for (int i = 0; i < parts.Length; i++) |
3756 | retmass += parts[i].GetMass(); | 5187 | retmass += parts[i].GetMass(); |
@@ -3758,30 +5189,82 @@ namespace OpenSim.Region.Framework.Scenes | |||
3758 | return retmass; | 5189 | return retmass; |
3759 | } | 5190 | } |
3760 | 5191 | ||
3761 | /// <summary> | 5192 | // center of mass of full object |
3762 | /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that | 5193 | public Vector3 GetCenterOfMass() |
3763 | /// the physics engine can use it. | ||
3764 | /// </summary> | ||
3765 | /// <remarks> | ||
3766 | /// When the physics engine has finished with it, the sculpt data is discarded to save memory. | ||
3767 | /// </remarks> | ||
3768 | /* | ||
3769 | public void CheckSculptAndLoad() | ||
3770 | { | 5194 | { |
3771 | if (IsDeleted) | 5195 | PhysicsActor pa = RootPart.PhysActor; |
3772 | return; | ||
3773 | 5196 | ||
3774 | if ((RootPart.GetEffectiveObjectFlags() & (uint)PrimFlags.Phantom) != 0) | 5197 | if(((RootPart.Flags & PrimFlags.Physics) !=0) && pa !=null) |
3775 | return; | 5198 | { |
5199 | // physics knows better about center of mass of physical prims | ||
5200 | Vector3 tmp = pa.CenterOfMass; | ||
5201 | return tmp; | ||
5202 | } | ||
3776 | 5203 | ||
3777 | // m_log.Debug("Processing CheckSculptAndLoad for {0} {1}", Name, LocalId); | 5204 | Vector3 Ptot = Vector3.Zero; |
5205 | float totmass = 0f; | ||
5206 | float m; | ||
3778 | 5207 | ||
3779 | SceneObjectPart[] parts = m_parts.GetArray(); | 5208 | SceneObjectPart[] parts = m_parts.GetArray(); |
3780 | |||
3781 | for (int i = 0; i < parts.Length; i++) | 5209 | for (int i = 0; i < parts.Length; i++) |
3782 | parts[i].CheckSculptAndLoad(); | 5210 | { |
5211 | m = parts[i].GetMass(); | ||
5212 | Ptot += parts[i].GetPartCenterOfMass() * m; | ||
5213 | totmass += m; | ||
5214 | } | ||
5215 | |||
5216 | if (totmass == 0) | ||
5217 | totmass = 0; | ||
5218 | else | ||
5219 | totmass = 1 / totmass; | ||
5220 | Ptot *= totmass; | ||
5221 | |||
5222 | return Ptot; | ||
3783 | } | 5223 | } |
3784 | */ | 5224 | |
5225 | public void GetInertiaData(out float TotalMass, out Vector3 CenterOfMass, out Vector3 Inertia, out Vector4 aux ) | ||
5226 | { | ||
5227 | PhysicsActor pa = RootPart.PhysActor; | ||
5228 | |||
5229 | if(((RootPart.Flags & PrimFlags.Physics) !=0) && pa !=null) | ||
5230 | { | ||
5231 | PhysicsInertiaData inertia; | ||
5232 | |||
5233 | inertia = pa.GetInertiaData(); | ||
5234 | |||
5235 | TotalMass = inertia.TotalMass; | ||
5236 | CenterOfMass = inertia.CenterOfMass; | ||
5237 | Inertia = inertia.Inertia; | ||
5238 | aux = inertia.InertiaRotation; | ||
5239 | |||
5240 | return; | ||
5241 | } | ||
5242 | |||
5243 | TotalMass = GetMass(); | ||
5244 | CenterOfMass = GetCenterOfMass() - AbsolutePosition; | ||
5245 | CenterOfMass *= Quaternion.Conjugate(RootPart.RotationOffset); | ||
5246 | Inertia = Vector3.Zero; | ||
5247 | aux = Vector4.Zero; | ||
5248 | } | ||
5249 | |||
5250 | public void SetInertiaData(float TotalMass, Vector3 CenterOfMass, Vector3 Inertia, Vector4 aux ) | ||
5251 | { | ||
5252 | PhysicsInertiaData inertia = new PhysicsInertiaData(); | ||
5253 | inertia.TotalMass = TotalMass; | ||
5254 | inertia.CenterOfMass = CenterOfMass; | ||
5255 | inertia.Inertia = Inertia; | ||
5256 | inertia.InertiaRotation = aux; | ||
5257 | |||
5258 | if(TotalMass < 0) | ||
5259 | RootPart.PhysicsInertia = null; | ||
5260 | else | ||
5261 | RootPart.PhysicsInertia = new PhysicsInertiaData(inertia); | ||
5262 | |||
5263 | PhysicsActor pa = RootPart.PhysActor; | ||
5264 | if(pa !=null) | ||
5265 | pa.SetInertiaData(inertia); | ||
5266 | } | ||
5267 | |||
3785 | /// <summary> | 5268 | /// <summary> |
3786 | /// Set the user group to which this scene object belongs. | 5269 | /// Set the user group to which this scene object belongs. |
3787 | /// </summary> | 5270 | /// </summary> |
@@ -3798,7 +5281,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3798 | } | 5281 | } |
3799 | 5282 | ||
3800 | HasGroupChanged = true; | 5283 | HasGroupChanged = true; |
3801 | 5284 | ||
3802 | // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled | 5285 | // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled |
3803 | // for the same object with very different properties. The caller must schedule the update. | 5286 | // for the same object with very different properties. The caller must schedule the update. |
3804 | //ScheduleGroupForFullUpdate(); | 5287 | //ScheduleGroupForFullUpdate(); |
@@ -3937,6 +5420,133 @@ namespace OpenSim.Region.Framework.Scenes | |||
3937 | FromItemID = uuid; | 5420 | FromItemID = uuid; |
3938 | } | 5421 | } |
3939 | 5422 | ||
5423 | public void ResetOwnerChangeFlag() | ||
5424 | { | ||
5425 | ForEachPart(delegate(SceneObjectPart part) | ||
5426 | { | ||
5427 | part.ResetOwnerChangeFlag(); | ||
5428 | }); | ||
5429 | InvalidateEffectivePerms(); | ||
5430 | } | ||
5431 | |||
5432 | // clear some references to easy cg | ||
5433 | public void Clear() | ||
5434 | { | ||
5435 | m_parts.Clear(); | ||
5436 | m_sittingAvatars.Clear(); | ||
5437 | // m_rootPart = null; | ||
5438 | |||
5439 | m_PlaySoundMasterPrim = null; | ||
5440 | m_PlaySoundSlavePrims.Clear(); | ||
5441 | m_LoopSoundMasterPrim = null; | ||
5442 | m_targets.Clear(); | ||
5443 | m_partsNameToLinkMap.Clear(); | ||
5444 | } | ||
5445 | |||
5446 | private Dictionary<string,int> m_partsNameToLinkMap = new Dictionary<string, int>(); | ||
5447 | private string GetLinkNumber_lastname; | ||
5448 | private int GetLinkNumber_lastnumber; | ||
5449 | |||
5450 | // this scales bad but so does GetLinkNumPart | ||
5451 | public int GetLinkNumber(string name) | ||
5452 | { | ||
5453 | if(String.IsNullOrEmpty(name) || name == "Object") | ||
5454 | return -1; | ||
5455 | |||
5456 | lock(m_partsNameToLinkMap) | ||
5457 | { | ||
5458 | if(m_partsNameToLinkMap.Count == 0) | ||
5459 | { | ||
5460 | GetLinkNumber_lastname = String.Empty; | ||
5461 | GetLinkNumber_lastnumber = -1; | ||
5462 | SceneObjectPart[] parts = m_parts.GetArray(); | ||
5463 | for (int i = 0; i < parts.Length; i++) | ||
5464 | { | ||
5465 | string s = parts[i].Name; | ||
5466 | if(String.IsNullOrEmpty(s) || s == "Object" || s == "Primitive") | ||
5467 | continue; | ||
5468 | |||
5469 | if(m_partsNameToLinkMap.ContainsKey(s)) | ||
5470 | { | ||
5471 | int ol = parts[i].LinkNum; | ||
5472 | if(ol < m_partsNameToLinkMap[s]) | ||
5473 | m_partsNameToLinkMap[s] = ol; | ||
5474 | } | ||
5475 | else | ||
5476 | m_partsNameToLinkMap[s] = parts[i].LinkNum; | ||
5477 | } | ||
5478 | } | ||
5479 | |||
5480 | if(name == GetLinkNumber_lastname) | ||
5481 | return GetLinkNumber_lastnumber; | ||
5482 | |||
5483 | if(m_partsNameToLinkMap.ContainsKey(name)) | ||
5484 | { | ||
5485 | lock(m_partsNameToLinkMap) | ||
5486 | { | ||
5487 | GetLinkNumber_lastname = name; | ||
5488 | GetLinkNumber_lastnumber = m_partsNameToLinkMap[name]; | ||
5489 | return GetLinkNumber_lastnumber; | ||
5490 | } | ||
5491 | } | ||
5492 | } | ||
5493 | |||
5494 | if(m_sittingAvatars.Count > 0) | ||
5495 | { | ||
5496 | int j = m_parts.Count + 1; | ||
5497 | |||
5498 | ScenePresence[] avs = m_sittingAvatars.ToArray(); | ||
5499 | for (int i = 0; i < avs.Length; i++, j++) | ||
5500 | { | ||
5501 | if (avs[i].Name == name) | ||
5502 | { | ||
5503 | GetLinkNumber_lastname = name; | ||
5504 | GetLinkNumber_lastnumber = j; | ||
5505 | return j; | ||
5506 | } | ||
5507 | } | ||
5508 | } | ||
5509 | |||
5510 | return -1; | ||
5511 | } | ||
5512 | |||
5513 | public void InvalidatePartsLinkMaps() | ||
5514 | { | ||
5515 | lock(m_partsNameToLinkMap) | ||
5516 | { | ||
5517 | m_partsNameToLinkMap.Clear(); | ||
5518 | GetLinkNumber_lastname = String.Empty; | ||
5519 | GetLinkNumber_lastnumber = -1; | ||
5520 | } | ||
5521 | } | ||
5522 | |||
5523 | public bool CollisionSoundThrottled(int collisionSoundType) | ||
5524 | { | ||
5525 | double time = m_lastCollisionSoundMS; | ||
5526 | // m_lastCollisionSoundMS = Util.GetTimeStampMS(); | ||
5527 | // time = m_lastCollisionSoundMS - time; | ||
5528 | double now = Util.GetTimeStampMS(); | ||
5529 | time = now - time; | ||
5530 | switch (collisionSoundType) | ||
5531 | { | ||
5532 | case 0: // default sounds | ||
5533 | case 2: // default sounds with volume set by script | ||
5534 | if(time < 300.0) | ||
5535 | return true; | ||
5536 | break; | ||
5537 | case 1: // selected sound | ||
5538 | if(time < 200.0) | ||
5539 | return true; | ||
5540 | break; | ||
5541 | default: | ||
5542 | break; | ||
5543 | } | ||
5544 | m_lastCollisionSoundMS = now; | ||
5545 | return false; | ||
5546 | } | ||
5547 | |||
3940 | #endregion | 5548 | #endregion |
3941 | } | 5549 | } |
5550 | |||
5551 | |||
3942 | } | 5552 | } |