public static NameValue[] ParseNameValues(string text) { // Parse the name values if (text.Length > 0) { if (text == "\n") { return(new NameValue[0]); } string[] lines = text.Split('\n'); var NameValues = new NameValue[lines.Length]; for (int j = 0; j < lines.Length; j++) { if (!String.IsNullOrEmpty(lines[j])) { NameValue nv = new NameValue(lines[j]); NameValues[j] = nv; } } return(NameValues); } return(null); }
public static string NameValuesToString(NameValue[] values) { if (values == null) { return(String.Empty); } if (values.Length == 0) { return("\n"); } StringBuilder output = new StringBuilder(); for (int i = 0; i < values.Length; i++) { NameValue value = values[i]; if (value.Value != null) { string newLine = (i < values.Length - 1) ? "\n" : String.Empty; output.AppendFormat("{0} {1} {2} {3} {4}{5}", value.Name, TypeStrings[(int)value.Type], ClassStrings[(int)value.Class], SendtoStrings[(int)value.Sendto], value.Value.ToString(), newLine); } } return(output.ToString()); }
void CompleteAgentMovementHandler(Packet packet, Agent agent) { CompleteAgentMovementPacket request = (CompleteAgentMovementPacket)packet; // Create a representation for this agent Avatar avatar = new Avatar(); avatar.ID = agent.AgentID; avatar.LocalID = (uint)Interlocked.Increment(ref currentLocalID); avatar.Position = new Vector3(128f, 128f, 25f); avatar.Rotation = Quaternion.Identity; avatar.Scale = new Vector3(1f, 1f, 3f); // Set the avatar name NameValue[] name = new NameValue[2]; name[0] = new NameValue("FirstName", NameValue.ValueType.String, NameValue.ClassType.ReadWrite, NameValue.SendtoType.SimViewer, agent.FirstName); name[1] = new NameValue("LastName", NameValue.ValueType.String, NameValue.ClassType.ReadWrite, NameValue.SendtoType.SimViewer, agent.LastName); avatar.NameValues = name; // Link this avatar up with the corresponding agent agent.Avatar = avatar; // Give testers a provisionary balance of 1000L agent.Balance = 1000; AgentMovementCompletePacket complete = new AgentMovementCompletePacket(); complete.AgentData.AgentID = agent.AgentID; complete.AgentData.SessionID = agent.SessionID; complete.Data.LookAt = Vector3.UnitX; complete.Data.Position = avatar.Position; complete.Data.RegionHandle = server.RegionHandle; complete.Data.Timestamp = Utils.DateTimeToUnixTime(DateTime.Now); complete.SimData.ChannelVersion = Utils.StringToBytes("Simian"); agent.SendPacket(complete); SendLayerData(agent); }
/// <summary>Process an incoming packet and raise the appropriate events</summary> /// <param name="sender">The sender</param> /// <param name="e">The EventArgs object containing the packet data</param> protected void ObjectUpdateHandler(object sender, PacketReceivedEventArgs e) { Packet packet = e.Packet; Simulator simulator = e.Simulator; ObjectUpdatePacket update = (ObjectUpdatePacket)packet; UpdateDilation(e.Simulator, update.RegionData.TimeDilation); for (int b = 0; b < update.ObjectData.Length; b++) { ObjectUpdatePacket.ObjectDataBlock block = update.ObjectData[b]; ObjectMovementUpdate objectupdate = new ObjectMovementUpdate(); //Vector4 collisionPlane = Vector4.Zero; //Vector3 position; //Vector3 velocity; //Vector3 acceleration; //Quaternion rotation; //Vector3 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: case PCode.Prim: if (m_ObjectUpdate == null) continue; break; case PCode.Avatar: // Make an exception for updates about our own agent if (block.FullID != Client.Self.AgentID && m_AvatarUpdate == null) continue; break; case PCode.ParticleSystem: continue; // TODO: Do something with these } } #endregion Relevance check #region NameValue parsing string nameValue = Utils.BytesToString(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 Primitive.ConstructionData data = new Primitive.ConstructionData(); data.State = block.State; data.Material = (Material)block.Material; data.PathCurve = (PathCurve)block.PathCurve; data.profileCurve = block.ProfileCurve; data.PathBegin = Primitive.UnpackBeginCut(block.PathBegin); data.PathEnd = Primitive.UnpackEndCut(block.PathEnd); data.PathScaleX = Primitive.UnpackPathScale(block.PathScaleX); data.PathScaleY = Primitive.UnpackPathScale(block.PathScaleY); data.PathShearX = Primitive.UnpackPathShear((sbyte)block.PathShearX); data.PathShearY = Primitive.UnpackPathShear((sbyte)block.PathShearY); data.PathTwist = Primitive.UnpackPathTwist(block.PathTwist); data.PathTwistBegin = Primitive.UnpackPathTwist(block.PathTwistBegin); data.PathRadiusOffset = Primitive.UnpackPathTwist(block.PathRadiusOffset); data.PathTaperX = Primitive.UnpackPathTaper(block.PathTaperX); data.PathTaperY = Primitive.UnpackPathTaper(block.PathTaperY); data.PathRevolutions = Primitive.UnpackPathRevolutions(block.PathRevolutions); data.PathSkew = Primitive.UnpackPathTwist(block.PathSkew); data.ProfileBegin = Primitive.UnpackBeginCut(block.ProfileBegin); data.ProfileEnd = Primitive.UnpackEndCut(block.ProfileEnd); data.ProfileHollow = Primitive.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 objectupdate.CollisionPlane = new Vector4(block.ObjectData, pos); pos += 16; goto case 60; case 60: // Position objectupdate.Position = new Vector3(block.ObjectData, pos); pos += 12; // Velocity objectupdate.Velocity = new Vector3(block.ObjectData, pos); pos += 12; // Acceleration objectupdate.Acceleration = new Vector3(block.ObjectData, pos); pos += 12; // Rotation (theta) objectupdate.Rotation = new Quaternion(block.ObjectData, pos, true); pos += 12; // Angular velocity (omega) objectupdate.AngularVelocity = new Vector3(block.ObjectData, pos); pos += 12; break; case 48: // Collision normal for avatar objectupdate.CollisionPlane = new Vector4(block.ObjectData, pos); pos += 16; goto case 32; case 32: // The data is an array of unsigned shorts // Position objectupdate.Position = new Vector3( Utils.UInt16ToFloat(block.ObjectData, pos, -0.5f * 256.0f, 1.5f * 256.0f), Utils.UInt16ToFloat(block.ObjectData, pos + 2, -0.5f * 256.0f, 1.5f * 256.0f), Utils.UInt16ToFloat(block.ObjectData, pos + 4, -256.0f, 3.0f * 256.0f)); pos += 6; // Velocity objectupdate.Velocity = new Vector3( Utils.UInt16ToFloat(block.ObjectData, pos, -256.0f, 256.0f), Utils.UInt16ToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f), Utils.UInt16ToFloat(block.ObjectData, pos + 4, -256.0f, 256.0f)); pos += 6; // Acceleration objectupdate.Acceleration = new Vector3( Utils.UInt16ToFloat(block.ObjectData, pos, -256.0f, 256.0f), Utils.UInt16ToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f), Utils.UInt16ToFloat(block.ObjectData, pos + 4, -256.0f, 256.0f)); pos += 6; // Rotation (theta) objectupdate.Rotation = new Quaternion( Utils.UInt16ToFloat(block.ObjectData, pos, -1.0f, 1.0f), Utils.UInt16ToFloat(block.ObjectData, pos + 2, -1.0f, 1.0f), Utils.UInt16ToFloat(block.ObjectData, pos + 4, -1.0f, 1.0f), Utils.UInt16ToFloat(block.ObjectData, pos + 6, -1.0f, 1.0f)); pos += 8; // Angular velocity (omega) objectupdate.AngularVelocity = new Vector3( Utils.UInt16ToFloat(block.ObjectData, pos, -256.0f, 256.0f), Utils.UInt16ToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f), Utils.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 objectupdate.Position = new Vector3( Utils.ByteToFloat(block.ObjectData, pos, -256.0f, 256.0f), Utils.ByteToFloat(block.ObjectData, pos + 1, -256.0f, 256.0f), Utils.ByteToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f)); pos += 3; // Velocity objectupdate.Velocity = new Vector3( Utils.ByteToFloat(block.ObjectData, pos, -256.0f, 256.0f), Utils.ByteToFloat(block.ObjectData, pos + 1, -256.0f, 256.0f), Utils.ByteToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f)); pos += 3; // Accleration objectupdate.Acceleration = new Vector3( Utils.ByteToFloat(block.ObjectData, pos, -256.0f, 256.0f), Utils.ByteToFloat(block.ObjectData, pos + 1, -256.0f, 256.0f), Utils.ByteToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f)); pos += 3; // Rotation objectupdate.Rotation = new Quaternion( Utils.ByteToFloat(block.ObjectData, pos, -1.0f, 1.0f), Utils.ByteToFloat(block.ObjectData, pos + 1, -1.0f, 1.0f), Utils.ByteToFloat(block.ObjectData, pos + 2, -1.0f, 1.0f), Utils.ByteToFloat(block.ObjectData, pos + 3, -1.0f, 1.0f)); pos += 4; // Angular Velocity objectupdate.AngularVelocity = new Vector3( Utils.ByteToFloat(block.ObjectData, pos, -256.0f, 256.0f), Utils.ByteToFloat(block.ObjectData, pos + 1, -256.0f, 256.0f), Utils.ByteToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f)); pos += 3; break; default: Logger.Log("Got an ObjectUpdate block with ObjectUpdate field length of " + block.ObjectData.Length, Helpers.LogLevel.Warning, Client); 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: bool isNewObject; lock (simulator.ObjectsPrimitives.Dictionary) isNewObject = !simulator.ObjectsPrimitives.ContainsKey(block.ID); Primitive prim = GetPrimitive(simulator, block.ID, block.FullID); // Textures objectupdate.Textures = new Primitive.TextureEntry(block.TextureEntry, 0, block.TextureEntry.Length); OnObjectDataBlockUpdate(new ObjectDataBlockUpdateEventArgs(simulator, prim, data, block, objectupdate, nameValues)); #region Update Prim Info with decoded data prim.Flags = (PrimFlags)block.UpdateFlags; if ((prim.Flags & PrimFlags.ZlibCompressed) != 0) { Logger.Log("Got a ZlibCompressed ObjectUpdate, implement me!", Helpers.LogLevel.Warning, Client); continue; } // Automatically request ObjectProperties for prim if it was rezzed selected. if ((prim.Flags & PrimFlags.CreateSelected) != 0) { 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 = Utils.BytesToString(block.MediaURL); prim.Text = Utils.BytesToString(block.Text); prim.TextColor = new Color4(block.TextColor, 0, false, true); // Sound information prim.Sound = block.Sound; prim.SoundFlags = (SoundFlags)block.Flags; prim.SoundGain = block.Gain; prim.SoundRadius = block.Radius; // Joint information prim.Joint = (JointType)block.JointType; prim.JointPivot = block.JointPivot; prim.JointAxisOrAnchor = block.JointAxisOrAnchor; // Object parameters prim.PrimData = data; // Textures, texture animations, particle system, and extra params prim.Textures = objectupdate.Textures; prim.TextureAnim = new Primitive.TextureAnimation(block.TextureAnim, 0); prim.ParticleSys = new Primitive.ParticleSystem(block.PSBlock, 0); prim.SetExtraParamsFromBytes(block.ExtraParams, 0); // PCode-specific data switch (pcode) { case PCode.Grass: case PCode.Tree: case PCode.NewTree: if (block.Data.Length == 1) prim.TreeSpecies = (Tree)block.Data[0]; else Logger.Log("Got a foliage update with an invalid TreeSpecies field", Helpers.LogLevel.Warning); // prim.ScratchPad = Utils.EmptyBytes; // break; //default: // prim.ScratchPad = new byte[block.Data.Length]; // if (block.Data.Length > 0) // Buffer.BlockCopy(block.Data, 0, prim.ScratchPad, 0, prim.ScratchPad.Length); break; } prim.ScratchPad = Utils.EmptyBytes; // Packed parameters prim.CollisionPlane = objectupdate.CollisionPlane; prim.Position = objectupdate.Position; prim.Velocity = objectupdate.Velocity; prim.Acceleration = objectupdate.Acceleration; prim.Rotation = objectupdate.Rotation; prim.AngularVelocity = objectupdate.AngularVelocity; #endregion OnObjectUpdate(new PrimEventArgs(simulator, prim, update.RegionData.TimeDilation, isNewObject, attachment)); break; #endregion Prim and Foliage #region Avatar case PCode.Avatar: bool isNewAvatar; lock (simulator.ObjectsAvatars.Dictionary) isNewAvatar = !simulator.ObjectsAvatars.ContainsKey(block.ID); // Update some internals if this is our avatar if (block.FullID == Client.Self.AgentID && simulator == Client.Network.CurrentSim) { #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 = objectupdate.CollisionPlane; Client.Self.relativePosition = objectupdate.Position; Client.Self.velocity = objectupdate.Velocity; Client.Self.acceleration = objectupdate.Acceleration; Client.Self.relativeRotation = objectupdate.Rotation; Client.Self.angularVelocity = objectupdate.AngularVelocity; #endregion } #region Create an Avatar from the decoded data Avatar avatar = GetAvatar(simulator, block.ID, block.FullID); objectupdate.Avatar = true; // Textures objectupdate.Textures = new Primitive.TextureEntry(block.TextureEntry, 0, block.TextureEntry.Length); OnObjectDataBlockUpdate(new ObjectDataBlockUpdateEventArgs(simulator, avatar, data, block, objectupdate, nameValues)); uint oldSeatID = avatar.ParentID; avatar.ID = block.FullID; avatar.LocalID = block.ID; avatar.CollisionPlane = objectupdate.CollisionPlane; avatar.Position = objectupdate.Position; avatar.Velocity = objectupdate.Velocity; avatar.Acceleration = objectupdate.Acceleration; avatar.Rotation = objectupdate.Rotation; avatar.AngularVelocity = objectupdate.AngularVelocity; avatar.NameValues = nameValues; avatar.PrimData = data; if (block.Data.Length > 0) { Logger.Log("Unexpected Data field for an avatar update, length " + block.Data.Length, Helpers.LogLevel.Warning); } avatar.ParentID = block.ParentID; avatar.RegionHandle = update.RegionData.RegionHandle; SetAvatarSittingOn(simulator, avatar, block.ParentID, oldSeatID); // Textures avatar.Textures = objectupdate.Textures; #endregion Create an Avatar from the decoded data OnAvatarUpdate(new AvatarUpdateEventArgs(simulator, avatar, update.RegionData.TimeDilation, isNewAvatar)); break; #endregion Avatar case PCode.ParticleSystem: DecodeParticleUpdate(block); // TODO: Create a callback for particle updates break; default: Logger.DebugLog("Got an ObjectUpdate block with an unrecognized PCode " + pcode.ToString(), Client); break; } } }
public static new Avatar FromOSD(OSD O) { OSDMap tex = (OSDMap)O; Avatar A = new Avatar(); Primitive P = Primitive.FromOSD(O); Type Prim = typeof(Primitive); FieldInfo[] Fields = Prim.GetFields(); for (int x = 0; x < Fields.Length; x++) { Logger.Log("Field Matched in FromOSD: "+Fields[x].Name, Helpers.LogLevel.Debug); Fields[x].SetValue(A, Fields[x].GetValue(P)); } A.Groups = new List<UUID>(); foreach (OSD U in (OSDArray)tex["groups"]) { A.Groups.Add(U.AsUUID()); } A.ProfileStatistics = Statistics.FromOSD(tex["profile_statistics"]); A.ProfileProperties = AvatarProperties.FromOSD(tex["profile_properties"]); A.ProfileInterests = Interests.FromOSD(tex["profile_interest"]); A.ControlFlags = (AgentManager.ControlFlags)tex["control_flags"].AsInteger(); OSDArray vp = (OSDArray)tex["visual_parameters"]; A.VisualParameters = new byte[vp.Count]; for (int i = 0; i < vp.Count; i++) { A.VisualParameters[i] = (byte)vp[i].AsInteger(); } // *********************From Code Above ******************************* /*if (NameValues[i].Name == "FirstName" && NameValues[i].Type == NameValue.ValueType.String) firstName = (string)NameValues[i].Value; else if (NameValues[i].Name == "LastName" && NameValues[i].Type == NameValue.ValueType.String) lastName = (string)NameValues[i].Value;*/ // ******************************************************************** A.NameValues = new NameValue[3]; NameValue First = new NameValue(); First.Name = "FirstName"; First.Type = NameValue.ValueType.String; First.Value = tex["first_name"].AsString(); NameValue Last = new NameValue(); Last.Name = "LastName"; Last.Type = NameValue.ValueType.String; Last.Value = tex["last_name"].AsString(); // ***************From Code Above*************** // if (NameValues[i].Name == "Title" && NameValues[i].Type == NameValue.ValueType.String) // ********************************************* NameValue Group = new NameValue(); Group.Name = "Title"; Group.Type = NameValue.ValueType.String; Group.Value = tex["group_name"].AsString(); A.NameValues[0] = First; A.NameValues[1] = Last; A.NameValues[2] = Group; return A; }
public static new Avatar FromOSD(OSD O) { OSDMap tex = (OSDMap)O; Avatar A = new Avatar(); Primitive P = Primitive.FromOSD(O); Type Prim = typeof(Primitive); FieldInfo[] Fields = Prim.GetFields(); for (int x = 0; x < Fields.Length; x++) { Logger.Log("Field Matched in FromOSD: " + Fields[x].Name, Helpers.LogLevel.Debug); Fields[x].SetValue(A, Fields[x].GetValue(P)); } A.Groups = new List <UUID>(); foreach (OSD U in (OSDArray)tex["groups"]) { A.Groups.Add(U.AsUUID()); } A.ProfileStatistics = Statistics.FromOSD(tex["profile_statistics"]); A.ProfileProperties = AvatarProperties.FromOSD(tex["profile_properties"]); A.ProfileInterests = Interests.FromOSD(tex["profile_interest"]); A.ControlFlags = (AgentManager.ControlFlags)tex["control_flags"].AsInteger(); OSDArray vp = (OSDArray)tex["visual_parameters"]; A.VisualParameters = new byte[vp.Count]; for (int i = 0; i < vp.Count; i++) { A.VisualParameters[i] = (byte)vp[i].AsInteger(); } // *********************From Code Above ******************************* /*if (NameValues[i].Name == "FirstName" && NameValues[i].Type == NameValue.ValueType.String) * firstName = (string)NameValues[i].Value; * else if (NameValues[i].Name == "LastName" && NameValues[i].Type == NameValue.ValueType.String) * lastName = (string)NameValues[i].Value;*/ // ******************************************************************** A.NameValues = new NameValue[3]; NameValue First = new NameValue(); First.Name = "FirstName"; First.Type = NameValue.ValueType.String; First.Value = tex["first_name"].AsString(); NameValue Last = new NameValue(); Last.Name = "LastName"; Last.Type = NameValue.ValueType.String; Last.Value = tex["last_name"].AsString(); // ***************From Code Above*************** // if (NameValues[i].Name == "Title" && NameValues[i].Type == NameValue.ValueType.String) // ********************************************* NameValue Group = new NameValue(); Group.Name = "Title"; Group.Type = NameValue.ValueType.String; Group.Value = tex["group_name"].AsString(); A.NameValues[0] = First; A.NameValues[1] = Last; A.NameValues[2] = Group; return(A); }
public ObjectUpdatePacket.ObjectDataBlock modBlock(ObjectUpdatePacket.ObjectDataBlock block) { string FirstName = null; string LastName = null; string Title = null; string[] namevalues = Utils.BytesToString(block.NameValue).Split("\r\n".ToCharArray()); foreach (string line in namevalues) { NameValue namevalue = new NameValue(line); if (namevalue.Value != null) { if (namevalue.Name == "FirstName") { FirstName = Convert.ToString(namevalue.Value); if (avclients.ContainsKey(block.FullID)) { if (avclients[block.FullID] == "") { } else { if (form.Display()) FirstName = "(" + avclients[block.FullID] + ") " + FirstName; } namevalue.Value = FirstName; } else { blocks.Add(block.FullID, block); } } else if (namevalue.Name == "LastName") { LastName = Convert.ToString(namevalue.Value); } else if (namevalue.Name == "Title") { Title = Convert.ToString(namevalue.Value); } } } string newname = ""; if (FirstName != null) { if (newname != "") newname += "\r\n"; newname += "FirstName STRING RW SV " + FirstName; } if (LastName != null) { if (newname != "") newname += "\n"; newname += "LastName STRING RW SV " + LastName; } if (Title != null) { if (newname != "") newname += "\r\n"; newname += "Title STRING RW SV " + Title; } block.NameValue = Utils.StringToBytes(newname); //writethis("\n" + block.FullID.ToString() + "\n" + newname, ConsoleColor.White, ConsoleColor.Green); return block; }
public Packet inObj(Packet packet, IPEndPoint sim) { string simIP = sim.ToString(); if (!lastSim.Equals(simIP)) { lastSim = simIP; avclients.Clear(); } ObjectUpdatePacket ObjectUpdate = (ObjectUpdatePacket)packet; foreach (ObjectUpdatePacket.ObjectDataBlock block in ObjectUpdate.ObjectData) { if ((block.PCode == 0x2f) && (block.FullID!=frame.AgentID)) // Avatars only { //writethis("\n\n-----------\n------\n---\n" + block.ToString(),ConsoleColor.White,ConsoleColor.DarkBlue); string FirstName = null; string LastName = null; string Title = null; #region decode name if (block.NameValue != null) { if(local2global.ContainsKey(block.ID)) { local2global[block.ID]=block.FullID; }else { local2global.Add(block.ID,block.FullID); } string[] namevalues = Utils.BytesToString(block.NameValue).Split("\r\n".ToCharArray()); foreach (string line in namevalues) { NameValue namevalue = new NameValue(line); if (namevalue.Value != null) { if (namevalue.Name == "FirstName") { FirstName = Convert.ToString(namevalue.Value); if (avclients.ContainsKey(block.FullID)) { if (avclients[block.FullID] == "") { } else { if(form.Display()) FirstName = "(" + avclients[block.FullID] + ") " + FirstName; } namevalue.Value = FirstName; } else { if (!blocks.ContainsKey(block.FullID)) { blocks.Add(block.FullID, block); rb = ObjectUpdate.RegionData; } } } else if (namevalue.Name == "LastName") { LastName = Convert.ToString(namevalue.Value); } else if (namevalue.Name == "Title") { Title = Convert.ToString(namevalue.Value); } } } string newname = ""; if (FirstName != null) { if (newname != "") newname += "\r\n"; newname += "FirstName STRING RW SV " + FirstName; } if (LastName != null) { if (newname != "") newname += "\n"; newname += "LastName STRING RW SV " + LastName; } if (Title != null) { if (newname != "") newname += "\n"; newname += "Title STRING RW SV " + Title; } block.NameValue = Utils.StringToBytes(newname); //writethis("\n" + block.FullID.ToString() + "\n" + newname, ConsoleColor.White, ConsoleColor.DarkGreen); } #endregion } } return ObjectUpdate; }
private void ObjectDataBlockUpdateHandler(Simulator simulator, Primitive prim, Primitive.ConstructionData constructionData, ObjectUpdatePacket.ObjectDataBlock block, ObjectUpdate update, NameValue[] nameValues) { // Note: We can't do membership or really much useful here since the // primitive doesn't have its information filled in quite yet. Instead, // we're forced to use the OnNew* events, which get called *after* all // the data has been filled in. //Console.WriteLine("Object: " + update.LocalID.ToString() + " - " + update.Position.ToString() + " " + update.Velocity.ToString()); }
public static string NameValuesToString(NameValue[] values) { if (values == null || values.Length == 0) return String.Empty; StringBuilder output = new StringBuilder(); for (int i = 0; i < values.Length; i++) { NameValue value = values[i]; if (value.Value != null) { string newLine = (i < values.Length - 1) ? "\n" : String.Empty; output.AppendFormat("{0} {1} {2} {3} {4}{5}", value.Name, TypeStrings[(int)value.Type], ClassStrings[(int)value.Class], SendtoStrings[(int)value.Sendto], value.Value.ToString(), newLine); } } return output.ToString(); }
public static string NameValuesToString(NameValue[] values) { if (values == null || values.Length == 0) return String.Empty; // Set the culture to en-US to print out values in the format SL is expecting them System.Globalization.CultureInfo culture = System.Threading.Thread.CurrentThread.CurrentCulture; System.Threading.Thread.CurrentThread.CurrentCulture = Utils.EnUsCulture; StringBuilder output = new StringBuilder(); for (int i = 0; i < values.Length; i++) { NameValue value = values[i]; if (value.Value != null) { string newLine = (i < values.Length - 1) ? "\n" : String.Empty; output.AppendFormat("{0} {1} {2} {3} {4}{5}", value.Name, TypeStrings[(int)value.Type], ClassStrings[(int)value.Class], SendtoStrings[(int)value.Sendto], value.Value.ToString(), newLine); } } // Set the culture back System.Threading.Thread.CurrentThread.CurrentCulture = culture; return output.ToString(); }
private Packet InObjectUpdateHandler(Packet packet, IPEndPoint sim) { string simIP = sim.ToString(); ObjectUpdatePacket ObjectUpdate = (ObjectUpdatePacket)packet; foreach (ObjectUpdatePacket.ObjectDataBlock block in ObjectUpdate.ObjectData) { if (block.PCode == 0x2f) // Avatars only { // If this simulator doesn't exist, create it if (!SharedInfo.Aux_Simulators.ContainsKey(simIP)) { SharedInfo.Aux_Simulators.Add(simIP, new PubComb.Aux_Simulator(simIP)); } Vector3 position = new Vector3(); #region decode position switch (block.ObjectData.Length) { case 76: position = new Vector3(block.ObjectData, 16); break; case 60: position = new Vector3(block.ObjectData, 0); break; case 32: // The data is an array of unsigned shorts position = new Vector3( Utils.UInt16ToFloat(block.ObjectData, 0, -0.5f * 256.0f, 1.5f * 256.0f), Utils.UInt16ToFloat(block.ObjectData, 2, -0.5f * 256.0f, 1.5f * 256.0f), Utils.UInt16ToFloat(block.ObjectData, 4, -256.0f, 3.0f * 256.0f)); break; case 16: // The data is an array of single bytes (8-bit numbers) position = new Vector3( Utils.ByteToFloat(block.ObjectData, 0, -256.0f, 256.0f), Utils.ByteToFloat(block.ObjectData, 1, -256.0f, 256.0f), Utils.ByteToFloat(block.ObjectData, 2, -256.0f, 256.0f)); break; default: plugin.SayToUser("Couldn't decode position, the data was " + block.ObjectData.Length.ToString() + " bytes long."); break; } #endregion string FirstName = null; string LastName = null; #region decode name if (block.NameValue != null) { string[] namevalues = Utils.BytesToString(block.NameValue).Split("\r\n".ToCharArray()); foreach (string line in namevalues) { NameValue namevalue = new NameValue(line); if (namevalue.Value != null) { if (namevalue.Name == "FirstName") { FirstName = Convert.ToString(namevalue.Value); } else if (namevalue.Name == "LastName") { LastName = Convert.ToString(namevalue.Value); } } } } string name = ""; if (FirstName != null) name += FirstName; else name += "(Waiting)"; name += " "; if (LastName != null) name += LastName; else name += "(Waiting)"; #endregion PubComb.Aux_Avatar avatar = new PubComb.Aux_Avatar(block.FullID, simIP, block.ID, name, position); if (!SharedInfo.Aux_Simulators[simIP].Avatars.ContainsKey(block.FullID)) { // Add avatar to simulator SharedInfo.Aux_Simulators[simIP].Avatars.Add(block.FullID, avatar); form.AddAvatar(avatar); } else { // Just update the avatar's position SharedInfo.Aux_Simulators[simIP].Avatars[block.FullID].Position = position; form.UpdateAvatar(avatar); } if (avatar.UUID == frame.AgentID) { SharedInfo.AgentName = name; SharedInfo.AvPosition = position; } } } return packet; }
protected void FireOnObjectDataBlockUpdate(Simulator simulator, Primitive primitive, Primitive.ConstructionData data, ObjectUpdatePacket.ObjectDataBlock block, ObjectUpdate objectupdate, NameValue[] nameValue) { if (OnObjectDataBlockUpdate != null) { try { OnObjectDataBlockUpdate(simulator, primitive, data, block, objectupdate, nameValue); } catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); } } }
public bool AgentAdd(object sender, Agent agent, PrimFlags creatorFlags) { // Sanity check, since this should have already been done agent.Avatar.Prim.ID = agent.Info.ID; // Check if the agent already exists in the scene lock (sceneAgents) { if (sceneAgents.ContainsKey(agent.ID)) sceneAgents.Remove(agent.ID); } // Update the current region handle agent.Avatar.Prim.RegionHandle = regionHandle; // Avatars always have physics agent.Avatar.Prim.Flags |= PrimFlags.Physics; // Default avatar values agent.Avatar.Prim.Position = new Vector3(128f, 128f, 25f); agent.Avatar.Prim.Rotation = Quaternion.Identity; agent.Avatar.Prim.Scale = new Vector3(0.45f, 0.6f, 1.9f); agent.Avatar.Prim.PrimData.Material = Material.Flesh; agent.Avatar.Prim.PrimData.PCode = PCode.Avatar; agent.Avatar.Prim.Textures = new Primitive.TextureEntry(new UUID("c228d1cf-4b5d-4ba8-84f4-899a0796aa97")); // Set the avatar name NameValue[] name = new NameValue[2]; name[0] = new NameValue("FirstName", NameValue.ValueType.String, NameValue.ClassType.ReadWrite, NameValue.SendtoType.SimViewer, agent.Info.FirstName); name[1] = new NameValue("LastName", NameValue.ValueType.String, NameValue.ClassType.ReadWrite, NameValue.SendtoType.SimViewer, agent.Info.LastName); agent.Avatar.Prim.NameValues = name; // Give testers a provisionary balance of 1000L agent.Info.Balance = 1000; // Some default avatar prim properties agent.Avatar.Prim.Properties = new Primitive.ObjectProperties(); agent.Avatar.Prim.Properties.CreationDate = Utils.UnixTimeToDateTime(agent.Info.CreationTime); agent.Avatar.Prim.Properties.Name = agent.FullName; agent.Avatar.Prim.Properties.ObjectID = agent.ID; if (agent.Avatar.Prim.LocalID == 0) { // Assign a unique LocalID to this agent agent.Avatar.Prim.LocalID = (uint)Interlocked.Increment(ref currentLocalID); } if (OnAgentAdd != null) OnAgentAdd(sender, agent, creatorFlags); // Add the agent to the scene dictionary lock (sceneAgents) sceneAgents[agent.ID] = agent; Logger.Log("Added agent " + agent.FullName + " to the scene", Helpers.LogLevel.Info); return true; }
/// <summary>Process an incoming packet and raise the appropriate events</summary> /// <param name="sender">The sender</param> /// <param name="e">The EventArgs object containing the packet data</param> protected void ObjectUpdateCompressedHandler(object sender, PacketReceivedEventArgs e) { Packet packet = e.Packet; Simulator simulator = e.Simulator; ObjectUpdateCompressedPacket update = (ObjectUpdateCompressedPacket)packet; for (int b = 0; b < update.ObjectData.Length; b++) { ObjectUpdateCompressedPacket.ObjectDataBlock block = update.ObjectData[b]; int i = 0; try { // UUID UUID FullID = new UUID(block.Data, 0); i += 16; // Local ID uint LocalID = (uint)(block.Data[i++] + (block.Data[i++] << 8) + (block.Data[i++] << 16) + (block.Data[i++] << 24)); // PCode PCode pcode = (PCode)block.Data[i++]; #region Relevance check if (!Client.Settings.ALWAYS_DECODE_OBJECTS) { switch (pcode) { case PCode.Grass: case PCode.Tree: case PCode.NewTree: case PCode.Prim: if (m_ObjectUpdate == null) continue; break; } } #endregion Relevance check bool isNew; lock (simulator.ObjectsPrimitives.Dictionary) isNew = simulator.ObjectsPrimitives.ContainsKey(LocalID); Primitive prim = GetPrimitive(simulator, LocalID, FullID); prim.LocalID = LocalID; prim.ID = FullID; prim.Flags = (PrimFlags)block.UpdateFlags; prim.PrimData.PCode = pcode; #region Decode block and update Prim // State prim.PrimData.State = block.Data[i++]; // CRC i += 4; // Material prim.PrimData.Material = (Material)block.Data[i++]; // Click action prim.ClickAction = (ClickAction)block.Data[i++]; // Scale prim.Scale = new Vector3(block.Data, i); i += 12; // Position prim.Position = new Vector3(block.Data, i); i += 12; // Rotation prim.Rotation = new Quaternion(block.Data, i, true); i += 12; // Compressed flags CompressedFlags flags = (CompressedFlags)Utils.BytesToUInt(block.Data, i); i += 4; prim.OwnerID = new UUID(block.Data, i); i += 16; // Angular velocity if ((flags & CompressedFlags.HasAngularVelocity) != 0) { prim.AngularVelocity = new Vector3(block.Data, i); i += 12; } // Parent ID if ((flags & CompressedFlags.HasParent) != 0) { prim.ParentID = (uint)(block.Data[i++] + (block.Data[i++] << 8) + (block.Data[i++] << 16) + (block.Data[i++] << 24)); } else { prim.ParentID = 0; } // Tree data if ((flags & CompressedFlags.Tree) != 0) { prim.TreeSpecies = (Tree)block.Data[i++]; //prim.ScratchPad = Utils.EmptyBytes; } // Scratch pad else if ((flags & CompressedFlags.ScratchPad) != 0) { prim.TreeSpecies = (Tree)0; int size = block.Data[i++]; //prim.ScratchPad = new byte[size]; //Buffer.BlockCopy(block.Data, i, prim.ScratchPad, 0, size); i += size; } prim.ScratchPad = Utils.EmptyBytes; // Floating text if ((flags & CompressedFlags.HasText) != 0) { string text = String.Empty; while (block.Data[i] != 0) { text += (char)block.Data[i]; i++; } i++; // Floating text prim.Text = text; // Text color prim.TextColor = new Color4(block.Data, i, false); i += 4; } else { prim.Text = String.Empty; } // Media URL if ((flags & CompressedFlags.MediaURL) != 0) { string text = String.Empty; while (block.Data[i] != 0) { text += (char)block.Data[i]; i++; } i++; prim.MediaURL = text; } // Particle system if ((flags & CompressedFlags.HasParticles) != 0) { prim.ParticleSys = new Primitive.ParticleSystem(block.Data, i); i += 86; } // Extra parameters i += prim.SetExtraParamsFromBytes(block.Data, i); //Sound data if ((flags & CompressedFlags.HasSound) != 0) { prim.Sound = new UUID(block.Data, i); i += 16; prim.SoundGain = Utils.BytesToFloat(block.Data, i); i += 4; prim.SoundFlags = (SoundFlags)block.Data[i++]; prim.SoundRadius = Utils.BytesToFloat(block.Data, i); i += 4; } // Name values if ((flags & CompressedFlags.HasNameValues) != 0) { string text = String.Empty; while (block.Data[i] != 0) { text += (char)block.Data[i]; i++; } i++; // Parse the name values if (text.Length > 0) { string[] lines = text.Split('\n'); prim.NameValues = new NameValue[lines.Length]; for (int j = 0; j < lines.Length; j++) { if (!String.IsNullOrEmpty(lines[j])) { NameValue nv = new NameValue(lines[j]); prim.NameValues[j] = nv; } } } } prim.PrimData.PathCurve = (PathCurve)block.Data[i++]; ushort pathBegin = Utils.BytesToUInt16(block.Data, i); i += 2; prim.PrimData.PathBegin = Primitive.UnpackBeginCut(pathBegin); ushort pathEnd = Utils.BytesToUInt16(block.Data, i); i += 2; prim.PrimData.PathEnd = Primitive.UnpackEndCut(pathEnd); prim.PrimData.PathScaleX = Primitive.UnpackPathScale(block.Data[i++]); prim.PrimData.PathScaleY = Primitive.UnpackPathScale(block.Data[i++]); prim.PrimData.PathShearX = Primitive.UnpackPathShear((sbyte)block.Data[i++]); prim.PrimData.PathShearY = Primitive.UnpackPathShear((sbyte)block.Data[i++]); prim.PrimData.PathTwist = Primitive.UnpackPathTwist((sbyte)block.Data[i++]); prim.PrimData.PathTwistBegin = Primitive.UnpackPathTwist((sbyte)block.Data[i++]); prim.PrimData.PathRadiusOffset = Primitive.UnpackPathTwist((sbyte)block.Data[i++]); prim.PrimData.PathTaperX = Primitive.UnpackPathTaper((sbyte)block.Data[i++]); prim.PrimData.PathTaperY = Primitive.UnpackPathTaper((sbyte)block.Data[i++]); prim.PrimData.PathRevolutions = Primitive.UnpackPathRevolutions(block.Data[i++]); prim.PrimData.PathSkew = Primitive.UnpackPathTwist((sbyte)block.Data[i++]); prim.PrimData.profileCurve = block.Data[i++]; ushort profileBegin = Utils.BytesToUInt16(block.Data, i); i += 2; prim.PrimData.ProfileBegin = Primitive.UnpackBeginCut(profileBegin); ushort profileEnd = Utils.BytesToUInt16(block.Data, i); i += 2; prim.PrimData.ProfileEnd = Primitive.UnpackEndCut(profileEnd); ushort profileHollow = Utils.BytesToUInt16(block.Data, i); i += 2; prim.PrimData.ProfileHollow = Primitive.UnpackProfileHollow(profileHollow); // TextureEntry int textureEntryLength = (int)Utils.BytesToUInt(block.Data, i); i += 4; prim.Textures = new Primitive.TextureEntry(block.Data, i, textureEntryLength); i += textureEntryLength; // Texture animation if ((flags & CompressedFlags.TextureAnimation) != 0) { //int textureAnimLength = (int)Utils.BytesToUIntBig(block.Data, i); i += 4; prim.TextureAnim = new Primitive.TextureAnimation(block.Data, i); } #endregion #region Raise Events bool isAttachment = (flags & CompressedFlags.HasNameValues) != 0 && prim.ParentID != 0; OnObjectUpdate(new PrimEventArgs(simulator, prim, update.RegionData.TimeDilation, isNew, isAttachment)); #endregion } catch (IndexOutOfRangeException ex) { Logger.Log("Error decoding an ObjectUpdateCompressed packet", Helpers.LogLevel.Warning, Client, ex); Logger.Log(block, Helpers.LogLevel.Warning); } } }
/// <summary> /// /// </summary> /// <param name="packet"></param> /// <param name="simulator"></param> protected void CompressedUpdateHandler(Packet packet, Simulator simulator) { ObjectUpdateCompressedPacket update = (ObjectUpdateCompressedPacket)packet; for (int b = 0; b < update.ObjectData.Length; b++) { ObjectUpdateCompressedPacket.ObjectDataBlock block = update.ObjectData[b]; int i = 0; try { // UUID UUID FullID = new UUID(block.Data, 0); i += 16; // Local ID uint LocalID = (uint)(block.Data[i++] + (block.Data[i++] << 8) + (block.Data[i++] << 16) + (block.Data[i++] << 24)); // PCode PCode pcode = (PCode)block.Data[i++]; #region Relevance check 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; } } #endregion Relevance check Primitive prim = GetPrimitive(simulator, LocalID, FullID); prim.LocalID = LocalID; prim.ID = FullID; prim.Flags = (PrimFlags)block.UpdateFlags; prim.PrimData.PCode = pcode; switch (pcode) { case PCode.Grass: case PCode.Tree: case PCode.NewTree: #region Foliage Decoding // State prim.PrimData.State = block.Data[i++]; // CRC i += 4; // Material prim.PrimData.Material = (Material)block.Data[i++]; // Click action prim.ClickAction = (ClickAction)block.Data[i++]; // Scale prim.Scale = new Vector3(block.Data, i); i += 12; // Position prim.Position = new Vector3(block.Data, i); i += 12; // Rotation prim.Rotation = new Quaternion(block.Data, i, true); i += 12; #endregion Foliage Decoding // FIXME: We are leaving a lot of data left undecoded here, including the // tree species. Need to understand what is going on with these packets // and fix it soon! FireOnNewFoliage(simulator, prim, update.RegionData.RegionHandle, update.RegionData.TimeDilation); break; case PCode.Prim: #region Decode block and update Prim // State prim.PrimData.State = block.Data[i++]; // CRC i += 4; // Material prim.PrimData.Material = (Material)block.Data[i++]; // Click action prim.ClickAction = (ClickAction)block.Data[i++]; // Scale prim.Scale = new Vector3(block.Data, i); i += 12; // Position prim.Position = new Vector3(block.Data, i); i += 12; // Rotation prim.Rotation = new Quaternion(block.Data, i, true); i += 12; // Compressed flags CompressedFlags flags = (CompressedFlags)Utils.BytesToUInt(block.Data, i); i += 4; prim.OwnerID = new UUID(block.Data, i); i += 16; // Angular velocity if ((flags & CompressedFlags.HasAngularVelocity) != 0) { prim.AngularVelocity = new Vector3(block.Data, i); i += 12; } // Parent ID if ((flags & CompressedFlags.HasParent) != 0) { prim.ParentID = (uint)(block.Data[i++] + (block.Data[i++] << 8) + (block.Data[i++] << 16) + (block.Data[i++] << 24)); } else { prim.ParentID = 0; } // Tree data if ((flags & CompressedFlags.Tree) != 0) { prim.GenericData = new byte[1]; prim.GenericData[0] = block.Data[i++]; } // Scratch pad else if ((flags & CompressedFlags.ScratchPad) != 0) { int size = block.Data[i++]; prim.GenericData = new byte[size]; Buffer.BlockCopy(block.Data, i, prim.GenericData, 0, size); i += size; } // Floating text if ((flags & CompressedFlags.HasText) != 0) { string text = String.Empty; while (block.Data[i] != 0) { text += (char)block.Data[i]; i++; } i++; // Floating text prim.Text = text; // Text color prim.TextColor = new Color4(block.Data, i, false); // FIXME: Is alpha inversed here as well? i += 4; } else { prim.Text = String.Empty; } // Media URL if ((flags & CompressedFlags.MediaURL) != 0) { string text = String.Empty; while (block.Data[i] != 0) { text += (char)block.Data[i]; i++; } i++; prim.MediaURL = text; } // Particle system if ((flags & CompressedFlags.HasParticles) != 0) { prim.ParticleSys = new Primitive.ParticleSystem(block.Data, i); i += 86; } // Extra parameters i += prim.SetExtraParamsFromBytes(block.Data, i); //Sound data if ((flags & CompressedFlags.HasSound) != 0) { prim.Sound = new UUID(block.Data, i); i += 16; prim.SoundGain = Utils.BytesToFloat(block.Data, i); i += 4; prim.SoundFlags = block.Data[i++]; prim.SoundRadius = Utils.BytesToFloat(block.Data, i); i += 4; } // Name values if ((flags & CompressedFlags.HasNameValues) != 0) { string text = String.Empty; while (block.Data[i] != 0) { text += (char)block.Data[i]; i++; } i++; // Parse the name values if (text.Length > 0) { string[] lines = text.Split('\n'); prim.NameValues = new NameValue[lines.Length]; for (int j = 0; j < lines.Length; j++) { if (!String.IsNullOrEmpty(lines[j])) { NameValue nv = new NameValue(lines[j]); prim.NameValues[j] = nv; } } } } prim.PrimData.PathCurve = (PathCurve)block.Data[i++]; ushort pathBegin = Utils.BytesToUInt16(block.Data, i); i += 2; prim.PrimData.PathBegin = Primitive.UnpackBeginCut(pathBegin); ushort pathEnd = Utils.BytesToUInt16(block.Data, i); i += 2; prim.PrimData.PathEnd = Primitive.UnpackEndCut(pathEnd); prim.PrimData.PathScaleX = Primitive.UnpackPathScale(block.Data[i++]); prim.PrimData.PathScaleY = Primitive.UnpackPathScale(block.Data[i++]); prim.PrimData.PathShearX = Primitive.UnpackPathShear((sbyte)block.Data[i++]); prim.PrimData.PathShearY = Primitive.UnpackPathShear((sbyte)block.Data[i++]); prim.PrimData.PathTwist = Primitive.UnpackPathTwist((sbyte)block.Data[i++]); prim.PrimData.PathTwistBegin = Primitive.UnpackPathTwist((sbyte)block.Data[i++]); prim.PrimData.PathRadiusOffset = Primitive.UnpackPathTwist((sbyte)block.Data[i++]); prim.PrimData.PathTaperX = Primitive.UnpackPathTaper((sbyte)block.Data[i++]); prim.PrimData.PathTaperY = Primitive.UnpackPathTaper((sbyte)block.Data[i++]); prim.PrimData.PathRevolutions = Primitive.UnpackPathRevolutions(block.Data[i++]); prim.PrimData.PathSkew = Primitive.UnpackPathTwist((sbyte)block.Data[i++]); prim.PrimData.profileCurve = block.Data[i++]; ushort profileBegin = Utils.BytesToUInt16(block.Data, i); i += 2; prim.PrimData.ProfileBegin = Primitive.UnpackBeginCut(profileBegin); ushort profileEnd = Utils.BytesToUInt16(block.Data, i); i += 2; prim.PrimData.ProfileEnd = Primitive.UnpackEndCut(profileEnd); ushort profileHollow = Utils.BytesToUInt16(block.Data, i); i += 2; prim.PrimData.ProfileHollow = Primitive.UnpackProfileHollow(profileHollow); // TextureEntry int textureEntryLength = (int)Utils.BytesToUInt(block.Data, i); i += 4; prim.Textures = new Primitive.TextureEntry(block.Data, i, textureEntryLength); i += textureEntryLength; // Texture animation if ((flags & CompressedFlags.TextureAnimation) != 0) { //int textureAnimLength = (int)Utils.BytesToUIntBig(block.Data, i); i += 4; prim.TextureAnim = new Primitive.TextureAnimation(block.Data, i); } #endregion #region Fire Events // Fire the appropriate callback if ((flags & CompressedFlags.HasNameValues) != 0 && prim.ParentID != 0) FireOnNewAttachment(simulator, prim, update.RegionData.RegionHandle, update.RegionData.TimeDilation); else if ((flags & CompressedFlags.Tree) != 0) FireOnNewFoliage(simulator, prim, update.RegionData.RegionHandle, update.RegionData.TimeDilation); else FireOnNewPrim(simulator, prim, update.RegionData.RegionHandle, update.RegionData.TimeDilation); #endregion break; default: Logger.DebugLog("Got an ObjectUpdateCompressed for PCode " + pcode.ToString() + ", implement this!", Client); break; } } catch (IndexOutOfRangeException e) { Logger.Log("Error decoding an ObjectUpdateCompressed packet", Helpers.LogLevel.Warning, Client, e); Logger.Log(block, Helpers.LogLevel.Warning); } } }
public ObjectDataBlockUpdateEventArgs(Simulator simulator, Primitive prim, Primitive.ConstructionData constructionData, ObjectUpdatePacket.ObjectDataBlock block, ObjectMovementUpdate objectupdate, NameValue[] nameValues) { this.m_Simulator = simulator; this.m_Prim = prim; this.m_ConstructionData = constructionData; this.m_Block = block; this.m_Update = objectupdate; this.m_NameValues = nameValues; }
/// <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]; Vector4 collisionPlane = Vector4.Zero; Vector3 position; Vector3 velocity; Vector3 acceleration; Quaternion rotation; Vector3 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 Vector4(block.ObjectData, pos); pos += 16; goto case 60; case 60: // Position position = new Vector3(block.ObjectData, pos); pos += 12; // Velocity velocity = new Vector3(block.ObjectData, pos); pos += 12; // Acceleration acceleration = new Vector3(block.ObjectData, pos); pos += 12; // Rotation (theta) rotation = new Quaternion(block.ObjectData, pos, true); pos += 12; // Angular velocity (omega) angularVelocity = new Vector3(block.ObjectData, pos); pos += 12; break; case 48: // Collision normal for avatar collisionPlane = new Vector4(block.ObjectData, pos); pos += 16; goto case 32; case 32: // The data is an array of unsigned shorts // Position position = new Vector3( 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 Vector3( 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 Vector3( 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 Quaternion( 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 Vector3( 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 Vector3( 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 Vector3( 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 Vector3( 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 Quaternion( 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 Vector3( 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: Logger.Log("Got an ObjectUpdate block with ObjectUpdate field length of " + block.ObjectData.Length, Helpers.LogLevel.Warning, Client); 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) { Logger.Log("Got a ZlibCompressed ObjectUpdate, implement me!", Helpers.LogLevel.Warning, Client); 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 Color4(block.TextColor, 0, false, true); // 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: Logger.DebugLog("Got an ObjectUpdate block with an unrecognized PCode " + pcode.ToString(), Client); break; } } }