public void Quaternions() { LLQuaternion a = new LLQuaternion(1, 0, 0, 0); LLQuaternion b = new LLQuaternion(1, 0, 0, 0); Assert.IsTrue(a == b, "LLQuaternion comparison operator failed"); LLQuaternion expected = new LLQuaternion(0, 0, 0, -1); LLQuaternion result = a * b; Assert.IsTrue(result == expected, a.ToString() + " * " + b.ToString() + " produced " + result.ToString() + " instead of " + expected.ToString()); a = new LLQuaternion(1, 0, 0, 0); b = new LLQuaternion(0, 1, 0, 0); expected = new LLQuaternion(0, 0, 1, 0); result = a * b; Assert.IsTrue(result == expected, a.ToString() + " * " + b.ToString() + " produced " + result.ToString() + " instead of " + expected.ToString()); a = new LLQuaternion(0, 0, 1, 0); b = new LLQuaternion(0, 1, 0, 0); expected = new LLQuaternion(-1, 0, 0, 0); result = a * b; Assert.IsTrue(result == expected, a.ToString() + " * " + b.ToString() + " produced " + result.ToString() + " instead of " + expected.ToString()); }
/// <summary> /// Send new AgentUpdate packet to update our current camera /// position and rotation /// </summary> /// <param name="reliable">Whether to require server acknowledgement /// of this packet</param> /// <param name="simulator">Simulator to send the update to</param> public void SendUpdate(bool reliable, Simulator simulator) { LLVector3 origin = Camera.Position; LLVector3 xAxis = Camera.LeftAxis; LLVector3 yAxis = Camera.AtAxis; LLVector3 zAxis = Camera.UpAxis; // Attempted to sort these in a rough order of how often they might change if (agentControls == 0 && yAxis == LastCameraYAxis && origin == LastCameraCenter && State == lastState && HeadRotation == LastHeadRotation && BodyRotation == LastBodyRotation && xAxis == LastCameraXAxis && Camera.Far == LastFar && zAxis == LastCameraZAxis) { ++duplicateCount; } else { duplicateCount = 0; } if (Client.Settings.CONTINUOUS_AGENT_UPDATES || duplicateCount < 10) { // Store the current state to do duplicate checking in the future LastHeadRotation = HeadRotation; LastBodyRotation = BodyRotation; LastCameraYAxis = yAxis; LastCameraCenter = origin; LastCameraXAxis = xAxis; LastCameraZAxis = zAxis; LastFar = Camera.Far; lastState = State; // Build the AgentUpdate packet and send it AgentUpdatePacket update = new AgentUpdatePacket(); update.Header.Reliable = reliable; update.AgentData.AgentID = Client.Self.AgentID; update.AgentData.SessionID = Client.Self.SessionID; update.AgentData.HeadRotation = HeadRotation; update.AgentData.BodyRotation = BodyRotation; update.AgentData.CameraAtAxis = yAxis; update.AgentData.CameraCenter = origin; update.AgentData.CameraLeftAxis = xAxis; update.AgentData.CameraUpAxis = zAxis; update.AgentData.Far = Camera.Far; update.AgentData.State = (byte)State; update.AgentData.ControlFlags = agentControls; update.AgentData.Flags = (byte)Flags; Client.Network.SendPacket(update, simulator); ResetControlFlags(); } }
public static LLVector3 operator *(LLVector3 vec, LLQuaternion quat) { LLQuaternion vq = new LLQuaternion(vec.X, vec.Y, vec.Z, 0); LLQuaternion nq = new LLQuaternion(-quat.X, -quat.Y, -quat.Z, quat.W); LLQuaternion result = (quat * vq) * nq; return(new LLVector3(result.X, result.Y, result.Z)); }
/// <summary> /// /// </summary> /// <param name="lhs"></param> /// <param name="rhs"></param> /// <returns></returns> public static LLQuaternion operator *(LLQuaternion lhs, LLQuaternion rhs) { LLQuaternion ret = new LLQuaternion(); ret.W = lhs.W * rhs.W - lhs.X * rhs.X - lhs.Y * rhs.Y - lhs.Z * rhs.Z; ret.X = lhs.W * rhs.X + lhs.X * rhs.W + lhs.Y * rhs.Z - lhs.Z * rhs.Y; ret.Y = lhs.W * rhs.Y + lhs.Y * rhs.W + lhs.Z * rhs.X - lhs.X * rhs.Z; ret.Z = lhs.W * rhs.Z + lhs.Z * rhs.W + lhs.X * rhs.Y - lhs.Y * rhs.X; return(ret); }
/// <summary> /// Send an AgentUpdate with the camera set at the current agent /// position and pointing towards the heading specified /// </summary> /// <param name="heading">Camera rotation in radians</param> /// <param name="reliable">Whether to send the AgentUpdate reliable /// or not</param> public void UpdateFromHeading(double heading, bool reliable) { Camera.Position = Client.Self.SimPosition; Camera.LookDirection(heading); BodyRotation.Z = (float)Math.Sin(heading / 2.0d); BodyRotation.W = (float)Math.Cos(heading / 2.0d); HeadRotation = BodyRotation; SendUpdate(reliable); }
/// <summary> /// /// </summary> /// <param name="o"></param> /// <returns></returns> public override bool Equals(object o) { if (!(o is LLQuaternion)) { return(false); } LLQuaternion quaternion = (LLQuaternion)o; return(X == quaternion.X && Y == quaternion.Y && Z == quaternion.Z && W == quaternion.W); }
public void Yaw(float angle) { LLQuaternion q = new LLQuaternion(angle, zAxis); LLMatrix3 m = new LLMatrix3(q); Rotate(m); if (!xAxis.IsFinite() || !yAxis.IsFinite()) { throw new Exception("Non-finite in CoordinateFrame.Yaw()"); } }
public CoordinateFrame(LLVector3 origin, LLQuaternion rotation) { LLMatrix3 m = new LLMatrix3(rotation); this.origin = origin; xAxis = m[0]; yAxis = m[1]; zAxis = m[2]; if (!IsFinite()) { throw new ArgumentException("Non-finite in CoordinateFrame constructor"); } }
/// <summary> /// Constructor, aka 'CallBack Central' - Setup callbacks for packets related to our avatar /// </summary> /// <param name="client"></param> public MainAvatar(SecondLife client) { PacketCallback callback; Client = client; TeleportMessage = ""; // Create emtpy vectors for now HomeLookAt = HomePosition = Position = LookAt = new LLVector3(); Rotation = new LLQuaternion(); // Coarse location callback Client.Network.RegisterCallback(PacketType.CoarseLocationUpdate, new PacketCallback(CoarseLocationHandler)); // Teleport callbacks callback = new PacketCallback(TeleportHandler); Client.Network.RegisterCallback(PacketType.TeleportStart, callback); Client.Network.RegisterCallback(PacketType.TeleportProgress, callback); Client.Network.RegisterCallback(PacketType.TeleportFailed, callback); Client.Network.RegisterCallback(PacketType.TeleportFinish, callback); // Instant Message callback Client.Network.RegisterCallback(PacketType.ImprovedInstantMessage, new PacketCallback(InstantMessageHandler)); // Chat callback Client.Network.RegisterCallback(PacketType.ChatFromSimulator, new PacketCallback(ChatHandler)); TeleportTimer = new Timer(18000); TeleportTimer.Elapsed += new ElapsedEventHandler(TeleportTimerEvent); TeleportTimeout = false; // Movement complete callback Client.Network.RegisterCallback(PacketType.AgentMovementComplete, new PacketCallback(MovementCompleteHandler)); // Health callback Client.Network.RegisterCallback(PacketType.HealthMessage, new PacketCallback(HealthHandler)); // Money callbacks callback = new PacketCallback(BalanceHandler); Client.Network.RegisterCallback(PacketType.MoneyBalanceReply, callback); Client.Network.RegisterCallback(PacketType.MoneySummaryReply, callback); Client.Network.RegisterCallback(PacketType.AdjustBalance, callback); }
/// <summary> /// Rotates the avatar body and camera toward a target position. /// This will also anchor the camera position on the avatar /// </summary> /// <param name="target">Region coordinates to turn toward</param> public bool TurnToward(LLVector3 target) { if (Client.Settings.SEND_AGENT_UPDATES) { LLVector3 myPos = Client.Self.SimPosition; LLVector3 forward = new LLVector3(1, 0, 0); LLVector3 offset = LLVector3.Norm(target - myPos); LLQuaternion newRot = LLVector3.RotBetween(forward, offset); BodyRotation = newRot; HeadRotation = newRot; Camera.LookAt(myPos, target); SendUpdate(); return(true); } else { Logger.Log("Attempted TurnToward but agent updates are disabled", Helpers.LogLevel.Warning, Client); return(false); } }
/// <summary> /// Builds an AgentUpdate packet entirely from parameters. This /// will not touch the state of Self.Movement or /// Self.Movement.Camera in any way /// </summary> /// <param name="controlFlags"></param> /// <param name="position"></param> /// <param name="forwardAxis"></param> /// <param name="leftAxis"></param> /// <param name="upAxis"></param> /// <param name="bodyRotation"></param> /// <param name="headRotation"></param> /// <param name="farClip"></param> /// <param name="reliable"></param> /// <param name="flags"></param> /// <param name="state"></param> public void SendManualUpdate(AgentManager.ControlFlags controlFlags, LLVector3 position, LLVector3 forwardAxis, LLVector3 leftAxis, LLVector3 upAxis, LLQuaternion bodyRotation, LLQuaternion headRotation, float farClip, AgentFlags flags, AgentState state, bool reliable) { AgentUpdatePacket update = new AgentUpdatePacket(); update.AgentData.AgentID = Client.Self.AgentID; update.AgentData.SessionID = Client.Self.SessionID; update.AgentData.BodyRotation = bodyRotation; update.AgentData.HeadRotation = headRotation; update.AgentData.CameraCenter = position; update.AgentData.CameraAtAxis = forwardAxis; update.AgentData.CameraLeftAxis = leftAxis; update.AgentData.CameraUpAxis = upAxis; update.AgentData.Far = farClip; update.AgentData.ControlFlags = (uint)controlFlags; update.AgentData.Flags = (byte)flags; update.AgentData.State = (byte)state; update.Header.Reliable = reliable; Client.Network.SendPacket(update); }
/// <summary> /// Calculate the magnitude of the supplied quaternion /// </summary> public static float RotMag(LLQuaternion q) { return (float)Math.Sqrt(q.W * q.W + q.X * q.X + q.Y * q.Y + q.Z * q.Z); }
private void TerseUpdateHandler(Packet packet, Simulator simulator) { float x, y, z, w; uint localid; LLVector4 CollisionPlane = null; LLVector3 Position; LLVector3 Velocity; LLVector3 Acceleration; LLQuaternion Rotation; LLVector3 RotationVelocity; ImprovedTerseObjectUpdatePacket update = (ImprovedTerseObjectUpdatePacket)packet; foreach (ImprovedTerseObjectUpdatePacket.ObjectDataBlock block in update.ObjectData) { int i = 0; bool avatar; localid = (uint)(block.Data[i++] + (block.Data[i++] << 8) + (block.Data[i++] << 16) + (block.Data[i++] << 24)); byte state = block.Data[i++]; avatar = Convert.ToBoolean(block.Data[i++]); if (avatar) { if (OnAvatarMoved == null) { return; } CollisionPlane = new LLVector4(block.Data, i); i += 16; } else { if (OnPrimMoved == null) { return; } } // Position Position = new LLVector3(block.Data, i); i += 12; // Velocity x = Dequantize(block.Data, i, -128.0F, 128.0F); i += 2; y = Dequantize(block.Data, i, -128.0F, 128.0F); i += 2; z = Dequantize(block.Data, i, -128.0F, 128.0F); i += 2; Velocity = new LLVector3(x, y, z); // Acceleration x = Dequantize(block.Data, i, -64.0F, 64.0F); i += 2; y = Dequantize(block.Data, i, -64.0F, 64.0F); i += 2; z = Dequantize(block.Data, i, -64.0F, 64.0F); i += 2; Acceleration = new LLVector3(x, y, z); // Rotation x = Dequantize(block.Data, i, -1.0F, 1.0F); i += 2; y = Dequantize(block.Data, i, -1.0F, 1.0F); i += 2; z = Dequantize(block.Data, i, -1.0F, 1.0F); i += 2; w = Dequantize(block.Data, i, -1.0F, 1.0F); i += 2; Rotation = new LLQuaternion(x, y, z, w); // Rotation velocity x = Dequantize(block.Data, i, -64.0F, 64.0F); i += 2; y = Dequantize(block.Data, i, -64.0F, 64.0F); i += 2; z = Dequantize(block.Data, i, -64.0F, 64.0F); i += 2; RotationVelocity = new LLVector3(x, y, z); if (avatar) { if (localid == Client.Self.LocalID) { Client.Self.Position = Position; Client.Self.Rotation = Rotation; } AvatarUpdate avupdate = new AvatarUpdate(); avupdate.LocalID = localid; avupdate.State = state; avupdate.Position = Position; avupdate.CollisionPlane = CollisionPlane; avupdate.Velocity = Velocity; avupdate.Acceleration = Acceleration; avupdate.Rotation = Rotation; avupdate.RotationVelocity = RotationVelocity; if (OnAvatarMoved != null) { OnAvatarMoved(simulator, avupdate, update.RegionData.RegionHandle, update.RegionData.TimeDilation); } } else { // TODO: Is there an easy way to distinguish prims from trees in this packet, // or would the client have to do it's own lookup to determine whether it's a // prim or a tree? If the latter, we should rename this update to something // less prim specific PrimUpdate primupdate = new PrimUpdate(); primupdate.LocalID = localid; primupdate.State = state; primupdate.Position = Position; primupdate.Velocity = Velocity; primupdate.Acceleration = Acceleration; primupdate.Rotation = Rotation; primupdate.RotationVelocity = RotationVelocity; if (OnPrimMoved != null) { OnPrimMoved(simulator, primupdate, update.RegionData.RegionHandle, update.RegionData.TimeDilation); } } } }
public void Rotate(LLQuaternion q) { LLMatrix3 m = new LLMatrix3(q); Rotate(m); }
/// <summary> /// Create, or "rez" a new prim object in a simulator /// </summary> /// <param name="simulator">A reference to the <seealso cref="libsecondlife.Simulator"/> object to place the object in</param> /// <param name="prim">Data describing the prim object to rez</param> /// <param name="groupID">Group ID that this prim will be set to, or LLUUID.Zero if you /// do not want the object to be associated with a specific group</param> /// <param name="position">An approximation of the position at which to rez the prim</param> /// <param name="scale">Scale vector to size this prim</param> /// <param name="rotation">Rotation quaternion to rotate this prim</param> /// <remarks>Due to the way client prim rezzing is done on the server, /// the requested position for an object is only close to where the prim /// actually ends up. If you desire exact placement you'll need to /// follow up by moving the object after it has been created. This /// function will not set textures, light and flexible data, or other /// extended primitive properties</remarks> public void AddPrim(Simulator simulator, LLObject.ObjectData prim, LLUUID groupID, LLVector3 position, LLVector3 scale, LLQuaternion rotation) { ObjectAddPacket packet = new ObjectAddPacket(); packet.AgentData.AgentID = Client.Self.AgentID; packet.AgentData.SessionID = Client.Self.SessionID; packet.AgentData.GroupID = groupID; packet.ObjectData.State = prim.State; packet.ObjectData.AddFlags = (uint)LLObject.ObjectFlags.CreateSelected; packet.ObjectData.PCode = (byte)PCode.Prim; packet.ObjectData.Material = (byte)prim.Material; packet.ObjectData.Scale = scale; packet.ObjectData.Rotation = rotation; packet.ObjectData.PathCurve = (byte)prim.PathCurve; packet.ObjectData.PathBegin = LLObject.PackBeginCut(prim.PathBegin); packet.ObjectData.PathEnd = LLObject.PackEndCut(prim.PathEnd); packet.ObjectData.PathRadiusOffset = LLObject.PackPathTwist(prim.PathRadiusOffset); packet.ObjectData.PathRevolutions = LLObject.PackPathRevolutions(prim.PathRevolutions); packet.ObjectData.PathScaleX = LLObject.PackPathScale(prim.PathScaleX); packet.ObjectData.PathScaleY = LLObject.PackPathScale(prim.PathScaleY); packet.ObjectData.PathShearX = (byte)LLObject.PackPathShear(prim.PathShearX); packet.ObjectData.PathShearY = (byte)LLObject.PackPathShear(prim.PathShearY); packet.ObjectData.PathSkew = LLObject.PackPathTwist(prim.PathSkew); packet.ObjectData.PathTaperX = LLObject.PackPathTaper(prim.PathTaperX); packet.ObjectData.PathTaperY = LLObject.PackPathTaper(prim.PathTaperY); packet.ObjectData.PathTwist = LLObject.PackPathTwist(prim.PathTwist); packet.ObjectData.PathTwistBegin = LLObject.PackPathTwist(prim.PathTwistBegin); packet.ObjectData.ProfileCurve = prim.profileCurve; packet.ObjectData.ProfileBegin = LLObject.PackBeginCut(prim.ProfileBegin); packet.ObjectData.ProfileEnd = LLObject.PackEndCut(prim.ProfileEnd); packet.ObjectData.ProfileHollow = LLObject.PackProfileHollow(prim.ProfileHollow); packet.ObjectData.RayStart = position; packet.ObjectData.RayEnd = position; packet.ObjectData.RayEndIsIntersection = 0; packet.ObjectData.RayTargetID = LLUUID.Zero; packet.ObjectData.BypassRaycast = 1; Client.Network.SendPacket(packet, simulator); }
/// <summary> /// Multiplication operator /// </summary> /// <param name="lhs"></param> /// <param name="rhs"></param> /// <returns></returns> public static LLQuaternion operator *(LLQuaternion lhs, LLQuaternion rhs) { LLQuaternion ret = new LLQuaternion(); ret.W = lhs.W * rhs.W - lhs.X * rhs.X - lhs.Y * rhs.Y - lhs.Z * rhs.Z; ret.X = lhs.W * rhs.X + lhs.X * rhs.W + lhs.Y * rhs.Z - lhs.Z * rhs.Y; ret.Y = lhs.W * rhs.Y + lhs.Y * rhs.W + lhs.Z * rhs.X - lhs.X * rhs.Z; ret.Z = lhs.W * rhs.Z + lhs.Z * rhs.W + lhs.X * rhs.Y - lhs.Y * rhs.X; return ret; }
/// <summary> /// Returns a normalized version of the supplied quaternion /// </summary> /// <param name="q">The quaternion to normalize</param> /// <returns>A normalized version of the quaternion</returns> public static LLQuaternion Norm(LLQuaternion q) { const float MAG_THRESHOLD = 0.0000001f; float mag = (float)Math.Sqrt(q.X * q.X + q.Y * q.Y + q.Z * q.Z + q.W * q.W); if (mag > MAG_THRESHOLD) { float oomag = 1.0f / mag; q.X *= oomag; q.Y *= oomag; q.Z *= oomag; q.W *= oomag; } else { q.X = 0.0f; q.Y = 0.0f; q.Z = 0.0f; q.W = 1.0f; } return q; }
protected bool MultipleObjUpdate(SimClient simClient, Packet packet) { MultipleObjectUpdatePacket multipleupdate = (MultipleObjectUpdatePacket)packet; for (int i = 0; i < multipleupdate.ObjectData.Length; i++) { if (multipleupdate.ObjectData[i].Type == 9) //change position { libsecondlife.LLVector3 pos = new LLVector3(multipleupdate.ObjectData[i].Data, 0); foreach (Entity ent in m_world.Entities.Values) { if (ent.localid == multipleupdate.ObjectData[i].ObjectLocalID) { ((OpenSim.world.Primitive)ent).UpdatePosition(pos); } } //should update stored position of the prim } else if (multipleupdate.ObjectData[i].Type == 10)//rotation { libsecondlife.LLQuaternion rot = new LLQuaternion(multipleupdate.ObjectData[i].Data, 0, true); foreach (Entity ent in m_world.Entities.Values) { if (ent.localid == multipleupdate.ObjectData[i].ObjectLocalID) { ent.rotation = new Axiom.MathLib.Quaternion(rot.W, rot.X, rot.Y, rot.Z); ((OpenSim.world.Primitive)ent).UpdateFlag = true; } } } else if (multipleupdate.ObjectData[i].Type == 13)//scale { libsecondlife.LLVector3 scale = new LLVector3(multipleupdate.ObjectData[i].Data, 12); foreach (Entity ent in m_world.Entities.Values) { if (ent.localid == multipleupdate.ObjectData[i].ObjectLocalID) { ((OpenSim.world.Primitive)ent).Scale = scale; } } } } return true; }
public CoordinateFrame(LLVector3 origin, LLQuaternion rotation) { LLMatrix3 m = new LLMatrix3(rotation); this.origin = origin; xAxis = m[0]; yAxis = m[1]; zAxis = m[2]; if (!IsFinite()) throw new ArgumentException("Non-finite in CoordinateFrame constructor"); }
public static LLVector3 operator *(LLVector3 vec, LLQuaternion quat) { LLQuaternion vq = new LLQuaternion(vec.X, vec.Y, vec.Z, 0); LLQuaternion nq = new LLQuaternion(-quat.X, -quat.Y, -quat.Z, quat.W); LLQuaternion result = (quat * vq) * nq; return new LLVector3(result.X, result.Y, result.Z); }
public static LLVector3 Rot(LLVector3 vector, LLQuaternion rotation) { return vector * rotation; }
public LLMatrix3(LLQuaternion q) { this = LLQuaternion.GetMatrix(q); }
public void Rotate(float angle, LLVector3 rotationAxis) { LLQuaternion q = new LLQuaternion(angle, rotationAxis); Rotate(q); }
/// <summary> /// /// </summary> /// <param name="simulator"></param> /// <param name="scale"></param> /// <param name="rotation"></param> /// <param name="position"></param> /// <param name="grassType"></param> /// <param name="groupOwner"></param> public void AddGrass(Simulator simulator, LLVector3 scale, LLQuaternion rotation, LLVector3 position, Grass grassType, LLUUID groupOwner) { ObjectAddPacket add = new ObjectAddPacket(); add.AgentData.AgentID = Client.Network.AgentID; add.AgentData.SessionID = Client.Network.SessionID; add.AgentData.GroupID = groupOwner; add.ObjectData.BypassRaycast = 1; add.ObjectData.Material = 3; add.ObjectData.PathCurve = 16; add.ObjectData.PCode = (byte)PCode.Grass; add.ObjectData.RayEnd = position; add.ObjectData.RayStart = position; add.ObjectData.RayTargetID = LLUUID.Zero; add.ObjectData.Rotation = rotation; add.ObjectData.Scale = scale; add.ObjectData.State = (byte)grassType; Client.Network.SendPacket(add, simulator); }
/// <summary> /// /// </summary> /// <param name="simulator"></param> /// <param name="localID"></param> /// <param name="attachPoint"></param> /// <param name="rotation"></param> public void AttachObject(Simulator simulator, uint localID, AttachmentPoint attachPoint, LLQuaternion rotation) { ObjectAttachPacket attach = new ObjectAttachPacket(); attach.AgentData.AgentID = Client.Network.AgentID; attach.AgentData.SessionID = Client.Network.SessionID; attach.AgentData.AttachmentPoint = (byte)attachPoint; attach.ObjectData = new ObjectAttachPacket.ObjectDataBlock[1]; attach.ObjectData[0] = new ObjectAttachPacket.ObjectDataBlock(); attach.ObjectData[0].ObjectLocalID = localID; attach.ObjectData[0].Rotation = rotation; Client.Network.SendPacket(attach, simulator); }
private void TerseUpdateHandler(Packet packet, Simulator simulator) { float x, y, z, w; uint localid; LLVector4 CollisionPlane = LLVector4.Zero; LLVector3 Position; LLVector3 Velocity; LLVector3 Acceleration; LLQuaternion Rotation; LLVector3 RotationVelocity; ImprovedTerseObjectUpdatePacket update = (ImprovedTerseObjectUpdatePacket)packet; foreach (ImprovedTerseObjectUpdatePacket.ObjectDataBlock block in update.ObjectData) { int i = 0; bool avatar; localid = (uint)(block.Data[i++] + (block.Data[i++] << 8) + (block.Data[i++] << 16) + (block.Data[i++] << 24)); byte state = block.Data[i++]; avatar = Convert.ToBoolean(block.Data[i++]); if (avatar) { if (OnAvatarMoved == null) return; CollisionPlane = new LLVector4(block.Data, i); i += 16; } else { if (OnPrimMoved == null) return; } // Position Position = new LLVector3(block.Data, i); i += 12; // Velocity x = Dequantize(block.Data, i, -128.0F, 128.0F); i += 2; y = Dequantize(block.Data, i, -128.0F, 128.0F); i += 2; z = Dequantize(block.Data, i, -128.0F, 128.0F); i += 2; Velocity = new LLVector3(x, y, z); // Acceleration x = Dequantize(block.Data, i, -64.0F, 64.0F); i += 2; y = Dequantize(block.Data, i, -64.0F, 64.0F); i += 2; z = Dequantize(block.Data, i, -64.0F, 64.0F); i += 2; Acceleration = new LLVector3(x, y, z); // Rotation x = Dequantize(block.Data, i, -1.0F, 1.0F); i += 2; y = Dequantize(block.Data, i, -1.0F, 1.0F); i += 2; z = Dequantize(block.Data, i, -1.0F, 1.0F); i += 2; w = Dequantize(block.Data, i, -1.0F, 1.0F); i += 2; Rotation = new LLQuaternion(x, y, z, w); // Rotation velocity x = Dequantize(block.Data, i, -64.0F, 64.0F); i += 2; y = Dequantize(block.Data, i, -64.0F, 64.0F); i += 2; z = Dequantize(block.Data, i, -64.0F, 64.0F); i += 2; RotationVelocity = new LLVector3(x, y, z); if (avatar) { if (localid == Client.Self.LocalID) { Client.Self.Position = Position; Client.Self.Rotation = Rotation; } AvatarUpdate avupdate = new AvatarUpdate(); avupdate.LocalID = localid; avupdate.State = state; avupdate.Position = Position; avupdate.CollisionPlane = CollisionPlane; avupdate.Velocity = Velocity; avupdate.Acceleration = Acceleration; avupdate.Rotation = Rotation; avupdate.RotationVelocity = RotationVelocity; avupdate.Textures = new TextureEntry(block.TextureEntry, 4, block.TextureEntry.Length - 4); if (OnAvatarMoved != null) { OnAvatarMoved(simulator, avupdate, update.RegionData.RegionHandle, update.RegionData.TimeDilation); } } else { // TODO: Is there an easy way to distinguish prims from trees in this packet, // or would the client have to do it's own lookup to determine whether it's a // prim or a tree? If the latter, we should rename this update to something // less prim specific PrimUpdate primupdate = new PrimUpdate(); primupdate.LocalID = localid; primupdate.State = state; primupdate.Position = Position; primupdate.Velocity = Velocity; primupdate.Acceleration = Acceleration; primupdate.Rotation = Rotation; primupdate.RotationVelocity = RotationVelocity; primupdate.Textures = new TextureEntry(block.TextureEntry, 4, block.TextureEntry.Length - 4); if (OnPrimMoved != null) { OnPrimMoved(simulator, primupdate, update.RegionData.RegionHandle, update.RegionData.TimeDilation); } } } }
/// <summary> /// Returns the inverse matrix from a quaternion, or the correct /// matrix if the quaternion is inverse /// </summary> /// <param name="q">Quaternion to convert to a matrix</param> /// <returns>A matrix representation of the quaternion</returns> public static LLMatrix3 GetMatrix(LLQuaternion q) { LLMatrix3 m; float xx, xy, xz, xw, yy, yz, yw, zz, zw; xx = q.X * q.X; xy = q.X * q.Y; xz = q.X * q.Z; xw = q.X * q.W; yy = q.Y * q.Y; yz = q.Y * q.Z; yw = q.Y * q.W; zz = q.Z * q.Z; zw = q.Z * q.W; m.M11 = 1f - 2f * (yy + zz); m.M12 = 2f * (xy + zw); m.M13 = 2f * (xz - yw); m.M21 = 2f * (xy - zw); m.M22 = 1f - 2f * (xx + zz); m.M23 = 2f * (yz + xw); m.M31 = 2f * (xz + yw); m.M32 = 2f * (yz - xw); m.M33 = 1f - 2f * (xx + yy); return m; }
/// <summary> /// /// </summary> /// <param name="simulator"></param> /// <param name="localID"></param> /// <param name="rotation"></param> public void SetRotation(Simulator simulator, uint localID, LLQuaternion rotation) { ObjectRotationPacket objRotPacket = new ObjectRotationPacket(); objRotPacket.AgentData.AgentID = Client.Network.AgentID; objRotPacket.AgentData.SessionID = Client.Network.SessionID; objRotPacket.ObjectData = new ObjectRotationPacket.ObjectDataBlock[1]; objRotPacket.ObjectData[0] = new ObjectRotationPacket.ObjectDataBlock(); objRotPacket.ObjectData[0].ObjectLocalID = localID; objRotPacket.ObjectData[0].Rotation = rotation; Client.Network.SendPacket(objRotPacket, simulator); }
public LLQuaternion ToQuaternion() { LLQuaternion quat = new LLQuaternion(); float tr, s; float[] q = new float[4]; int i, j, k; int[] nxt = new int[] { 1, 2, 0 }; tr = this[0, 0] + this[1, 1] + this[2, 2]; // Check the diagonal if (tr > 0f) { s = (float)Math.Sqrt(tr + 1f); quat.W = s / 2f; s = 0.5f / s; quat.X = (this[1, 2] - this[2, 1]) * s; quat.Y = (this[2, 0] - this[0, 2]) * s; quat.Z = (this[0, 1] - this[1, 0]) * s; } else { // Diagonal is negative i = 0; if (this[1, 1] > this[0, 0]) i = 1; if (this[2, 2] > this[i, i]) i = 2; j = nxt[i]; k = nxt[j]; s = (float)Math.Sqrt((this[i, i] - (this[j, j] + this[k, k])) + 1f); q[i] = s * 0.5f; if (s != 0f) s = 0.5f / s; q[3] = (this[j, k] - this[k, j]) * s; q[j] = (this[i, j] + this[j, i]) * s; q[k] = (this[i, k] + this[k, i]) * s; quat.X = q[0]; quat.Y = q[1]; quat.Z = q[2]; quat.W = q[3]; } return quat; }
/// <summary> /// Rotates the avatar body and camera toward a target position. /// This will also anchor the camera position on the avatar /// </summary> /// <param name="target">Region coordinates to turn toward</param> public bool TurnToward(LLVector3 target) { if (Client.Settings.SEND_AGENT_UPDATES) { LLVector3 myPos = Client.Self.SimPosition; LLVector3 forward = new LLVector3(1, 0, 0); LLVector3 offset = LLVector3.Norm(target - myPos); LLQuaternion newRot = LLVector3.RotBetween(forward, offset); BodyRotation = newRot; HeadRotation = newRot; Camera.LookAt(myPos, target); SendUpdate(); return true; } else { Logger.Log("Attempted TurnToward but agent updates are disabled", Helpers.LogLevel.Warning, Client); return false; } }
/// <summary> /// Rez an object from inventory /// </summary> /// <param name="simulator">Simulator to place object in</param> /// <param name="rotation">Rotation of the object when rezzed</param> /// <param name="position">Vector of where to place object</param> /// <param name="item">InventoryObject object containing item details</param> /// <param name="groupOwner">LLUUID of group to own the object</param> public LLUUID RequestRezFromInventory(Simulator simulator, LLQuaternion rotation, LLVector3 position, InventoryObject item, LLUUID groupOwner) { return RequestRezFromInventory(simulator, rotation, position, item, groupOwner, LLUUID.Random(), false); }
/// <summary> /// Send new AgentUpdate packet to update our current camera /// position and rotation /// </summary> /// <param name="reliable">Whether to require server acknowledgement /// of this packet</param> /// <param name="simulator">Simulator to send the update to</param> public void SendUpdate(bool reliable, Simulator simulator) { LLVector3 origin = Camera.Position; LLVector3 xAxis = Camera.LeftAxis; LLVector3 yAxis = Camera.AtAxis; LLVector3 zAxis = Camera.UpAxis; // Attempted to sort these in a rough order of how often they might change if (agentControls == 0 && yAxis == LastCameraYAxis && origin == LastCameraCenter && State == lastState && HeadRotation == LastHeadRotation && BodyRotation == LastBodyRotation && xAxis == LastCameraXAxis && Camera.Far == LastFar && zAxis == LastCameraZAxis) { ++duplicateCount; } else { duplicateCount = 0; } if (Client.Settings.DISABLE_AGENT_UPDATE_DUPLICATE_CHECK || duplicateCount < 10) { // Store the current state to do duplicate checking LastHeadRotation = HeadRotation; LastBodyRotation = BodyRotation; LastCameraYAxis = yAxis; LastCameraCenter = origin; LastCameraXAxis = xAxis; LastCameraZAxis = zAxis; LastFar = Camera.Far; lastState = State; // Build the AgentUpdate packet and send it AgentUpdatePacket update = new AgentUpdatePacket(); update.Header.Reliable = reliable; update.AgentData.AgentID = Client.Self.AgentID; update.AgentData.SessionID = Client.Self.SessionID; update.AgentData.HeadRotation = HeadRotation; update.AgentData.BodyRotation = BodyRotation; update.AgentData.CameraAtAxis = yAxis; update.AgentData.CameraCenter = origin; update.AgentData.CameraLeftAxis = xAxis; update.AgentData.CameraUpAxis = zAxis; update.AgentData.Far = Camera.Far; update.AgentData.State = (byte)State; update.AgentData.ControlFlags = agentControls; update.AgentData.Flags = (byte)Flags; Client.Network.SendPacket(update, simulator); if (autoResetControls) { ResetControlFlags(); } } }
public void Yaw(float angle) { LLQuaternion q = new LLQuaternion(angle, zAxis); LLMatrix3 m = new LLMatrix3(q); Rotate(m); if (!xAxis.IsFinite() || !yAxis.IsFinite()) throw new Exception("Non-finite in CoordinateFrame.Yaw()"); }
/// <summary> /// Sends camera and action updates to the server including the /// position and orientation of our camera, and a ControlFlags field /// specifying our current movement actions /// </summary> /// <param name="reliable">Whether to ensure this packet makes it to the server</param> public void UpdateCamera(Avatar.AgentUpdateFlags controlFlags, LLVector3 position, LLVector3 forwardAxis, LLVector3 leftAxis, LLVector3 upAxis, LLQuaternion bodyRotation, LLQuaternion headRotation, float farClip, bool reliable) { AgentUpdatePacket update = new AgentUpdatePacket(); update.AgentData.AgentID = Client.Network.AgentID; update.AgentData.SessionID = Client.Network.SessionID; update.AgentData.State = 0; update.AgentData.BodyRotation = bodyRotation; update.AgentData.HeadRotation = headRotation; update.AgentData.CameraCenter = position; update.AgentData.CameraAtAxis = forwardAxis; update.AgentData.CameraLeftAxis = leftAxis; update.AgentData.CameraUpAxis = upAxis; update.AgentData.Far = farClip; update.AgentData.ControlFlags = (uint)controlFlags; update.AgentData.Flags = 0; update.Header.Reliable = reliable; Client.Network.SendPacket(update); }
/// <summary> /// Used for new prims, or significant changes to existing prims /// </summary> /// <param name="packet"></param> /// <param name="simulator"></param> protected void UpdateHandler(Packet packet, Simulator simulator) { ObjectUpdatePacket update = (ObjectUpdatePacket)packet; UpdateDilation(simulator, update.RegionData.TimeDilation); for (int b = 0; b < update.ObjectData.Length; b++) { ObjectUpdatePacket.ObjectDataBlock block = update.ObjectData[b]; LLVector4 collisionPlane = LLVector4.Zero; LLVector3 position; LLVector3 velocity; LLVector3 acceleration; LLQuaternion rotation; LLVector3 angularVelocity; NameValue[] nameValues; bool attachment = false; PCode pcode = (PCode)block.PCode; #region Relevance check // Check if we are interested in this object if (!Client.Settings.ALWAYS_DECODE_OBJECTS) { switch (pcode) { case PCode.Grass: case PCode.Tree: case PCode.NewTree: if (OnNewFoliage == null) continue; break; case PCode.Prim: if (OnNewPrim == null) continue; break; case PCode.Avatar: // Make an exception for updates about our own agent if (block.FullID != Client.Self.AgentID && OnNewAvatar == null) continue; break; case PCode.ParticleSystem: continue; // TODO: Do something with these } } #endregion Relevance check #region NameValue parsing string nameValue = Helpers.FieldToUTF8String(block.NameValue); if (nameValue.Length > 0) { string[] lines = nameValue.Split('\n'); nameValues = new NameValue[lines.Length]; for (int i = 0; i < lines.Length; i++) { if (!String.IsNullOrEmpty(lines[i])) { NameValue nv = new NameValue(lines[i]); if (nv.Name == "AttachItemID") attachment = true; nameValues[i] = nv; } } } else { nameValues = new NameValue[0]; } #endregion NameValue parsing #region Decode Object (primitive) parameters LLObject.ObjectData data = new LLObject.ObjectData(); data.State = block.State; data.Material = (LLObject.MaterialType)block.Material; data.PathCurve = (LLObject.PathCurve)block.PathCurve; data.profileCurve = block.ProfileCurve; data.PathBegin = LLObject.UnpackBeginCut(block.PathBegin); data.PathEnd = LLObject.UnpackEndCut(block.PathEnd); data.PathScaleX = LLObject.UnpackPathScale(block.PathScaleX); data.PathScaleY = LLObject.UnpackPathScale(block.PathScaleY); data.PathShearX = LLObject.UnpackPathShear((sbyte)block.PathShearX); data.PathShearY = LLObject.UnpackPathShear((sbyte)block.PathShearY); data.PathTwist = LLObject.UnpackPathTwist(block.PathTwist); data.PathTwistBegin = LLObject.UnpackPathTwist(block.PathTwistBegin); data.PathRadiusOffset = LLObject.UnpackPathTwist(block.PathRadiusOffset); data.PathTaperX = LLObject.UnpackPathTaper(block.PathTaperX); data.PathTaperY = LLObject.UnpackPathTaper(block.PathTaperY); data.PathRevolutions = LLObject.UnpackPathRevolutions(block.PathRevolutions); data.PathSkew = LLObject.UnpackPathTwist(block.PathSkew); data.ProfileBegin = LLObject.UnpackBeginCut(block.ProfileBegin); data.ProfileEnd = LLObject.UnpackEndCut(block.ProfileEnd); data.ProfileHollow = LLObject.UnpackProfileHollow(block.ProfileHollow); data.PCode = pcode; #endregion #region Decode Additional packed parameters in ObjectData int pos = 0; switch (block.ObjectData.Length) { case 76: // Collision normal for avatar collisionPlane = new LLVector4(block.ObjectData, pos); pos += 16; goto case 60; case 60: // Position position = new LLVector3(block.ObjectData, pos); pos += 12; // Velocity velocity = new LLVector3(block.ObjectData, pos); pos += 12; // Acceleration acceleration = new LLVector3(block.ObjectData, pos); pos += 12; // Rotation (theta) rotation = new LLQuaternion(block.ObjectData, pos, true); pos += 12; // Angular velocity (omega) angularVelocity = new LLVector3(block.ObjectData, pos); pos += 12; break; case 48: // Collision normal for avatar collisionPlane = new LLVector4(block.ObjectData, pos); pos += 16; goto case 32; case 32: // The data is an array of unsigned shorts // Position position = new LLVector3( Helpers.UInt16ToFloat(block.ObjectData, pos, -0.5f * 256.0f, 1.5f * 256.0f), Helpers.UInt16ToFloat(block.ObjectData, pos + 2, -0.5f * 256.0f, 1.5f * 256.0f), Helpers.UInt16ToFloat(block.ObjectData, pos + 4, -256.0f, 3.0f * 256.0f)); pos += 6; // Velocity velocity = new LLVector3( Helpers.UInt16ToFloat(block.ObjectData, pos, -256.0f, 256.0f), Helpers.UInt16ToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f), Helpers.UInt16ToFloat(block.ObjectData, pos + 4, -256.0f, 256.0f)); pos += 6; // Acceleration acceleration = new LLVector3( Helpers.UInt16ToFloat(block.ObjectData, pos, -256.0f, 256.0f), Helpers.UInt16ToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f), Helpers.UInt16ToFloat(block.ObjectData, pos + 4, -256.0f, 256.0f)); pos += 6; // Rotation (theta) rotation = new LLQuaternion( Helpers.UInt16ToFloat(block.ObjectData, pos, -1.0f, 1.0f), Helpers.UInt16ToFloat(block.ObjectData, pos + 2, -1.0f, 1.0f), Helpers.UInt16ToFloat(block.ObjectData, pos + 4, -1.0f, 1.0f), Helpers.UInt16ToFloat(block.ObjectData, pos + 6, -1.0f, 1.0f)); pos += 8; // Angular velocity (omega) angularVelocity = new LLVector3( Helpers.UInt16ToFloat(block.ObjectData, pos, -256.0f, 256.0f), Helpers.UInt16ToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f), Helpers.UInt16ToFloat(block.ObjectData, pos + 4, -256.0f, 256.0f)); pos += 6; break; case 16: // The data is an array of single bytes (8-bit numbers) // Position position = new LLVector3( Helpers.ByteToFloat(block.ObjectData, pos, -256.0f, 256.0f), Helpers.ByteToFloat(block.ObjectData, pos + 1, -256.0f, 256.0f), Helpers.ByteToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f)); pos += 3; // Velocity velocity = new LLVector3( Helpers.ByteToFloat(block.ObjectData, pos, -256.0f, 256.0f), Helpers.ByteToFloat(block.ObjectData, pos + 1, -256.0f, 256.0f), Helpers.ByteToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f)); pos += 3; // Accleration acceleration = new LLVector3( Helpers.ByteToFloat(block.ObjectData, pos, -256.0f, 256.0f), Helpers.ByteToFloat(block.ObjectData, pos + 1, -256.0f, 256.0f), Helpers.ByteToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f)); pos += 3; // Rotation rotation = new LLQuaternion( Helpers.ByteToFloat(block.ObjectData, pos, -1.0f, 1.0f), Helpers.ByteToFloat(block.ObjectData, pos + 1, -1.0f, 1.0f), Helpers.ByteToFloat(block.ObjectData, pos + 2, -1.0f, 1.0f), Helpers.ByteToFloat(block.ObjectData, pos + 3, -1.0f, 1.0f)); pos += 4; // Angular Velocity angularVelocity = new LLVector3( Helpers.ByteToFloat(block.ObjectData, pos, -256.0f, 256.0f), Helpers.ByteToFloat(block.ObjectData, pos + 1, -256.0f, 256.0f), Helpers.ByteToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f)); pos += 3; break; default: Client.Log("Got an ObjectUpdate block with ObjectUpdate field length of " + block.ObjectData.Length, Helpers.LogLevel.Warning); continue; } #endregion // Determine the object type and create the appropriate class switch (pcode) { #region Prim and Foliage case PCode.Grass: case PCode.Tree: case PCode.NewTree: case PCode.Prim: Primitive prim = GetPrimitive(simulator, block.ID, block.FullID); #region Update Prim Info with decoded data prim.Flags = (LLObject.ObjectFlags)block.UpdateFlags; if ((prim.Flags & LLObject.ObjectFlags.ZlibCompressed) != 0) { Client.Log("Got a ZlibCompressed ObjectUpdate, implement me!", Helpers.LogLevel.Warning); continue; } // Automatically request ObjectProperties for prim if it was rezzed selected. if ((prim.Flags & LLObject.ObjectFlags.CreateSelected) == LLObject.ObjectFlags.CreateSelected) SelectObject(simulator, prim.LocalID); prim.NameValues = nameValues; prim.LocalID = block.ID; prim.ID = block.FullID; prim.ParentID = block.ParentID; prim.RegionHandle = update.RegionData.RegionHandle; prim.Scale = block.Scale; prim.ClickAction = (ClickAction)block.ClickAction; prim.OwnerID = block.OwnerID; prim.MediaURL = Helpers.FieldToUTF8String(block.MediaURL); prim.Text = Helpers.FieldToUTF8String(block.Text); prim.TextColor = new LLColor(block.TextColor, 0, false); // Only alpha is inversed prim.TextColor.A = (byte)(1.0f - prim.TextColor.A); // Sound information prim.Sound = block.Sound; prim.SoundFlags = block.Flags; prim.SoundGain = block.Gain; prim.SoundRadius = block.Radius; // Joint information prim.Joint = (Primitive.JointType)block.JointType; prim.JointPivot = block.JointPivot; prim.JointAxisOrAnchor = block.JointAxisOrAnchor; // Object parameters prim.Data = data; // Textures, texture animations, particle system, and extra params prim.Textures = new LLObject.TextureEntry(block.TextureEntry, 0, block.TextureEntry.Length); prim.TextureAnim = new Primitive.TextureAnimation(block.TextureAnim, 0); prim.ParticleSys = new Primitive.ParticleSystem(block.PSBlock, 0); prim.SetExtraParamsFromBytes(block.ExtraParams, 0); // PCode-specific data prim.GenericData = block.Data; // Packed parameters prim.CollisionPlane = collisionPlane; prim.Position = position; prim.Velocity = velocity; prim.Acceleration = acceleration; prim.Rotation = rotation; prim.AngularVelocity = angularVelocity; #endregion if (attachment) FireOnNewAttachment(simulator, prim, update.RegionData.RegionHandle, update.RegionData.TimeDilation); else if (pcode == PCode.Prim) FireOnNewPrim(simulator, prim, update.RegionData.RegionHandle, update.RegionData.TimeDilation); else FireOnNewFoliage(simulator, prim, update.RegionData.RegionHandle, update.RegionData.TimeDilation); break; #endregion Prim and Foliage #region Avatar case PCode.Avatar: // Update some internals if this is our avatar if (block.FullID == Client.Self.AgentID) { #region Update Client.Self // We need the local ID to recognize terse updates for our agent Client.Self.localID = block.ID; // Packed parameters Client.Self.collisionPlane = collisionPlane; Client.Self.relativePosition = position; Client.Self.velocity = velocity; Client.Self.acceleration = acceleration; Client.Self.relativeRotation = rotation; Client.Self.angularVelocity = angularVelocity; #endregion } #region Create an Avatar from the decoded data Avatar avatar = GetAvatar(simulator, block.ID, block.FullID); uint oldSeatID = avatar.sittingOn; avatar.ID = block.FullID; avatar.LocalID = block.ID; avatar.CollisionPlane = collisionPlane; avatar.Position = position; avatar.Velocity = velocity; avatar.Acceleration = acceleration; avatar.Rotation = rotation; avatar.AngularVelocity = angularVelocity; avatar.NameValues = nameValues; avatar.Data = data; avatar.GenericData = block.Data; avatar.sittingOn = block.ParentID; SetAvatarSittingOn(simulator, avatar, block.ParentID, oldSeatID); // Set the current simulator for this avatar avatar.CurrentSim = simulator; // Textures avatar.Textures = new Primitive.TextureEntry(block.TextureEntry, 0, block.TextureEntry.Length); #endregion Create an Avatar from the decoded data FireOnNewAvatar(simulator, avatar, update.RegionData.RegionHandle, update.RegionData.TimeDilation); break; #endregion Avatar case PCode.ParticleSystem: DecodeParticleUpdate(block); // TODO: Create a callback for particle updates break; default: Client.DebugLog("Got an ObjectUpdate block with an unrecognized PCode " + pcode.ToString()); break; } } }
/// <summary> /// Rez an object from inventory /// </summary> /// <param name="simulator">Simulator to place object in</param> /// <param name="rotation">Rotation of the object when rezzed</param> /// <param name="position">Vector of where to place object</param> /// <param name="item">InventoryObject object containing item details</param> public LLUUID RequestRezFromInventory(Simulator simulator, LLQuaternion rotation, LLVector3 position, InventoryObject item) { return RequestRezFromInventory(simulator, rotation, position, item, _Client.Self.ActiveGroup, LLUUID.Random(), false); }
protected void InterpolationTimer_Elapsed(object obj) { if (Client.Network.Connected) { int interval = Environment.TickCount - Client.Self.lastInterpolation; float seconds = (float)interval / 1000f; // Iterate through all of the simulators lock (Client.Network.Simulators) { for (int i = 0; i < Client.Network.Simulators.Count; i++) { float adjSeconds = seconds * Client.Network.Simulators[i].Stats.Dilation; // Iterate through all of this sims avatars Client.Network.Simulators[i].ObjectsAvatars.ForEach( delegate(Avatar avatar) { #region Linear Motion // Only do movement interpolation (extrapolation) when there is a non-zero velocity but // no acceleration if (avatar.Acceleration != LLVector3.Zero && avatar.Velocity == LLVector3.Zero) { avatar.Position += (avatar.Velocity + (0.5f * (adjSeconds - HAVOK_TIMESTEP)) * avatar.Acceleration) * adjSeconds; avatar.Velocity += avatar.Acceleration * adjSeconds; } #endregion Linear Motion } ); // Iterate through all of this sims primitives Client.Network.Simulators[i].ObjectsPrimitives.ForEach( delegate(Primitive prim) { if (prim.Joint == Primitive.JointType.Invalid) { #region Angular Velocity LLVector3 angVel = prim.AngularVelocity; float omega = LLVector3.MagSquared(angVel); if (omega > 0.00001f) { omega = (float)Math.Sqrt(omega); float angle = omega * adjSeconds; angVel *= 1.0f / omega; LLQuaternion dQ = new LLQuaternion(angle, angVel); prim.Rotation *= dQ; } #endregion Angular Velocity #region Linear Motion // Only do movement interpolation (extrapolation) when there is a non-zero velocity but // no acceleration if (prim.Acceleration != LLVector3.Zero && prim.Velocity == LLVector3.Zero) { prim.Position += (prim.Velocity + (0.5f * (adjSeconds - HAVOK_TIMESTEP)) * prim.Acceleration) * adjSeconds; prim.Velocity += prim.Acceleration * adjSeconds; } #endregion Linear Motion } else if (prim.Joint == Primitive.JointType.Hinge) { //FIXME: Hinge movement extrapolation } else if (prim.Joint == Primitive.JointType.Point) { //FIXME: Point movement extrapolation } else { Client.Log("Unhandled joint type " + prim.Joint, Helpers.LogLevel.Warning); } } ); } } // Make sure the last interpolated time is always updated Client.Self.lastInterpolation = Environment.TickCount; } }
/// <summary> /// Rez an object from inventory /// </summary> /// <param name="simulator">Simulator to place object in</param> /// <param name="rotation">Rotation of the object when rezzed</param> /// <param name="position">Vector of where to place object</param> /// <param name="item">InventoryObject object containing item details</param> /// <param name="groupOwner">LLUUID of group to own the object</param> /// <param name="queryID">User defined queryID to correlate replies</param> /// <param name="requestObjectDetails">if set to true the simulator /// will automatically send object detail packet(s) back to the client</param> public LLUUID RequestRezFromInventory(Simulator simulator, LLQuaternion rotation, LLVector3 position, InventoryObject item, LLUUID groupOwner, LLUUID queryID, bool requestObjectDetails) { RezObjectPacket add = new RezObjectPacket(); add.AgentData.AgentID = _Client.Self.AgentID; add.AgentData.SessionID = _Client.Self.SessionID; add.AgentData.GroupID = groupOwner; add.RezData.FromTaskID = LLUUID.Zero; add.RezData.BypassRaycast = 1; add.RezData.RayStart = position; add.RezData.RayEnd = position; add.RezData.RayTargetID = LLUUID.Zero; add.RezData.RayEndIsIntersection = false; add.RezData.RezSelected = requestObjectDetails; add.RezData.RemoveItem = false; add.RezData.ItemFlags = item.Flags; add.RezData.GroupMask = (uint)item.Permissions.GroupMask; add.RezData.EveryoneMask = (uint)item.Permissions.EveryoneMask; add.RezData.NextOwnerMask = (uint)item.Permissions.NextOwnerMask; add.InventoryData.ItemID = item.UUID; add.InventoryData.FolderID = item.ParentUUID; add.InventoryData.CreatorID = item.CreatorID; add.InventoryData.OwnerID = item.OwnerID; add.InventoryData.GroupID = item.GroupID; add.InventoryData.BaseMask = (uint)item.Permissions.BaseMask; add.InventoryData.OwnerMask = (uint)item.Permissions.OwnerMask; add.InventoryData.GroupMask = (uint)item.Permissions.GroupMask; add.InventoryData.EveryoneMask = (uint)item.Permissions.EveryoneMask; add.InventoryData.NextOwnerMask = (uint)item.Permissions.NextOwnerMask; add.InventoryData.GroupOwned = item.GroupOwned; add.InventoryData.TransactionID = queryID; add.InventoryData.Type = (sbyte)item.InventoryType; add.InventoryData.InvType = (sbyte)item.InventoryType; add.InventoryData.Flags = item.Flags; add.InventoryData.SaleType = (byte)item.SaleType; add.InventoryData.SalePrice = item.SalePrice; add.InventoryData.Name = Helpers.StringToField(item.Name); add.InventoryData.Description = Helpers.StringToField(item.Description); add.InventoryData.CreationDate = (int)Helpers.DateTimeToUnixTime(item.CreationDate); _Client.Network.SendPacket(add, simulator); return queryID; }
public static Primitive FromLLSD(LLSD llsd) { Primitive prim = new Primitive(); LLObject.ObjectData data = new ObjectData(); LLSDMap map = (LLSDMap)llsd; LLSDMap volume = (LLSDMap)map["volume"]; LLSDMap path = (LLSDMap)volume["path"]; LLSDMap profile = (LLSDMap)volume["profile"]; #region Path/Profile data.PathBegin = (float)path["begin"].AsReal(); data.PathCurve = (PathCurve)path["curve"].AsInteger(); data.PathEnd = (float)path["end"].AsReal(); data.PathRadiusOffset = (float)path["radius_offset"].AsReal(); data.PathRevolutions = (float)path["revolutions"].AsReal(); data.PathScaleX = (float)path["scale_x"].AsReal(); data.PathScaleY = (float)path["scale_y"].AsReal(); data.PathShearX = (float)path["shear_x"].AsReal(); data.PathShearY = (float)path["shear_y"].AsReal(); data.PathSkew = (float)path["skew"].AsReal(); data.PathTaperX = (float)path["taper_x"].AsReal(); data.PathTaperY = (float)path["taper_y"].AsReal(); data.PathTwist = path["twist"].AsInteger(); data.PathTwistBegin = path["twist_begin"].AsInteger(); data.ProfileBegin = (float)profile["begin"].AsReal(); data.ProfileCurve = (ProfileCurve)profile["curve"].AsInteger(); data.ProfileHole = (HoleType)profile["hole"].AsInteger(); data.ProfileEnd = (float)profile["end"].AsReal(); data.ProfileHollow = (float)profile["hollow"].AsReal(); #endregion Path/Profile prim.Data = data; if (map["phantom"].AsBoolean()) { prim.Flags |= ObjectFlags.Phantom; } if (map["physical"].AsBoolean()) { prim.Flags |= ObjectFlags.Physics; } if (map["shadows"].AsBoolean()) { prim.Flags |= ObjectFlags.CastShadows; } prim.ParentID = (uint)map["parentid"].AsInteger(); prim.Position = LLVector3.FromLLSD(map["position"]); prim.Rotation = LLQuaternion.FromLLSD(map["rotation"]); prim.Scale = LLVector3.FromLLSD(map["scale"]); prim.Flexible = FlexibleData.FromLLSD(map["flexible"]); prim.Light = LightData.FromLLSD(map["light"]); prim.Sculpt = SculptData.FromLLSD(map["sculpt"]); prim.Textures = TextureEntry.FromLLSD(map["textures"]); return(prim); }