protected override void DeSerialise(byte[] buf, ref int o, int length) { SenderId = BinarySerializer.DeSerializeGuid(buf, ref o, length); SenderIsTrial = BinarySerializer.DeSerializeBool(buf, ref o, length); TextureEntry = BinarySerializer.DeSerializeTextureEntry(buf, ref o, length); int len = buf[o++]; // TODO: Decode visual params: Each byte appears to be a weight that needs to be scaled between the min and max values of the parameter identified by the index VisualParam = new byte[len]; Array.Copy(buf, o, VisualParam, 0, len); o += len; len = buf[o++]; for (int i = 0; i < len; i++) { AppearanceDatas.Add(new AppearanceData() { AppearanceVersion = buf[o++], CofVersion = BinarySerializer.DeSerializeInt32_Le(buf, ref o, length), Flags = BinarySerializer.DeSerializeUInt32_Le(buf, ref o, length) }); } len = buf[o++]; for (int i = 0; i < len; i++) { HoverHeights.Add(BinarySerializer.DeSerializeVector3(buf, ref o, length)); } }
protected override void DeSerialise(byte[] buf, ref int o, int length) { SoundId = BinarySerializer.DeSerializeGuid(buf, ref o, length); OwnerId = BinarySerializer.DeSerializeGuid(buf, ref o, length); ObjectId = BinarySerializer.DeSerializeGuid(buf, ref o, length); ParentId = BinarySerializer.DeSerializeGuid(buf, ref o, length); Handle = new RegionHandle(BinarySerializer.DeSerializeUInt64_Le(buf, ref o, length)); Position = BinarySerializer.DeSerializeVector3(buf, ref o, buf.Length); }
protected override void DeSerialise(byte[] buf, ref int o, int length) { UsecSinceStart = BinarySerializer.DeSerializeUInt64_Le(buf, ref o, length); SecPerDay = BinarySerializer.DeSerializeUInt32_Le(buf, ref o, length); SecPerYear = BinarySerializer.DeSerializeUInt32_Le(buf, ref o, length); SunDirection = BinarySerializer.DeSerializeVector3(buf, ref o, buf.Length); SunPhase = BinarySerializer.DeSerializeFloat_Le(buf, ref o, length); SunAngVelocity = BinarySerializer.DeSerializeVector3(buf, ref o, buf.Length); }
protected override void DeSerialise(byte[] buf, ref int o, int length) { AgentId = BinarySerializer.DeSerializeGuid(buf, ref o, length); SessionId = BinarySerializer.DeSerializeGuid(buf, ref o, length); Position = BinarySerializer.DeSerializeVector3(buf, ref o, length); LookAt = BinarySerializer.DeSerializeVector3(buf, ref o, length); RegionHandle = new RegionHandle(BinarySerializer.DeSerializeUInt64_Le(buf, ref o, length)); TimeStamp = BinarySerializer.DeSerializeDateTime(buf, ref o, length); ChannelVersion = BinarySerializer.DeSerializeString(buf, ref o, length, 2); }
protected override void DeSerialise(byte[] buf, ref int o, int length) { FromName = BinarySerializer.DeSerializeString(buf, ref o, length, 1); SourceId = BinarySerializer.DeSerializeGuid(buf, ref o, length); OwnerId = BinarySerializer.DeSerializeGuid(buf, ref o, length); SourceType = (ChatSourceType)buf[o++]; ChatType = (ChatType)buf[o++]; AudibleLevel = (ChatAudibleLevel)buf[o++]; Position = BinarySerializer.DeSerializeVector3(buf, ref o, length); Message = BinarySerializer.DeSerializeString(buf, ref o, length, 2); }
protected override void DeSerialise(byte[] buf, ref int o, int length) { AgentId = BinarySerializer.DeSerializeGuid(buf, ref o, length); SessionId = BinarySerializer.DeSerializeGuid(buf, ref o, length); IsFromGroup = buf[o++] != 0; // TODO: Put this in BinarySerializer to make sure that it is consistent ToAgentId = BinarySerializer.DeSerializeGuid(buf, ref o, length); ParentEstateId = BinarySerializer.DeSerializeUInt32_Le(buf, ref o, length); RegionId = BinarySerializer.DeSerializeGuid(buf, ref o, length); Position = BinarySerializer.DeSerializeVector3(buf, ref o, length); OnlineMode = (OnlineMode)buf[o++]; DialogType = (DialogType)buf[o++]; Id = BinarySerializer.DeSerializeGuid(buf, ref o, length); Timestamp = BinarySerializer.DeSerializeUInt32_Le(buf, ref o, length); FromAgentName = BinarySerializer.DeSerializeString(buf, ref o, length, 1); MessageText = BinarySerializer.DeSerializeString(buf, ref o, length, 2); UInt16 len = BinarySerializer.DeSerializeUInt16_Le(buf, ref o, length); BinaryBucket = new byte[len]; Array.Copy(buf, o, BinaryBucket, 0, len); o += len; }
public static PolyMorphData DeSerializePolyMorphData(byte[] buffer, ref int offset, int length) { PolyMorphData data = new PolyMorphData(); Int32 nVertices = BinarySerializer.DeSerializeInt32_Le(buffer, ref offset, length); for (int i = 0; i < nVertices; i++) { UInt32 vertexIndex = BinarySerializer.DeSerializeUInt32_Le(buffer, ref offset, length); if (vertexIndex > 10000) { throw new Exception($"Bad morph index: {vertexIndex}"); } Vector3 coordinate = BinarySerializer.DeSerializeVector3(buffer, ref offset, length); Vector3 normal = BinarySerializer.DeSerializeVector3(buffer, ref offset, length); Vector3 biNormal = BinarySerializer.DeSerializeVector3(buffer, ref offset, length); Vector2 texCoord = BinarySerializer.DeSerializeVector2(buffer, ref offset, length); } return(data); }
public static PolyMesh DeSerializePolyMesh(byte[] buffer, ref int o, int length, bool isLod) { if (length < 128) { throw new Exception("Not enough bytes in file for header."); } PolyMesh mesh = new PolyMesh { IsLod = isLod, SharedData = new PolyMeshSharedData() }; string identifier = BinarySerializer.DeSerializeString(buffer, ref o, 24, -1); if (identifier.Trim() != ExpectedBinaryIdentifier) { throw new Exception($"Invalid mesh file header."); } string logMessage = ""; mesh.SharedData.HasWeights = BinarySerializer.DeSerializeBool(buffer, ref o, length); mesh.SharedData.HasDetailTexCoords = BinarySerializer.DeSerializeBool(buffer, ref o, length); mesh.SharedData.Position = BinarySerializer.DeSerializeVector3(buffer, ref o, length); Vector3 rotationAngles = BinarySerializer.DeSerializeVector3(buffer, ref o, length); byte rotationOrder = BinarySerializer.DeSerializeUInt8(buffer, ref o, length); rotationOrder = 0; // NOTE: This is what the LL code does mesh.SharedData.Rotation = Quaternion.Euler(rotationAngles); mesh.SharedData.Scale = BinarySerializer.DeSerializeVector3(buffer, ref o, length); logMessage = $"\n" + $" identifier: \"{identifier}\"\n" + $" hasWeights: {mesh.SharedData.HasWeights}\n" + $" hasDetailTexCoords: {mesh.SharedData.HasDetailTexCoords}\n" + $" position: {mesh.SharedData.Position}\n" + $" rotationAngles: {rotationAngles}\n" + $" rotationOrder: {rotationOrder}\n" + $" scale: {mesh.SharedData.Scale}\n" ; if (isLod == false) { UInt32 numVertices = BinarySerializer.DeSerializeUInt16_Le(buffer, ref o, length); logMessage += $" nVertices: 0x{numVertices:x4}\n"; mesh.SharedData.AllocateVertexData(numVertices); #region Vertices if (length - o < mesh.SharedData.NumVertices * 12) { throw new Exception($"Not enough bytes to read vertices."); } for (int i = 0; i < mesh.SharedData.NumVertices; i++) { mesh.SharedData.BaseCoords[i] = BinarySerializer.DeSerializeVector3(buffer, ref o, length); } #endregion Vertices #region Normals if (length - o < mesh.SharedData.NumVertices * 12) { throw new Exception($"Not enough bytes to read normals."); } for (int i = 0; i < mesh.SharedData.NumVertices; i++) { mesh.SharedData.BaseNormals[i] = BinarySerializer.DeSerializeVector3(buffer, ref o, length); } #endregion Normals #region BiNormals if (length - o < mesh.SharedData.NumVertices * 12) { throw new Exception($"Not enough bytes to read bi-normals."); } for (int i = 0; i < mesh.SharedData.NumVertices; i++) { mesh.SharedData.BaseBiNormals[i] = BinarySerializer.DeSerializeVector3(buffer, ref o, length); } #endregion BiNormals #region TexCoords if (length - o < mesh.SharedData.NumVertices * 8) { throw new Exception($"Not enough bytes to read tex-coords."); } for (int i = 0; i < mesh.SharedData.NumVertices; i++) { mesh.SharedData.TexCoords[i] = BinarySerializer.DeSerializeVector2(buffer, ref o, length); } #endregion TexCoords #region DetailedTexCoords if (mesh.SharedData.HasDetailTexCoords) { if (length - o < mesh.SharedData.NumVertices * 8) { throw new Exception($"Not enough bytes to read detailed tex-coords."); } for (int i = 0; i < mesh.SharedData.NumVertices; i++) { mesh.SharedData.DetailTexCoords[i] = BinarySerializer.DeSerializeVector2(buffer, ref o, length); } } #endregion DetailedTexCoords #region Weights if (mesh.SharedData.HasWeights) { if (length - o < mesh.SharedData.NumVertices * 4) { throw new Exception($"Not enough bytes to read weights."); } for (int i = 0; i < mesh.SharedData.NumVertices; i++) { mesh.SharedData.Weights[i] = BinarySerializer.DeSerializeFloat_Le(buffer, ref o, length); } } #endregion Weights } #region Faces UInt16 nFaces = BinarySerializer.DeSerializeUInt16_Le(buffer, ref o, length); logMessage += $" nFaces: 0x{nFaces:x4}\n"; mesh.SharedData.AllocateFaceData(nFaces); int numTris = 0; if (length - o < nFaces * 3 * 2) { throw new Exception($"Not enough bytes to read faces."); } for (int i = 0; i < nFaces; i++) { Int16 a = BinarySerializer.DeSerializeInt16_Le(buffer, ref o, length); Int16 b = BinarySerializer.DeSerializeInt16_Le(buffer, ref o, length); Int16 c = BinarySerializer.DeSerializeInt16_Le(buffer, ref o, length); if (mesh.SharedData.ReferenceData != null && ( a >= mesh.SharedData.ReferenceData.NumVertices || b >= mesh.SharedData.ReferenceData.NumVertices || c >= mesh.SharedData.ReferenceData.NumVertices )) { throw new Exception("DeSerializePolyMesh: Face index is out of range of the reference mesh."); } PolyFace face = new PolyFace(a, c, b); // Swizzled order for Unity if (isLod) { // Store largest index in case of LODs for (int j = 0; j < 3; j++) { if (face[j] > mesh.SharedData.NumVertices - 1) { mesh.SharedData.NumVertices = (UInt32)face[j] + 1; } } } mesh.SharedData.Faces[i] = face; numTris++; } logMessage += $" NumTriangles: {numTris}\n"; #endregion Faces if (isLod == false) { UInt16 nSkinJoints = 0; if (mesh.SharedData.HasWeights) { nSkinJoints = BinarySerializer.DeSerializeUInt16_Le(buffer, ref o, length); logMessage += $" nSkinJoints: 0x{nSkinJoints:x4}\n"; mesh.SharedData.AllocateJointNames(nSkinJoints); } #region SkinJoints for (int i = 0; i < nSkinJoints; i++) { mesh.SharedData.JointNames[i] = BinarySerializer.DeSerializeString(buffer, ref o, 64, -1); logMessage += $" jointName: {mesh.SharedData.JointNames[i]}\n"; } #endregion SkinJoints #region MorphSections while (true) { string morphName = BinarySerializer.DeSerializeString(buffer, ref o, 64, -1); if (morphName == "End Morphs") { break; } PolyMorphData morphData = DeSerializePolyMorphData(buffer, ref o, length); morphData.Name = morphName; logMessage += $" Morph name: {morphName}\n"; mesh.SharedData.MorphData.Add(morphData); // Insert jiggle physics morphs: switch (morphName) { case "Breast_Female_Cleavage": //mesh.SharedData.MorphData.Add(CloneMorphParamCleavage (morphData, 0.75f, "Breast_Physics_LeftRight_Driven")); //mesh.SharedData.MorphData.Add(CloneMorphParamDuplicate(morphData, "Breast_Physics_InOut_Driven")); break; case "Breast_Gravity": //mesh.SharedData.MorphData.Add(CloneMorphParamDuplicate(morphData, "Breast_Physics_UpDown_Driven")); break; case "Big_Belly_Torso": //mesh.SharedData.MorphData.Add(CloneMorphParamDirection(morphData, new Vector3(0f, 0.05f, 0f), "Belly_Physics_Torso_UpDown_Driven")); break; case "Big_Belly_Legs": //mesh.SharedData.MorphData.Add(CloneMorphParamDirection(morphData, new Vector3(0f, 0.05f, 0f), "Belly_Physics_Legs_UpDown_Driven")); break; case "skirt_belly": //mesh.SharedData.MorphData.Add(CloneMorphParamDirection(morphData, new Vector3(0f, 0.05f, 0f), "Belly_Physics_Skirt_UpDown_Driven")); break; case "Small_Butt": //mesh.SharedData.MorphData.Add(CloneMorphParamDirection(morphData, new Vector3(0f, 0.05f, 0f), "Butt_Physics_UpDown_Driven")); //mesh.SharedData.MorphData.Add(CloneMorphParamDirection(morphData, new Vector3(0f, 0.03f, 0f), "Butt_Physics_LeftRight_Driven")); break; } } #endregion MorphSections #region Remaps Int32 nRemaps = BinarySerializer.DeSerializeInt32_Le(buffer, ref o, length); for (int i = 0; i < nRemaps; i++) { Int32 src = BinarySerializer.DeSerializeInt32_Le(buffer, ref o, length); Int32 dst = BinarySerializer.DeSerializeInt32_Le(buffer, ref o, length); mesh.SharedData.SharedVertices[src] = dst; } #endregion Remaps } if (mesh.SharedData.NumJointNames == 0) { mesh.SharedData.AllocateJointNames(1); } logMessage += $"{length - o} bytes left in buffer."; Logger.LogDebug("PolyMesh.DeSerializePolyMesh", logMessage); return(mesh); }
public MovementUpdate DeSerializeMovementUpdate(byte[] buffer, ref int offset, int length) { float size = 256; // TODO: This should be fetched from the Region.WidthInMetres of the region this message is for. float minHeight = -256; // TODO: I don't know where this should come from float maxHeight = 3 * 256; // TODO: I don't know where this should come from MovementUpdate update = new MovementUpdate(); int len = buffer[offset++]; int limit = offset + len; switch (len) { case 60 + 16: // pull out collision normal for avatar update.FootPlane = BinarySerializer.DeSerializeVector4(buffer, ref offset, limit); goto case 60; case 60: update.Position = BinarySerializer.DeSerializeVector3(buffer, ref offset, limit); update.Velocity = BinarySerializer.DeSerializeVector3(buffer, ref offset, limit); update.Acceleration = BinarySerializer.DeSerializeVector3(buffer, ref offset, limit); update.Rotation = BinarySerializer.DeSerializeQuaternion(buffer, ref offset, limit); // Theta update.AngularVelocity = BinarySerializer.DeSerializeVector3(buffer, ref offset, limit); // Omega break; case 32 + 16: // pull out collision normal for avatar update.FootPlane = BinarySerializer.DeSerializeVector4(buffer, ref offset, limit); goto case 32; case 32: // Values are UInt16 and needs to be quantized to floats update.Position = new Vector3( x: BinarySerializer.DeSerializeUInt16_Le(buffer, ref offset, limit).ToFloat(-0.5f * size, 1.5f * size), z: BinarySerializer.DeSerializeUInt16_Le(buffer, ref offset, limit).ToFloat(minHeight, maxHeight), // Handedness y: BinarySerializer.DeSerializeUInt16_Le(buffer, ref offset, limit).ToFloat(-0.5f * size, 1.5f * size)); update.Velocity = new Vector3( x: BinarySerializer.DeSerializeUInt16_Le(buffer, ref offset, limit).ToFloat(-size, size), z: BinarySerializer.DeSerializeUInt16_Le(buffer, ref offset, limit).ToFloat(-size, size), // Handedness y: BinarySerializer.DeSerializeUInt16_Le(buffer, ref offset, limit).ToFloat(-size, size)); update.Acceleration = new Vector3( x: BinarySerializer.DeSerializeUInt16_Le(buffer, ref offset, limit).ToFloat(-size, size), z: BinarySerializer.DeSerializeUInt16_Le(buffer, ref offset, limit).ToFloat(-size, size), // Handedness y: BinarySerializer.DeSerializeUInt16_Le(buffer, ref offset, limit).ToFloat(-size, size)); update.Rotation = new Quaternion( x: BinarySerializer.DeSerializeUInt16_Le(buffer, ref offset, limit).ToFloat(-1f, 1f), z: BinarySerializer.DeSerializeUInt16_Le(buffer, ref offset, limit).ToFloat(-1f, 1f), // Handedness y: BinarySerializer.DeSerializeUInt16_Le(buffer, ref offset, limit).ToFloat(-1f, 1f), w: BinarySerializer.DeSerializeUInt16_Le(buffer, ref offset, limit).ToFloat(-1f, 1f)); update.AngularVelocity = new Vector3( x: BinarySerializer.DeSerializeUInt16_Le(buffer, ref offset, limit).ToFloat(-size, size), z: BinarySerializer.DeSerializeUInt16_Le(buffer, ref offset, limit).ToFloat(-size, size), // Handedness y: BinarySerializer.DeSerializeUInt16_Le(buffer, ref offset, limit).ToFloat(-size, size)); break; case 16: // Values are UInt8 and needs to be quantized to floats update.Position = new Vector3( x: BinarySerializer.DeSerializeUInt8(buffer, ref offset, limit).ToFloat(-0.5f * size, 1.5f * size), z: BinarySerializer.DeSerializeUInt8(buffer, ref offset, limit).ToFloat(minHeight, maxHeight), // Handedness y: BinarySerializer.DeSerializeUInt8(buffer, ref offset, limit).ToFloat(-0.5f * size, 1.5f * size)); update.Velocity = new Vector3( x: BinarySerializer.DeSerializeUInt8(buffer, ref offset, limit).ToFloat(-size, size), z: BinarySerializer.DeSerializeUInt8(buffer, ref offset, limit).ToFloat(-size, size), // Handedness y: BinarySerializer.DeSerializeUInt8(buffer, ref offset, limit).ToFloat(-size, size)); update.Acceleration = new Vector3( x: BinarySerializer.DeSerializeUInt8(buffer, ref offset, limit).ToFloat(-size, size), z: BinarySerializer.DeSerializeUInt8(buffer, ref offset, limit).ToFloat(-size, size), // Handedness y: BinarySerializer.DeSerializeUInt8(buffer, ref offset, limit).ToFloat(-size, size)); update.Rotation = new Quaternion( x: BinarySerializer.DeSerializeUInt8(buffer, ref offset, limit).ToFloat(-1f, 1f), z: BinarySerializer.DeSerializeUInt8(buffer, ref offset, limit).ToFloat(-1f, 1f), // Handedness y: BinarySerializer.DeSerializeUInt8(buffer, ref offset, limit).ToFloat(-1f, 1f), w: BinarySerializer.DeSerializeUInt8(buffer, ref offset, limit).ToFloat(-1f, 1f)); update.AngularVelocity = new Vector3( x: BinarySerializer.DeSerializeUInt8(buffer, ref offset, limit).ToFloat(-size, size), z: BinarySerializer.DeSerializeUInt8(buffer, ref offset, limit).ToFloat(-size, size), // Handedness y: BinarySerializer.DeSerializeUInt8(buffer, ref offset, limit).ToFloat(-size, size)); break; } return(update); }
protected override void DeSerialise(byte[] buf, ref int o, int length) { RegionHandle = new RegionHandle(BinarySerializer.DeSerializeUInt64_Le(buf, ref o, length)); TimeDilation = BinarySerializer.DeSerializeUInt16_Le(buf, ref o, length); int nObjects = buf[o++]; for (int i = 0; i < nObjects; i++) { int len; ObjectUpdateMessage.ObjectData data = new ObjectUpdateMessage.ObjectData(); Objects.Add(data); data.LocalId = BinarySerializer.DeSerializeUInt32_Le(buf, ref o, length); data.State = buf[o++]; data.FullId = BinarySerializer.DeSerializeGuid(buf, ref o, length); data.Crc = BinarySerializer.DeSerializeUInt32_Le(buf, ref o, length); data.PCode = (PCode)buf[o++]; data.Material = (MaterialType)buf[o++]; data.ClickAction = (ClickAction)buf[o++]; data.Scale = BinarySerializer.DeSerializeVector3(buf, ref o, buf.Length); data.MovementUpdate = DeSerializeMovementUpdate(buf, ref o, buf.Length); data.ParentId = BinarySerializer.DeSerializeUInt32_Le(buf, ref o, length); data.UpdateFlags = (ObjectUpdateFlags)BinarySerializer.DeSerializeUInt32_Le(buf, ref o, length); data.PathCurve = (PathType)buf[o++]; data.ProfileCurve = (ProfileType)buf[o++]; data.PathBegin = BinarySerializer.DeSerializeUInt16_Le(buf, ref o, length) * CUT_QUANTA; data.PathEnd = BinarySerializer.DeSerializeUInt16_Le(buf, ref o, length) * CUT_QUANTA; data.PathScaleX = buf[o++] * SCALE_QUANTA; data.PathScaleY = buf[o++] * SCALE_QUANTA; data.PathShearX = buf[o++] * SHEAR_QUANTA; data.PathShearY = buf[o++] * SHEAR_QUANTA; data.PathTwist = (sbyte)buf[o++] * SCALE_QUANTA; data.PathTwistBegin = (sbyte)buf[o++] * SCALE_QUANTA; data.PathRadiusOffset = (sbyte)buf[o++] * SCALE_QUANTA; data.PathTaperX = (sbyte)buf[o++] * TAPER_QUANTA; data.PathTaperY = (sbyte)buf[o++] * TAPER_QUANTA; data.PathRevolutions = buf[o++] * REV_QUANTA; data.PathSkew = (sbyte)buf[o++] * SCALE_QUANTA; data.ProfileBegin = BinarySerializer.DeSerializeUInt16_Le(buf, ref o, length) * CUT_QUANTA; data.ProfileEnd = BinarySerializer.DeSerializeUInt16_Le(buf, ref o, length) * CUT_QUANTA; data.ProfileHollow = BinarySerializer.DeSerializeUInt16_Le(buf, ref o, length) * HOLLOW_QUANTA; data.TextureEntry = BinarySerializer.DeSerializeTextureEntry(buf, ref o, length); data.TextureAnimation = BinarySerializer.DeSerializeTextureAnimation(buf, ref o, length); data.NameValue = BinarySerializer.DeSerializeString(buf, ref o, length, 2); len = BinarySerializer.DeSerializeUInt16_Le(buf, ref o, length); data.Data2 = new byte[len]; Array.Copy(buf, o, data.Data2, 0, len); o += len; data.Text = BinarySerializer.DeSerializeString(buf, ref o, length, 1); data.TextColour = BinarySerializer.DeSerializeColor(buf, ref o, length); data.MediaUrl = BinarySerializer.DeSerializeString(buf, ref o, length, 1); len = buf[o++]; data.ParticleSystemData = new byte[len]; Array.Copy(buf, o, data.ParticleSystemData, 0, len); o += len; len = buf[o++]; data.ExtraParameters = BinarySerializer.DeSerializeExtraParameters(buf, ref o, o + len); data.SoundId = BinarySerializer.DeSerializeGuid(buf, ref o, length); data.OwnerId = BinarySerializer.DeSerializeGuid(buf, ref o, length); data.Gain = BinarySerializer.DeSerializeUInt32_Le(buf, ref o, buf.Length); data.SoundFlags = (SoundFlags)buf[o++]; data.Radius = BinarySerializer.DeSerializeFloat_Le(buf, ref o, length); data.JointType = (JointType)buf[o++]; data.JointPivot = BinarySerializer.DeSerializeVector3(buf, ref o, buf.Length); data.JointAxisOrAnchor = BinarySerializer.DeSerializeVector3(buf, ref o, buf.Length); //Logger.LogDebug("ObjectUpdateMessage.DeSerialise", ToString()); } }
protected override void DeSerialise(byte[] buf, ref int o, int length) { RegionHandle = new RegionHandle(BinarySerializer.DeSerializeUInt64_Le(buf, ref o, length)); TimeDilation = BinarySerializer.DeSerializeUInt16_Le(buf, ref o, length); string logMessage = $"ObjectUpdateCompressed: RegionHandle={RegionHandle}, TimeDilation={TimeDilation}"; int nObjects = buf[o++]; for (int i = 0; i < nObjects; i++) { UInt32 len; ObjectUpdateMessage.ObjectData data = new ObjectUpdateMessage.ObjectData(); Objects.Add(data); data.UpdateFlags = (ObjectUpdateFlags)BinarySerializer.DeSerializeUInt32_Le(buf, ref o, length); int compressedLength = BinarySerializer.DeSerializeUInt16_Le(buf, ref o, length); byte[] compressedData = new byte[compressedLength]; Array.Copy(buf, o, compressedData, 0, compressedLength); o += compressedLength; int compressedOffset = 0; logMessage += $"\n Object {i}: UpdateFlags={data.UpdateFlags}, Data({compressedData.Length})={BitConverter.ToString(compressedData)}"; data.FullId = BinarySerializer.DeSerializeGuid(compressedData, ref compressedOffset, compressedLength); data.LocalId = BinarySerializer.DeSerializeUInt32_Le(compressedData, ref compressedOffset, compressedLength); data.PCode = (PCode)compressedData[compressedOffset++]; data.State = compressedData[compressedOffset++]; data.Crc = BinarySerializer.DeSerializeUInt32_Le(compressedData, ref compressedOffset, compressedLength); data.Material = (MaterialType)compressedData[compressedOffset++]; data.ClickAction = (ClickAction)compressedData[compressedOffset++]; data.Scale = BinarySerializer.DeSerializeVector3(compressedData, ref compressedOffset, compressedLength); data.Position = BinarySerializer.DeSerializeVector3(compressedData, ref compressedOffset, compressedLength); data.Rotation = BinarySerializer.DeSerializeQuaternion(compressedData, ref compressedOffset, compressedLength); CompressedFlags compressedFlags = (CompressedFlags)BinarySerializer.DeSerializeUInt32_Le(compressedData, ref compressedOffset, compressedLength); data.OwnerId = BinarySerializer.DeSerializeGuid(compressedData, ref compressedOffset, compressedLength); logMessage += $"\n FullId={data.FullId}, LocalId={data.LocalId}, PCode={data.PCode}, State={data.State}, Crc={data.Crc}, Material={data.Material}, ClickAction={data.ClickAction}, Scale={data.Scale}, Position={data.Position}, Rotation={data.Rotation}, CompressedFlags=({compressedFlags})"; if ((compressedFlags & CompressedFlags.HasAngularVelocity) != 0) { data.AngularVelocity = BinarySerializer.DeSerializeVector3(compressedData, ref compressedOffset, compressedLength); logMessage += $", AngularVelocity={data.AngularVelocity}"; } data.ParentId = (compressedFlags & CompressedFlags.HasParent) != 0 ? BinarySerializer.DeSerializeUInt32_Le(compressedData, ref compressedOffset, compressedLength) : (uint)0; logMessage += $", ParentId={data.ParentId}"; if ((compressedFlags & CompressedFlags.Tree) != 0) { byte treeSpecies = compressedData[compressedOffset++]; logMessage += $", TreeSpecies={treeSpecies}"; } if ((compressedFlags & CompressedFlags.ScratchPad) != 0) { len = compressedData[compressedOffset++]; compressedOffset += (int)len; // TODO: These offsets and length should all be UInt32 logMessage += $", Scratchpad({len})"; } if ((compressedFlags & CompressedFlags.HasText) != 0) { data.Text = BinarySerializer.DeSerializeString(compressedData, ref compressedOffset, compressedLength, 0); data.TextColour = BinarySerializer.DeSerializeColor(compressedData, ref compressedOffset, compressedLength); logMessage += $", Text={data.Text}, TextColour={data.TextColour}"; } if ((compressedFlags & CompressedFlags.MediaURL) != 0) { data.MediaUrl = BinarySerializer.DeSerializeString(compressedData, ref compressedOffset, compressedLength, 0); logMessage += $", MediaUrl={data.MediaUrl}"; } if ((compressedFlags & CompressedFlags.HasParticles) != 0) { // TODO: Parse the particle system data. OpenMetaverse says that this is a BitPack of 86 bytes. len = 86; compressedOffset += (int)len; logMessage += $", ParticleSystem({len})"; } data.ExtraParameters = BinarySerializer.DeSerializeExtraParameters(compressedData, ref compressedOffset, compressedOffset + compressedLength); if ((compressedFlags & CompressedFlags.HasSound) != 0) { data.SoundId = BinarySerializer.DeSerializeGuid(compressedData, ref compressedOffset, compressedLength); data.Gain = BinarySerializer.DeSerializeUInt32_Le(compressedData, ref compressedOffset, compressedLength); data.SoundFlags = (SoundFlags)compressedData[compressedOffset++]; data.Radius = BinarySerializer.DeSerializeFloat_Le(compressedData, ref compressedOffset, compressedLength); logMessage += $", SoundId={data.SoundId}, Gain={data.Gain}, SoundFlags={data.SoundFlags}, Radius={data.Radius}"; } if ((compressedFlags & CompressedFlags.HasNameValues) != 0) { data.NameValue = BinarySerializer.DeSerializeString(compressedData, ref compressedOffset, compressedLength, 0); logMessage += $", NameValue={data.NameValue}"; } data.PathCurve = (PathType)compressedData[compressedOffset++]; data.PathBegin = BinarySerializer.DeSerializeUInt16_Le(compressedData, ref compressedOffset, length) * CUT_QUANTA; data.PathEnd = BinarySerializer.DeSerializeUInt16_Le(compressedData, ref compressedOffset, length) * CUT_QUANTA; data.PathScaleX = compressedData[compressedOffset++] * SCALE_QUANTA; data.PathScaleY = compressedData[compressedOffset++] * SCALE_QUANTA; data.PathShearX = compressedData[compressedOffset++] * SHEAR_QUANTA; data.PathShearY = compressedData[compressedOffset++] * SHEAR_QUANTA; data.PathTwist = (sbyte)compressedData[compressedOffset++] * SCALE_QUANTA; data.PathTwistBegin = (sbyte)compressedData[compressedOffset++] * SCALE_QUANTA; data.PathRadiusOffset = (sbyte)compressedData[compressedOffset++] * SCALE_QUANTA; data.PathTaperX = (sbyte)compressedData[compressedOffset++] * TAPER_QUANTA; data.PathTaperY = (sbyte)compressedData[compressedOffset++] * TAPER_QUANTA; data.PathRevolutions = compressedData[compressedOffset++] * REV_QUANTA; data.PathSkew = (sbyte)compressedData[compressedOffset++] * SCALE_QUANTA; data.ProfileCurve = (ProfileType)compressedData[compressedOffset++]; data.ProfileBegin = BinarySerializer.DeSerializeUInt16_Le(compressedData, ref compressedOffset, length) * CUT_QUANTA; data.ProfileEnd = BinarySerializer.DeSerializeUInt16_Le(compressedData, ref compressedOffset, length) * CUT_QUANTA; data.ProfileHollow = BinarySerializer.DeSerializeUInt16_Le(compressedData, ref compressedOffset, length) * HOLLOW_QUANTA; data.TextureEntry = BinarySerializer.DeSerializeTextureEntry(compressedData, ref compressedOffset, compressedLength, true); logMessage += $", TextureEntry={data.TextureEntry}"; if ((compressedFlags & CompressedFlags.TextureAnimation) != 0) { data.TextureAnimation = BinarySerializer.DeSerializeTextureAnimation(compressedData, ref compressedOffset, compressedLength); logMessage += ", TextureAnimation"; } data.IsAttachment = (compressedFlags & CompressedFlags.HasNameValues) != 0 && data.ParentId != 0; } //Logger.LogDebug("ObjectUpdateCompressedMessage.DeSerialise", logMessage); }
protected override void DeSerialise(byte[] buf, ref int o, int length) { RegionHandle = new RegionHandle(BinarySerializer.DeSerializeUInt64_Le(buf, ref o, length)); TimeDilation = BinarySerializer.DeSerializeUInt16_Le(buf, ref o, length); string logMessage = $"ObjectUpdateCompressed: RegionHandle={RegionHandle}, TimeDilation={TimeDilation}"; int nObjects = buf[o++]; for (int i = 0; i < nObjects; i++) { UInt32 len; ObjectUpdateMessage.ObjectData data = new ObjectUpdateMessage.ObjectData(); Objects.Add(data); data.UpdateFlags = (ObjectUpdateFlags)BinarySerializer.DeSerializeUInt32_Le(buf, ref o, length); int compressedLength = BinarySerializer.DeSerializeUInt16_Le(buf, ref o, length); byte[] compressedData = new byte[compressedLength]; Array.Copy(buf, o, compressedData, 0, compressedLength); o += compressedLength; int compressedOffset = 0; logMessage += $"\n Object {i}: UpdateFlags={data.UpdateFlags}, Data({compressedData.Length})={BitConverter.ToString(compressedData)}"; data.FullId = BinarySerializer.DeSerializeGuid(compressedData, ref compressedOffset, compressedLength); data.LocalId = BinarySerializer.DeSerializeUInt32_Le(compressedData, ref compressedOffset, compressedLength); data.PCode = (PCode)compressedData[compressedOffset++]; data.State = compressedData[compressedOffset++]; data.Crc = BinarySerializer.DeSerializeUInt32_Le(compressedData, ref compressedOffset, compressedLength); data.Material = (MaterialType)compressedData[compressedOffset++]; data.ClickAction = (ClickAction)compressedData[compressedOffset++]; data.Scale = BinarySerializer.DeSerializeVector3(compressedData, ref compressedOffset, compressedLength); data.Position = BinarySerializer.DeSerializeVector3(compressedData, ref compressedOffset, compressedLength); data.Rotation = BinarySerializer.DeSerializeQuaternion(compressedData, ref compressedOffset, compressedLength); CompressedFlags compressedFlags = (CompressedFlags)BinarySerializer.DeSerializeUInt32_Le(compressedData, ref compressedOffset, compressedLength); data.OwnerId = BinarySerializer.DeSerializeGuid(compressedData, ref compressedOffset, compressedLength); logMessage += $"\n FullId={data.FullId}, LocalId={data.LocalId}, PCode={data.PCode}, State={data.State}, Crc={data.Crc}, Material={data.Material}, ClickAction={data.ClickAction}, Scale={data.Scale}, Position={data.Position}, Rotation={data.Rotation}, CompressedFlags=({compressedFlags})"; if ((compressedFlags & CompressedFlags.HasAngularVelocity) != 0) { data.AngularVelocity = BinarySerializer.DeSerializeVector3(compressedData, ref compressedOffset, compressedLength); logMessage += $", AngularVelocity={data.AngularVelocity}"; } data.ParentId = (compressedFlags & CompressedFlags.HasParent) != 0 ? BinarySerializer.DeSerializeUInt32_Le(compressedData, ref compressedOffset, compressedLength) : (uint)0; logMessage += $", ParentId={data.ParentId}"; if ((compressedFlags & CompressedFlags.Tree) != 0) { byte treeSpecies = compressedData[compressedOffset++]; logMessage += $", TreeSpecies={treeSpecies}"; } if ((compressedFlags & CompressedFlags.ScratchPad) != 0) { len = compressedData[compressedOffset++]; compressedOffset += (int)len; // TODO: These offsets and length should all be UInt32 logMessage += $", Scratchpad({len})"; } if ((compressedFlags & CompressedFlags.HasText) != 0) { data.Text = BinarySerializer.DeSerializeString(compressedData, ref compressedOffset, compressedLength, 0); data.TextColour = BinarySerializer.DeSerializeColor(compressedData, ref compressedOffset, compressedLength); logMessage += $", Text={data.Text}, TextColour={data.TextColour}"; } if ((compressedFlags & CompressedFlags.MediaURL) != 0) { data.MediaUrl = BinarySerializer.DeSerializeString(compressedData, ref compressedOffset, compressedLength, 0); logMessage += $", MediaUrl={data.MediaUrl}"; } if ((compressedFlags & CompressedFlags.HasParticles) != 0) { len = 86; logMessage += $", ParticleSystem({len})"; } byte nExtraParameters = compressedData[compressedOffset++]; for (int j = 0; j < nExtraParameters; j++) { if (j == 0) { logMessage += ", ExtraParameters=("; } ExtraParamType type = (ExtraParamType)BinarySerializer.DeSerializeUInt16_Le(compressedData, ref compressedOffset, compressedLength); len = BinarySerializer.DeSerializeUInt32_Le(compressedData, ref compressedOffset, compressedLength); switch (type) { case ExtraParamType.Flexible: break; case ExtraParamType.Light: break; case ExtraParamType.Sculpt: break; case ExtraParamType.LightImage: break; case ExtraParamType.Mesh: break; default: throw new ArgumentOutOfRangeException(); } logMessage += $"{type}, "; compressedOffset += (int)len; // TODO: These offsets and length should all be UInt32 if (j == nExtraParameters - 1) { logMessage += ")"; } } if ((compressedFlags & CompressedFlags.HasSound) != 0) { data.SoundId = BinarySerializer.DeSerializeGuid(compressedData, ref compressedOffset, compressedLength); data.Gain = BinarySerializer.DeSerializeUInt32_Le(compressedData, ref compressedOffset, compressedLength); data.SoundFlags = (SoundFlags)compressedData[compressedOffset++]; data.Radius = BinarySerializer.DeSerializeFloat_Le(compressedData, ref compressedOffset, compressedLength); logMessage += $", SoundId={data.SoundId}, Gain={data.Gain}, SoundFlags={data.SoundFlags}, Radius={data.Radius}"; } if ((compressedFlags & CompressedFlags.HasNameValues) != 0) { data.NameValue = BinarySerializer.DeSerializeString(compressedData, ref compressedOffset, compressedLength, 0); logMessage += $", NameValue={data.NameValue}"; } data.PathCurve = (PathType)compressedData[compressedOffset++]; data.PathBegin = BinarySerializer.DeSerializeUInt16_Le(compressedData, ref compressedOffset, length) * CUT_QUANTA; data.PathEnd = BinarySerializer.DeSerializeUInt16_Le(compressedData, ref compressedOffset, length) * CUT_QUANTA; data.PathScaleX = compressedData[compressedOffset++] * SCALE_QUANTA; data.PathScaleY = compressedData[compressedOffset++] * SCALE_QUANTA; data.PathShearX = compressedData[compressedOffset++] * SHEAR_QUANTA; data.PathShearY = compressedData[compressedOffset++] * SHEAR_QUANTA; data.PathTwist = (sbyte)compressedData[compressedOffset++] * SCALE_QUANTA; data.PathTwistBegin = (sbyte)compressedData[compressedOffset++] * SCALE_QUANTA; data.PathRadiusOffset = (sbyte)compressedData[compressedOffset++] * SCALE_QUANTA; data.PathTaperX = (sbyte)compressedData[compressedOffset++] * TAPER_QUANTA; data.PathTaperY = (sbyte)compressedData[compressedOffset++] * TAPER_QUANTA; data.PathRevolutions = compressedData[compressedOffset++] * REV_QUANTA; data.PathSkew = (sbyte)compressedData[compressedOffset++] * SCALE_QUANTA; data.ProfileCurve = (ProfileType)compressedData[compressedOffset++]; data.ProfileBegin = BinarySerializer.DeSerializeUInt16_Le(compressedData, ref compressedOffset, length) * CUT_QUANTA; data.ProfileEnd = BinarySerializer.DeSerializeUInt16_Le(compressedData, ref compressedOffset, length) * CUT_QUANTA; data.ProfileHollow = BinarySerializer.DeSerializeUInt16_Le(compressedData, ref compressedOffset, length) * HOLLOW_QUANTA; UInt32 textureEntryLength = BinarySerializer.DeSerializeUInt32_Le(compressedData, ref compressedOffset, length); logMessage += $", textures({textureEntryLength})"; compressedOffset += (int)textureEntryLength; if ((compressedFlags & CompressedFlags.TextureAnimation) != 0) { TextureAnimation textureAnimation = new TextureAnimation() { Mode = (TextureAnimationMode)compressedData[compressedOffset++], Face = compressedData[compressedOffset++], SizeX = compressedData[compressedOffset++], SizeY = compressedData[compressedOffset++], Start = BinarySerializer.DeSerializeFloat_Le(compressedData, ref compressedOffset, length), Length = BinarySerializer.DeSerializeFloat_Le(compressedData, ref compressedOffset, length), Rate = BinarySerializer.DeSerializeFloat_Le(compressedData, ref compressedOffset, length) }; logMessage += ", TextureAnimation"; } data.IsAttachment = (compressedFlags & CompressedFlags.HasNameValues) != 0 && data.ParentId != 0; } //Logger.LogDebug(logMessage); }