using System; using System.Collections.Generic; using System.Xml; using System.Xml.Serialization; using Axiom.Math; using libsecondlife; using libsecondlife.Packets; using OpenSim.Framework.Interfaces; using OpenSim.Framework.Inventory; using OpenSim.Framework.Types; using InventoryItem = OpenSim.Framework.Inventory.InventoryItem; namespace OpenSim.Region.Environment.Scenes { public delegate void PrimCountTaintedDelegate(); public class Primitive : EntityBase { private const uint FULL_MASK_PERMISSIONS = 2147483647; private LLVector3 m_positionLastFrame = new LLVector3(0, 0, 0); private ulong m_regionHandle; private byte m_updateFlag; private uint m_flags = 32 + 65536 + 131072 + 256 + 4 + 8 + 2048 + 524288 + 268435456 + 128; private Dictionary m_inventoryItems; private string m_description = ""; public LLUUID CreatorID; public LLUUID OwnerID; public LLUUID LastOwnerID; public Int32 CreationDate; public uint ParentID = 0; public uint OwnerMask = FULL_MASK_PERMISSIONS; public uint NextOwnerMask = FULL_MASK_PERMISSIONS; public uint GroupMask = 0;// FULL_MASK_PERMISSIONS; public uint EveryoneMask = 0;//FULL_MASK_PERMISSIONS; public uint BaseMask = 0;//FULL_MASK_PERMISSIONS; private PrimitiveBaseShape m_shape; private byte[] m_particleSystem = new byte[0]; public SceneObject m_RootParent; public bool m_isRootPrim; public EntityBase m_Parent; public event PrimCountTaintedDelegate OnPrimCountTainted; #region Properties /// /// If rootprim, will return world position /// otherwise will return local offset from rootprim /// public override LLVector3 Pos { get { if (m_isRootPrim) { //if we are rootprim then our offset should be zero return m_pos + m_Parent.Pos; } else { return m_pos; } } set { if (m_isRootPrim) { m_Parent.Pos = value; } m_pos = value - m_Parent.Pos; } } public PrimitiveBaseShape Shape { get { return m_shape; } } public LLVector3 WorldPos { get { if (!m_isRootPrim) { Primitive parentPrim = (Primitive)m_Parent; Vector3 offsetPos = new Vector3(m_pos.X, m_pos.Y, m_pos.Z); offsetPos = parentPrim.Rotation * offsetPos; return parentPrim.WorldPos + new LLVector3(offsetPos.x, offsetPos.y, offsetPos.z); } else { return Pos; } } } public string Description { get { return m_description; } set { m_description = value; } } public LLVector3 Scale { set { m_shape.Scale = value; } get { return m_shape.Scale; } } private string m_sitName = ""; public string SitName { get { return m_sitName; } } private string m_touchName = ""; public string TouchName { get { return m_touchName; } } private string m_text = ""; public string Text { get { return m_text; } set { m_text = value; ScheduleFullUpdate(); } } #endregion #region Constructors public Primitive(ulong regionHandle, Scene scene, LLUUID ownerID, uint localID, bool isRoot, EntityBase parent, SceneObject rootObject, PrimitiveBaseShape shape, LLVector3 pos) { m_regionHandle = regionHandle; m_scene = scene; m_inventoryItems = new Dictionary(); m_Parent = parent; m_isRootPrim = isRoot; m_RootParent = rootObject; ClearUpdateSchedule(); CreateFromShape(ownerID, localID, pos, shape); Rotation = Quaternion.Identity; m_scene.AcknowledgeNewPrim(this); OnPrimCountTainted(); } /// /// /// /// Empty constructor for duplication public Primitive() { } #endregion #region Destructors ~Primitive() { if (OnPrimCountTainted != null) OnPrimCountTainted(); } #endregion #region Duplication public Primitive Copy(EntityBase parent, SceneObject rootParent) { Primitive dupe = (Primitive)MemberwiseClone(); dupe.m_Parent = parent; dupe.m_RootParent = rootParent; // TODO: Copy this properly. dupe.m_inventoryItems = m_inventoryItems; dupe.m_children = new List(); dupe.m_shape = m_shape.Copy(); dupe.m_regionHandle = m_regionHandle; dupe.m_scene = m_scene; uint newLocalID = m_scene.PrimIDAllocate(); dupe.m_uuid = LLUUID.Random(); dupe.LocalId = newLocalID; if (parent is SceneObject) { dupe.m_isRootPrim = true; dupe.ParentID = 0; } else { dupe.m_isRootPrim = false; dupe.ParentID = ((Primitive)parent).LocalId; } dupe.Scale = new LLVector3(Scale.X, Scale.Y, Scale.Z); dupe.Rotation = new Quaternion(Rotation.w, Rotation.x, Rotation.y, Rotation.z); dupe.m_pos = new LLVector3(m_pos.X, m_pos.Y, m_pos.Z); rootParent.AddChildToList(dupe); m_scene.AcknowledgeNewPrim(dupe); dupe.TriggerOnPrimCountTainted(); foreach (Primitive prim in m_children) { Primitive primClone = prim.Copy(dupe, rootParent); dupe.m_children.Add(primClone); } return dupe; } #endregion #region Override from EntityBase /// /// /// public override void Update() { if (m_updateFlag == 1) //some change has been made so update the clients { SendTerseUpdateToALLClients(); ClearUpdateSchedule(); } else { if (m_updateFlag == 2) // is a new prim just been created/reloaded or has major changes { SendFullUpdateToAllClients(); ClearUpdateSchedule(); } } foreach (EntityBase child in m_children) { child.Update(); } } private void ClearUpdateSchedule() { m_updateFlag = 0; } #endregion #region Setup /// /// /// /// /// /// public void CreateFromShape(LLUUID ownerID, uint localID, LLVector3 pos, PrimitiveBaseShape shape) { CreationDate = (Int32)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds; OwnerID = ownerID; CreatorID = OwnerID; LastOwnerID = LLUUID.Zero; Pos = pos; m_uuid = LLUUID.Random(); m_localId = (uint)(localID); m_shape = shape; ScheduleFullUpdate(); } private void ScheduleFullUpdate() { m_updateFlag = 2; } private void ScheduleTerseUpdate() { if (m_updateFlag < 1) { m_updateFlag = 1; } } #endregion #region Linking / unlinking /// /// /// /// public void AddNewChildren(SceneObject linkObject) { // Console.WriteLine("linking new prims " + linkObject.rootLocalID + " to me (" + this.LocalId + ")"); //TODO check permissions m_children.Add(linkObject.rootPrimitive); linkObject.rootPrimitive.SetNewParent(this, m_RootParent); m_scene.DeleteEntity(linkObject.rootUUID); linkObject.DeleteAllChildren(); OnPrimCountTainted(); } /// /// /// /// /// public void SetNewParent(Primitive newParent, SceneObject rootParent) { LLVector3 oldPos = new LLVector3(Pos.X, Pos.Y, Pos.Z); m_isRootPrim = false; m_Parent = newParent; ParentID = newParent.LocalId; m_RootParent = rootParent; m_RootParent.AddChildToList(this); Pos = oldPos; Vector3 axPos = new Vector3(m_pos.X, m_pos.Y, m_pos.Z); axPos = m_Parent.Rotation.Inverse() * axPos; m_pos = new LLVector3(axPos.x, axPos.y, axPos.z); Quaternion oldRot = new Quaternion(Rotation.w, Rotation.x, Rotation.y, Rotation.z); Rotation = m_Parent.Rotation.Inverse() * Rotation; ScheduleFullUpdate(); foreach (Primitive child in m_children) { child.SetRootParent(rootParent, newParent, oldPos, oldRot); } m_children.Clear(); } /// /// /// /// public void SetRootParent(SceneObject newRoot, Primitive newParent, LLVector3 oldParentPosition, Quaternion oldParentRotation) { LLVector3 oldPos = new LLVector3(Pos.X, Pos.Y, Pos.Z); Vector3 axOldPos = new Vector3(oldPos.X, oldPos.Y, oldPos.Z); axOldPos = oldParentRotation * axOldPos; oldPos = new LLVector3(axOldPos.x, axOldPos.y, axOldPos.z); oldPos += oldParentPosition; Quaternion oldRot = new Quaternion(Rotation.w, Rotation.x, Rotation.y, Rotation.z); m_isRootPrim = false; m_Parent = newParent; ParentID = newParent.LocalId; newParent.AddToChildrenList(this); m_RootParent = newRoot; m_RootParent.AddChildToList(this); Pos = oldPos; Vector3 axPos = new Vector3(m_pos.X, m_pos.Y, m_pos.Z); axPos = m_Parent.Rotation.Inverse() * axPos; m_pos = new LLVector3(axPos.x, axPos.y, axPos.z); Rotation = oldParentRotation * Rotation; Rotation = m_Parent.Rotation.Inverse() * Rotation; ScheduleFullUpdate(); foreach (Primitive child in m_children) { child.SetRootParent(newRoot, newParent, oldPos, oldRot); } m_children.Clear(); } /// /// /// /// public void AddOffsetToChildren(LLVector3 offset) { foreach (Primitive prim in m_children) { prim.m_pos += offset; prim.ScheduleTerseUpdate(); } OnPrimCountTainted(); } /// /// /// /// public void AddToChildrenList(Primitive prim) { m_children.Add(prim); } #endregion #region Resizing/Scale /// /// /// /// public void ResizeGoup(LLVector3 scale) { m_shape.Scale = scale; ScheduleFullUpdate(); } #endregion #region Position /// /// /// /// public void UpdateGroupPosition(LLVector3 pos) { LLVector3 newPos = new LLVector3(pos.X, pos.Y, pos.Z); Pos = newPos; ScheduleTerseUpdate(); OnPrimCountTainted(); } /// /// /// /// public void UpdateSinglePosition(LLVector3 pos) { // Console.WriteLine("updating single prim position"); if (m_isRootPrim) { LLVector3 newPos = new LLVector3(pos.X, pos.Y, pos.Z); LLVector3 oldPos = new LLVector3(Pos.X, Pos.Y, Pos.Z); LLVector3 diff = oldPos - newPos; Vector3 axDiff = new Vector3(diff.X, diff.Y, diff.Z); axDiff = Rotation.Inverse() * axDiff; diff.X = axDiff.x; diff.Y = axDiff.y; diff.Z = axDiff.z; Pos = newPos; foreach (Primitive prim in m_children) { prim.m_pos += diff; prim.ScheduleTerseUpdate(); } ScheduleTerseUpdate(); } else { LLVector3 newPos = new LLVector3(pos.X, pos.Y, pos.Z); m_pos = newPos; ScheduleTerseUpdate(); } } #endregion #region Rotation /// /// /// /// public void UpdateGroupRotation(LLQuaternion rot) { Rotation = new Quaternion(rot.W, rot.X, rot.Y, rot.Z); ScheduleTerseUpdate(); } /// /// /// /// /// public void UpdateGroupMouseRotation(LLVector3 pos, LLQuaternion rot) { Rotation = new Quaternion(rot.W, rot.X, rot.Y, rot.Z); Pos = pos; ScheduleTerseUpdate(); } /// /// /// /// public void UpdateSingleRotation(LLQuaternion rot) { //Console.WriteLine("updating single prim rotation"); Quaternion axRot = new Quaternion(rot.W, rot.X, rot.Y, rot.Z); Quaternion oldParentRot = new Quaternion(Rotation.w, Rotation.x, Rotation.y, Rotation.z); Rotation = axRot; foreach (Primitive prim in m_children) { Vector3 axPos = new Vector3(prim.m_pos.X, prim.m_pos.Y, prim.m_pos.Z); axPos = oldParentRot * axPos; axPos = axRot.Inverse() * axPos; prim.m_pos = new LLVector3(axPos.x, axPos.y, axPos.z); prim.Rotation = oldParentRot * prim.Rotation; prim.Rotation = axRot.Inverse() * prim.Rotation; prim.ScheduleTerseUpdate(); } ScheduleTerseUpdate(); } #endregion #region Shape /// /// /// /// public void UpdateShape(ObjectShapePacket.ObjectDataBlock shapeBlock) { m_shape.PathBegin = shapeBlock.PathBegin; m_shape.PathEnd = shapeBlock.PathEnd; m_shape.PathScaleX = shapeBlock.PathScaleX; m_shape.PathScaleY = shapeBlock.PathScaleY; m_shape.PathShearX = shapeBlock.PathShearX; m_shape.PathShearY = shapeBlock.PathShearY; m_shape.PathSkew = shapeBlock.PathSkew; m_shape.ProfileBegin = shapeBlock.ProfileBegin; m_shape.ProfileEnd = shapeBlock.ProfileEnd; m_shape.PathCurve = shapeBlock.PathCurve; m_shape.ProfileCurve = shapeBlock.ProfileCurve; m_shape.ProfileHollow = shapeBlock.ProfileHollow; m_shape.PathRadiusOffset = shapeBlock.PathRadiusOffset; m_shape.PathRevolutions = shapeBlock.PathRevolutions; m_shape.PathTaperX = shapeBlock.PathTaperX; m_shape.PathTaperY = shapeBlock.PathTaperY; m_shape.PathTwist = shapeBlock.PathTwist; m_shape.PathTwistBegin = shapeBlock.PathTwistBegin; ScheduleFullUpdate(); } #endregion #region Inventory public void GetInventory(IClientAPI client, uint localID) { if (localID == this.m_localId) { client.SendTaskInventory(this.m_uuid, 0, new byte[0]); } } #endregion public void UpdateExtraParam(ushort type, bool inUse, byte[] data) { this.m_shape.ExtraParams = new byte[data.Length + 7]; int i =0; uint length = (uint) data.Length; this.m_shape.ExtraParams[i++] = 1; this.m_shape.ExtraParams[i++] = (byte)(type % 256); this.m_shape.ExtraParams[i++] = (byte)((type >> 8) % 256); this.m_shape.ExtraParams[i++] = (byte)(length % 256); this.m_shape.ExtraParams[i++] = (byte)((length >> 8) % 256); this.m_shape.ExtraParams[i++] = (byte)((length >> 16) % 256); this.m_shape.ExtraParams[i++] = (byte)((length >> 24) % 256); Array.Copy(data, 0, this.m_shape.ExtraParams, i, data.Length); this.ScheduleFullUpdate(); } #region Texture /// /// /// /// public void UpdateTextureEntry(byte[] textureEntry) { m_shape.TextureEntry = textureEntry; ScheduleFullUpdate(); } #endregion public void AddNewParticleSystem(libsecondlife.Primitive.ParticleSystem pSystem) { this.m_particleSystem = pSystem.GetBytes(); ScheduleFullUpdate(); } #region Client Update Methods /// /// /// /// public void SendFullUpdateForAllChildren(IClientAPI remoteClient) { SendFullUpdateToClient(remoteClient); for (int i = 0; i < m_children.Count; i++) { if (m_children[i] is Primitive) { ((Primitive)m_children[i]).SendFullUpdateForAllChildren(remoteClient); } } } /// /// /// /// public void SendFullUpdateToClient(IClientAPI remoteClient) { LLVector3 lPos; lPos = Pos; LLQuaternion lRot; lRot = new LLQuaternion(Rotation.x, Rotation.y, Rotation.z, Rotation.w); remoteClient.SendPrimitiveToClient(m_regionHandle, 64096, LocalId, m_shape, lPos, m_flags, m_uuid, OwnerID, m_text, ParentID, this.m_particleSystem, lRot); } /// /// /// public void SendFullUpdateToAllClients() { List avatars = m_scene.RequestAvatarList(); for (int i = 0; i < avatars.Count; i++) { SendFullUpdateToClient(avatars[i].ControllingClient); } } /// /// /// /// public void SendTerseUpdateForAllChildren(IClientAPI remoteClient) { SendTerseUpdateToClient(remoteClient); for (int i = 0; i < m_children.Count; i++) { if (m_children[i] is Primitive) { ((Primitive)m_children[i]).SendTerseUpdateForAllChildren(remoteClient); } } } /// /// /// /// public void SendTerseUpdateToClient(IClientAPI RemoteClient) { LLVector3 lPos; Quaternion lRot; lPos = Pos; lRot = Rotation; LLQuaternion mRot = new LLQuaternion(lRot.x, lRot.y, lRot.z, lRot.w); RemoteClient.SendPrimTerseUpdate(m_regionHandle, 64096, LocalId, lPos, mRot); } /// /// /// public void SendTerseUpdateToALLClients() { List avatars = m_scene.RequestAvatarList(); for (int i = 0; i < avatars.Count; i++) { SendTerseUpdateToClient(avatars[i].ControllingClient); } } #endregion public void TriggerOnPrimCountTainted() { OnPrimCountTainted(); } } }