first pass on unlinking of objects. From Jay Clarke (IBM)
parent
448612db62
commit
eb41ec00c9
|
@ -175,6 +175,8 @@ namespace OpenSim.Framework
|
||||||
public delegate void StartAnim(IClientAPI remoteClient, LLUUID animID, int seq);
|
public delegate void StartAnim(IClientAPI remoteClient, LLUUID animID, int seq);
|
||||||
|
|
||||||
public delegate void LinkObjects(uint parent, List<uint> children);
|
public delegate void LinkObjects(uint parent, List<uint> children);
|
||||||
|
|
||||||
|
public delegate void DelinkObjects(List<uint> primIds);
|
||||||
|
|
||||||
public delegate void RequestMapBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY);
|
public delegate void RequestMapBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY);
|
||||||
|
|
||||||
|
@ -290,6 +292,7 @@ namespace OpenSim.Framework
|
||||||
event SetAppearance OnSetAppearance;
|
event SetAppearance OnSetAppearance;
|
||||||
event StartAnim OnStartAnim;
|
event StartAnim OnStartAnim;
|
||||||
event LinkObjects OnLinkObjects;
|
event LinkObjects OnLinkObjects;
|
||||||
|
event DelinkObjects OnDelinkObjects;
|
||||||
event RequestMapBlocks OnRequestMapBlocks;
|
event RequestMapBlocks OnRequestMapBlocks;
|
||||||
event TeleportLocationRequest OnTeleportLocationRequest;
|
event TeleportLocationRequest OnTeleportLocationRequest;
|
||||||
event DisconnectUser OnDisconnectUser;
|
event DisconnectUser OnDisconnectUser;
|
||||||
|
|
|
@ -58,6 +58,7 @@ namespace OpenSim.Region.ClientStack
|
||||||
public event StartAnim OnStartAnim;
|
public event StartAnim OnStartAnim;
|
||||||
public event Action<IClientAPI> OnRequestAvatarsData;
|
public event Action<IClientAPI> OnRequestAvatarsData;
|
||||||
public event LinkObjects OnLinkObjects;
|
public event LinkObjects OnLinkObjects;
|
||||||
|
public event DelinkObjects OnDelinkObjects;
|
||||||
public event UpdateVector OnGrabObject;
|
public event UpdateVector OnGrabObject;
|
||||||
public event ObjectSelect OnDeGrabObject;
|
public event ObjectSelect OnDeGrabObject;
|
||||||
public event ObjectDuplicate OnObjectDuplicate;
|
public event ObjectDuplicate OnObjectDuplicate;
|
||||||
|
|
|
@ -223,7 +223,7 @@ namespace OpenSim.Region.ClientStack
|
||||||
#region Objects/m_sceneObjects
|
#region Objects/m_sceneObjects
|
||||||
|
|
||||||
case PacketType.ObjectLink:
|
case PacketType.ObjectLink:
|
||||||
// OpenSim.Framework.Console.MainLog.Instance.Verbose( Pack.ToString());
|
//OpenSim.Framework.Console.MainLog.Instance.Verbose( Pack.ToString());
|
||||||
ObjectLinkPacket link = (ObjectLinkPacket) Pack;
|
ObjectLinkPacket link = (ObjectLinkPacket) Pack;
|
||||||
uint parentprimid = 0;
|
uint parentprimid = 0;
|
||||||
List<uint> childrenprims = new List<uint>();
|
List<uint> childrenprims = new List<uint>();
|
||||||
|
@ -240,6 +240,26 @@ namespace OpenSim.Region.ClientStack
|
||||||
{
|
{
|
||||||
OnLinkObjects(parentprimid, childrenprims);
|
OnLinkObjects(parentprimid, childrenprims);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case PacketType.ObjectDelink:
|
||||||
|
//OpenSim.Framework.Console.MainLog.Instance.Verbose( Pack.ToString());
|
||||||
|
ObjectDelinkPacket delink = (ObjectDelinkPacket) Pack;
|
||||||
|
|
||||||
|
// It appears the prim at index 0 is not always the root prim (for
|
||||||
|
// instance, when one prim of a link set has been edited independently
|
||||||
|
// of the others). Therefore, we'll pass all the ids onto the delink
|
||||||
|
// method for it to decide which is the root.
|
||||||
|
List<uint> prims = new List<uint>();
|
||||||
|
for (int i = 0; i < delink.ObjectData.Length; i++)
|
||||||
|
{
|
||||||
|
prims.Add(delink.ObjectData[i].ObjectLocalID);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (OnDelinkObjects != null)
|
||||||
|
{
|
||||||
|
OnDelinkObjects(prims);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case PacketType.ObjectAdd:
|
case PacketType.ObjectAdd:
|
||||||
if (OnAddPrim != null)
|
if (OnAddPrim != null)
|
||||||
|
@ -775,4 +795,4 @@ namespace OpenSim.Region.ClientStack
|
||||||
OutPacket(logReply);
|
OutPacket(logReply);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -536,6 +536,56 @@ namespace OpenSim.Region.Environment.Scenes
|
||||||
parenPrim.LinkToGroup(sceneObj);
|
parenPrim.LinkToGroup(sceneObj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Delink a linkset
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="prims"></param>
|
||||||
|
public void DelinkObjects(List<uint> primIds)
|
||||||
|
{
|
||||||
|
//OpenSim.Framework.Console.MainLog.Instance.Verbose("DelinkObjects()");
|
||||||
|
|
||||||
|
SceneObjectGroup parenPrim = null;
|
||||||
|
|
||||||
|
// Need a list of the SceneObjectGroup local ids
|
||||||
|
// XXX I'm anticipating that building this dictionary once is more efficient than
|
||||||
|
// repeated scanning of the Entity.Values for a large number of primIds. However, it might
|
||||||
|
// be more efficient yet to keep this dictionary permanently on hand.
|
||||||
|
Dictionary<uint, SceneObjectGroup> sceneObjects = new Dictionary<uint, SceneObjectGroup>();
|
||||||
|
foreach (EntityBase ent in Entities.Values)
|
||||||
|
{
|
||||||
|
if (ent is SceneObjectGroup)
|
||||||
|
{
|
||||||
|
SceneObjectGroup obj = (SceneObjectGroup)ent;
|
||||||
|
sceneObjects.Add(obj.LocalId, obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the root prim among the prim ids we've been given
|
||||||
|
for (int i = 0; i < primIds.Count; i++)
|
||||||
|
{
|
||||||
|
if (sceneObjects.ContainsKey(primIds[i]))
|
||||||
|
{
|
||||||
|
parenPrim = sceneObjects[primIds[i]];
|
||||||
|
primIds.RemoveAt(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parenPrim != null)
|
||||||
|
{
|
||||||
|
foreach (uint childPrimId in primIds)
|
||||||
|
{
|
||||||
|
parenPrim.DelinkFromGroup(childPrimId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
OpenSim.Framework.Console.MainLog.Instance.Verbose(
|
||||||
|
"DelinkObjects(): Could not find a root prim out of {0} as given to a delink request!",
|
||||||
|
primIds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
|
|
|
@ -705,6 +705,7 @@ namespace OpenSim.Region.Environment.Scenes
|
||||||
client.OnObjectDescription += m_innerScene.PrimDescription;
|
client.OnObjectDescription += m_innerScene.PrimDescription;
|
||||||
client.OnObjectName += m_innerScene.PrimName;
|
client.OnObjectName += m_innerScene.PrimName;
|
||||||
client.OnLinkObjects += m_innerScene.LinkObjects;
|
client.OnLinkObjects += m_innerScene.LinkObjects;
|
||||||
|
client.OnDelinkObjects += m_innerScene.DelinkObjects;
|
||||||
client.OnObjectDuplicate += m_innerScene.DuplicateObject;
|
client.OnObjectDuplicate += m_innerScene.DuplicateObject;
|
||||||
client.OnUpdatePrimFlags += m_innerScene.UpdatePrimFlags;
|
client.OnUpdatePrimFlags += m_innerScene.UpdatePrimFlags;
|
||||||
|
|
||||||
|
@ -1273,4 +1274,4 @@ namespace OpenSim.Region.Environment.Scenes
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -222,6 +222,27 @@ namespace OpenSim.Region.Environment.Scenes
|
||||||
public SceneObjectGroup()
|
public SceneObjectGroup()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This constructor creates a SceneObjectGroup using a pre-existing SceneObjectPart.
|
||||||
|
/// The original SceneObjectPart will be used rather than a copy, preserving
|
||||||
|
/// its existing localID and UUID.
|
||||||
|
/// </summary>
|
||||||
|
public SceneObjectGroup(Scene scene, ulong regionHandle, SceneObjectPart part)
|
||||||
|
{
|
||||||
|
m_scene = scene;
|
||||||
|
m_regionHandle = regionHandle;
|
||||||
|
|
||||||
|
part.SetParent(this);
|
||||||
|
part.ParentID = 0;
|
||||||
|
|
||||||
|
m_parts.Add(part.UUID, part);
|
||||||
|
SetPartAsRoot(part);
|
||||||
|
|
||||||
|
AttachToBackup();
|
||||||
|
|
||||||
|
ScheduleGroupForFullUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
|
@ -594,10 +615,10 @@ namespace OpenSim.Region.Environment.Scenes
|
||||||
#region SceneGroupPart Methods
|
#region SceneGroupPart Methods
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// Get a child part with a given UUID
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="primID"></param>
|
/// <param name="primID"></param>
|
||||||
/// <returns></returns>
|
/// <returns>null if a child part with the primID was not found</returns>
|
||||||
public SceneObjectPart GetChildPart(LLUUID primID)
|
public SceneObjectPart GetChildPart(LLUUID primID)
|
||||||
{
|
{
|
||||||
SceneObjectPart childPart = null;
|
SceneObjectPart childPart = null;
|
||||||
|
@ -609,10 +630,10 @@ namespace OpenSim.Region.Environment.Scenes
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// Get a child part with a given local ID
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="localID"></param>
|
/// <param name="localID"></param>
|
||||||
/// <returns></returns>
|
/// <returns>null if a child part with the local ID was not found</returns>
|
||||||
public SceneObjectPart GetChildPart(uint localID)
|
public SceneObjectPart GetChildPart(uint localID)
|
||||||
{
|
{
|
||||||
foreach (SceneObjectPart part in m_parts.Values)
|
foreach (SceneObjectPart part in m_parts.Values)
|
||||||
|
@ -717,13 +738,85 @@ namespace OpenSim.Region.Environment.Scenes
|
||||||
objectGroup.DeleteParts();
|
objectGroup.DeleteParts();
|
||||||
ScheduleGroupForFullUpdate();
|
ScheduleGroupForFullUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Delink the given prim from this group. The delinked prim is established as
|
||||||
|
/// an independent SceneObjectGroup.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="partID"></param>
|
||||||
|
public void DelinkFromGroup(uint partID)
|
||||||
|
{
|
||||||
|
SceneObjectPart linkPart = GetChildPart(partID);
|
||||||
|
|
||||||
|
if (null != linkPart)
|
||||||
|
{
|
||||||
|
// Remove the part from this object
|
||||||
|
m_parts.Remove(linkPart.UUID);
|
||||||
|
|
||||||
|
// We need to reset the child part's position
|
||||||
|
// ready for life as a separate object after being a part of another object
|
||||||
|
Quaternion parentRot
|
||||||
|
= new Quaternion(
|
||||||
|
m_rootPart.RotationOffset.W,
|
||||||
|
m_rootPart.RotationOffset.X,
|
||||||
|
m_rootPart.RotationOffset.Y,
|
||||||
|
m_rootPart.RotationOffset.Z);
|
||||||
|
|
||||||
|
Vector3 axPos
|
||||||
|
= new Vector3(
|
||||||
|
linkPart.OffsetPosition.X,
|
||||||
|
linkPart.OffsetPosition.Y,
|
||||||
|
linkPart.OffsetPosition.Z);
|
||||||
|
|
||||||
|
axPos = parentRot * axPos;
|
||||||
|
linkPart.OffsetPosition = new LLVector3(axPos.x, axPos.y, axPos.z);
|
||||||
|
linkPart.GroupPosition = AbsolutePosition + linkPart.OffsetPosition;
|
||||||
|
linkPart.OffsetPosition = new LLVector3(0, 0, 0);
|
||||||
|
|
||||||
|
Quaternion oldRot
|
||||||
|
= new Quaternion(
|
||||||
|
linkPart.RotationOffset.W,
|
||||||
|
linkPart.RotationOffset.X,
|
||||||
|
linkPart.RotationOffset.Y,
|
||||||
|
linkPart.RotationOffset.Z);
|
||||||
|
Quaternion newRot = parentRot * oldRot;
|
||||||
|
linkPart.RotationOffset = new LLQuaternion(newRot.x, newRot.y, newRot.z, newRot.w);
|
||||||
|
|
||||||
|
// Add physics information back to delinked part if appropriate
|
||||||
|
// XXX This is messy and should be refactorable with the similar section in
|
||||||
|
// SceneObjectPart.UpdatePrimFlags()
|
||||||
|
if (m_rootPart.PhysActor != null)
|
||||||
|
{
|
||||||
|
linkPart.PhysActor = m_scene.PhysScene.AddPrimShape(
|
||||||
|
linkPart.Name,
|
||||||
|
linkPart.Shape,
|
||||||
|
new PhysicsVector(linkPart.AbsolutePosition.X, linkPart.AbsolutePosition.Y,
|
||||||
|
linkPart.AbsolutePosition.Z),
|
||||||
|
new PhysicsVector(linkPart.Scale.X, linkPart.Scale.Y, linkPart.Scale.Z),
|
||||||
|
new Quaternion(linkPart.RotationOffset.W, linkPart.RotationOffset.X,
|
||||||
|
linkPart.RotationOffset.Y, linkPart.RotationOffset.Z),
|
||||||
|
m_rootPart.PhysActor.IsPhysical);
|
||||||
|
}
|
||||||
|
|
||||||
|
SceneObjectGroup objectGroup = new SceneObjectGroup(m_scene, m_regionHandle, linkPart);
|
||||||
|
|
||||||
|
m_scene.AddEntity(objectGroup);
|
||||||
|
|
||||||
|
ScheduleGroupForFullUpdate();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
OpenSim.Framework.Console.MainLog.Instance.Verbose(
|
||||||
|
"DelinkFromGroup(): Child prim local id {0} not found in object with root prim id {1}",
|
||||||
|
partID, LocalId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void DetachFromBackup(SceneObjectGroup objectGroup)
|
private void DetachFromBackup(SceneObjectGroup objectGroup)
|
||||||
{
|
{
|
||||||
m_scene.EventManager.OnBackup -= objectGroup.ProcessBackup;
|
m_scene.EventManager.OnBackup -= objectGroup.ProcessBackup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void LinkNonRootPart(SceneObjectPart part, Vector3 oldGroupPosition, Quaternion oldGroupRotation)
|
private void LinkNonRootPart(SceneObjectPart part, Vector3 oldGroupPosition, Quaternion oldGroupRotation)
|
||||||
{
|
{
|
||||||
part.SetParent(this);
|
part.SetParent(this);
|
||||||
|
@ -1431,4 +1524,4 @@ namespace OpenSim.Region.Environment.Scenes
|
||||||
Text = text;
|
Text = text;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -328,17 +328,28 @@ namespace OpenSim.Region.Environment.Scenes
|
||||||
if (m_updateTimes.ContainsKey(part.UUID))
|
if (m_updateTimes.ContainsKey(part.UUID))
|
||||||
{
|
{
|
||||||
ScenePartUpdate update = m_updateTimes[part.UUID];
|
ScenePartUpdate update = m_updateTimes[part.UUID];
|
||||||
if (update.LastFullUpdateTime < part.TimeStampFull)
|
|
||||||
|
// Two updates can occur with the same timestamp (especially
|
||||||
|
// since our timestamp resolution is to the nearest second). The first
|
||||||
|
// could have been sent in the last update - we still need to send the
|
||||||
|
// second here.
|
||||||
|
if (update.LastFullUpdateTime <= part.TimeStampFull)
|
||||||
{
|
{
|
||||||
//need to do a full update
|
//need to do a full update
|
||||||
part.SendFullUpdate(ControllingClient);
|
part.SendFullUpdate(ControllingClient);
|
||||||
update.LastFullUpdateTime = (uint) Util.UnixTimeSinceEpoch();
|
|
||||||
|
// We'll update to the part's timestamp rather than the current to
|
||||||
|
// avoid the race condition whereby the next tick occurs while we are
|
||||||
|
// doing this update. If this happened, then subsequent updates which occurred
|
||||||
|
// on the same tick or the next tick of the last update would be ignored.
|
||||||
|
update.LastFullUpdateTime = part.TimeStampFull;
|
||||||
|
|
||||||
updateCount++;
|
updateCount++;
|
||||||
}
|
}
|
||||||
else if (update.LastTerseUpdateTime < part.TimeStampTerse)
|
else if (update.LastTerseUpdateTime <= part.TimeStampTerse)
|
||||||
{
|
{
|
||||||
part.SendTerseUpdate(ControllingClient);
|
part.SendTerseUpdate(ControllingClient);
|
||||||
update.LastTerseUpdateTime = (uint) Util.UnixTimeSinceEpoch();
|
update.LastTerseUpdateTime = part.TimeStampTerse;
|
||||||
updateCount++;
|
updateCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -348,7 +359,7 @@ namespace OpenSim.Region.Environment.Scenes
|
||||||
part.SendFullUpdate(ControllingClient);
|
part.SendFullUpdate(ControllingClient);
|
||||||
ScenePartUpdate update = new ScenePartUpdate();
|
ScenePartUpdate update = new ScenePartUpdate();
|
||||||
update.FullID = part.UUID;
|
update.FullID = part.UUID;
|
||||||
update.LastFullUpdateTime = (uint) Util.UnixTimeSinceEpoch();
|
update.LastFullUpdateTime = part.TimeStampFull;
|
||||||
m_updateTimes.Add(part.UUID, update);
|
m_updateTimes.Add(part.UUID, update);
|
||||||
updateCount++;
|
updateCount++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,7 @@ namespace SimpleApp
|
||||||
public event SetAppearance OnSetAppearance;
|
public event SetAppearance OnSetAppearance;
|
||||||
public event StartAnim OnStartAnim;
|
public event StartAnim OnStartAnim;
|
||||||
public event LinkObjects OnLinkObjects;
|
public event LinkObjects OnLinkObjects;
|
||||||
|
public event DelinkObjects OnDelinkObjects;
|
||||||
public event RequestMapBlocks OnRequestMapBlocks;
|
public event RequestMapBlocks OnRequestMapBlocks;
|
||||||
public event TeleportLocationRequest OnTeleportLocationRequest;
|
public event TeleportLocationRequest OnTeleportLocationRequest;
|
||||||
public event DisconnectUser OnDisconnectUser;
|
public event DisconnectUser OnDisconnectUser;
|
||||||
|
|
Loading…
Reference in New Issue