corrade-vassal – Rev 16
?pathlinks?
/*
* Copyright (c) 2006-2014, openmetaverse.org
* All rights reserved.
*
* - Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* - Neither the name of the openmetaverse.org nor the names
* of its contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
namespace OpenMetaverse.Packets
{
public static class PacketDecoder
{
/// <summary>
/// A custom decoder callback
/// </summary>
/// <param name="fieldName">The key of the object</param>
/// <param name="fieldData">the data to decode</param>
/// <returns>A string represending the fieldData</returns>
public delegate string CustomPacketDecoder(string fieldName, object fieldData);
private static Dictionary<string, List<CustomPacketDecoder>> Callbacks = new Dictionary<string, List<CustomPacketDecoder>>();
static PacketDecoder()
{
AddCallback("Color", DecodeColorField);
AddCallback("TextColor", DecodeColorField);
AddCallback("Timestamp", DecodeTimeStamp);
AddCallback("EstateCovenantReply.Data.CovenantTimestamp", DecodeTimeStamp);
AddCallback("CreationDate", DecodeTimeStamp);
AddCallback("BinaryBucket", DecodeBinaryBucket);
AddCallback("ParcelData.Data", DecodeBinaryToHexString);
AddCallback("LayerData.Data", DecodeBinaryToHexString);
AddCallback("ImageData.Data", DecodeImageData);
AddCallback("TransferData.Data", DecodeBinaryToHexString);
AddCallback("ObjectData.TextureEntry", DecodeTextureEntry);
AddCallback("ImprovedInstantMessage.MessageBlock.Dialog", DecodeDialog);
// Inventory/Permissions
AddCallback("BaseMask", DecodePermissionMask);
AddCallback("OwnerMask", DecodePermissionMask);
AddCallback("EveryoneMask", DecodePermissionMask);
AddCallback("NextOwnerMask", DecodePermissionMask);
AddCallback("GroupMask", DecodePermissionMask);
// FetchInventoryDescendents
AddCallback("InventoryData.SortOrder", DecodeInventorySort);
AddCallback("WearableType", DecodeWearableType);
//
AddCallback("InventoryData.Type", DecodeInventoryType);
AddCallback("InvType", DecodeInventoryInvType);
AddCallback("InventoryData.Flags", DecodeInventoryFlags);
// BulkUpdateInventory
AddCallback("ItemData.Type", DecodeInventoryType);
AddCallback("ItemData.Flags", DecodeInventoryFlags);
AddCallback("SaleType", DecodeObjectSaleType);
AddCallback("ScriptControlChange.Data.Controls", DecodeScriptControls);
AddCallback("RegionFlags", DecodeRegionFlags);
AddCallback("SimAccess", DecodeSimAccess);
AddCallback("ControlFlags", DecodeControlFlags);
// AgentUpdate
AddCallback("AgentUpdate.AgentData.State", DecodeAgentState);
AddCallback("AgentUpdate.AgentData.Flags", DecodeAgentFlags);
// ViewerEffect TypeData
AddCallback("ViewerEffect.Effect.TypeData", DecodeViewerEffectTypeData);
AddCallback("ViewerEffect.Effect.Type", DecodeViewerEffectType);
// Prim/ObjectUpdate decoders
AddCallback("ObjectUpdate.ObjectData.PCode", DecodeObjectPCode);
AddCallback("ObjectUpdate.ObjectData.Material", DecodeObjectMaterial);
AddCallback("ObjectUpdate.ObjectData.ClickAction", DecodeObjectClickAction);
AddCallback("ObjectData.UpdateFlags", DecodeObjectUpdateFlags);
AddCallback("ObjectUpdate.ObjectData.ObjectData", DecodeObjectData);
AddCallback("TextureAnim", DecodeObjectTextureAnim);
AddCallback("ObjectUpdate.ObjectData.NameValue", DecodeNameValue);
AddCallback("ObjectUpdate.ObjectData.Data", DecodeObjectData);
AddCallback("ObjectUpdate.ObjectData.PSBlock", DecodeObjectParticleSystem);
AddCallback("ParticleSys", DecodeObjectParticleSystem);
AddCallback("ObjectUpdate.ObjectData.ExtraParams", DecodeObjectExtraParams);
AddCallback("ImprovedTerseObjectUpdate.ObjectData.Data", DecodeTerseUpdate);
AddCallback("ImprovedTerseObjectUpdate.ObjectData.TextureEntry", DecodeTerseTextureEntry);
AddCallback("ObjectUpdateCompressed.ObjectData.Data", DecodeObjectCompressedData);
// ImprovedTerseObjectUpdate & ObjectUpdate AttachmentPoint & ObjectUpdateCompressed
AddCallback("ObjectData.State", DecodeObjectState);
//AddCallback("ObjectUpdateCompressed.ObjectData.State", DecodeObjectState);
//AddCallback("ImprovedTerseObjectUpdate.ObjectData.State", DecodeObjectState);
// ChatFromSimulator
AddCallback("ChatData.SourceType", DecodeChatSourceType);
AddCallback("ChatData.ChatType", DecodeChatChatType);
AddCallback("ChatData.Audible", DecodeChatAudible);
AddCallback("AttachedSound.DataBlock.Flags", DecodeAttachedSoundFlags);
AddCallback("RequestImage.Type", DecodeImageType);
AddCallback("EstateOwnerMessage.ParamList.Parameter", DecodeEstateParameter);
AddCallback("Codec", DecodeImageCodec);
AddCallback("Info.TeleportFlags", DecodeTeleportFlags);
// map
AddCallback("MapBlockRequest.AgentData.Flags", DecodeMapRequestFlags);
AddCallback("MapItemRequest.AgentData.Flags", DecodeMapRequestFlags);
AddCallback("MapBlockReply.Data.Access", DecodeMapAccess);
AddCallback("FolderData.Type", DecodeFolderType);
AddCallback("RequestData.ItemType", DecodeGridItemType);
// TransferRequest/TransferInfo
AddCallback("TransferInfo.Params", DecodeTransferParams);
AddCallback("TransferInfo.ChannelType", DecodeTransferChannelType);
AddCallback("TransferInfo.SourceType", DecodeTransferSourceType);
AddCallback("TransferInfo.TargetType", DecodeTransferTargetType);
AddCallback("TransferData.ChannelType", DecodeTransferChannelType);
// SendXferPacket
AddCallback("DataPacket.Data", DecodeBinaryToHexString);
// Directory Manager
AddCallback("DirClassifiedQuery.QueryData.QueryFlags", DecodeDirClassifiedQueryFlags);
AddCallback("QueryData.QueryFlags", DecodeDirQueryFlags);
AddCallback("Category", DecodeCategory);
AddCallback("QueryData.SearchType", SearchTypeFlags);
AddCallback("ClassifiedFlags", DecodeDirClassifiedFlags);
AddCallback("EventFlags", DecodeEventFlags);
AddCallback("ParcelAccessListRequest.Data.Flags", DecodeParcelACL);
AddCallback("ParcelAccessListReply.Data.Flags", DecodeParcelACL);
//AddCallback("ParcelAccessListReply.List.Flags", DecodeParcelACLReply);
// AgentAnimation
AddCallback("AnimID", DecodeAnimToConst);
AddCallback("LayerData.LayerID.Type", DecodeLayerDataType);
AddCallback("GroupPowers", DecodeGroupPowers);
}
/// <summary>
/// Add a custom decoder callback
/// </summary>
/// <param name="key">The key of the field to decode</param>
/// <param name="customPacketHandler">The custom decode handler</param>
public static void AddCallback(string key, CustomPacketDecoder customPacketHandler)
{
if (Callbacks.ContainsKey(key))
{
lock (Callbacks)
Callbacks[key].Add(customPacketHandler);
}
else
{
lock (Callbacks)
Callbacks.Add(key, new List<CustomPacketDecoder>() { customPacketHandler });
}
}
/// <summary>
/// Remove a custom decoder callback
/// </summary>
/// <param name="key">The key of the field to decode</param>
/// <param name="customPacketHandler">The custom decode handler</param>
public static void RemoveCustomHandler(string key, CustomPacketDecoder customPacketHandler)
{
if (Callbacks.ContainsKey(key))
lock (Callbacks)
{
if (Callbacks[key].Contains(customPacketHandler))
Callbacks[key].Remove(customPacketHandler);
}
}
#region Custom Decoders
private static string DecodeTerseUpdate(string fieldName, object fieldData)
{
byte[] block = (byte[])fieldData;
int i = 4;
StringBuilder result = new StringBuilder();
// LocalID
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
"LocalID",
Utils.BytesToUInt(block, 0),
"Uint32");
// State
byte point = block[i++];
result.AppendFormat("{0,30}: {1,-3} {2,-36} [{3}]" + Environment.NewLine,
"State",
point,
"(" + (AttachmentPoint)point + ")",
"AttachmentPoint");
// Avatar boolean
bool isAvatar = (block[i++] != 0);
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
"IsAvatar",
isAvatar,
"Boolean");
// Collision normal for avatar
if (isAvatar)
{
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
"CollisionPlane",
new Vector4(block, i),
"Vector4");
i += 16;
}
// Position
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
"Position",
new Vector3(block, i),
"Vector3");
i += 12;
// Velocity
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
"Velocity",
new Vector3(
Utils.UInt16ToFloat(block, i, -128.0f, 128.0f),
Utils.UInt16ToFloat(block, i + 2, -128.0f, 128.0f),
Utils.UInt16ToFloat(block, i + 4, -128.0f, 128.0f)),
"Vector3");
i += 6;
// Acceleration
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
"Acceleration",
new Vector3(
Utils.UInt16ToFloat(block, i, -64.0f, 64.0f),
Utils.UInt16ToFloat(block, i + 2, -64.0f, 64.0f),
Utils.UInt16ToFloat(block, i + 4, -64.0f, 64.0f)),
"Vector3");
i += 6;
// Rotation (theta)
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
"Rotation",
new Quaternion(
Utils.UInt16ToFloat(block, i, -1.0f, 1.0f),
Utils.UInt16ToFloat(block, i + 2, -1.0f, 1.0f),
Utils.UInt16ToFloat(block, i + 4, -1.0f, 1.0f),
Utils.UInt16ToFloat(block, i + 6, -1.0f, 1.0f)),
"Quaternion");
i += 8;
// Angular velocity (omega)
result.AppendFormat("{0,30}: {1,-40} [{2}]",
"AngularVelocity",
new Vector3(
Utils.UInt16ToFloat(block, i, -64.0f, 64.0f),
Utils.UInt16ToFloat(block, i + 2, -64.0f, 64.0f),
Utils.UInt16ToFloat(block, i + 4, -64.0f, 64.0f)),
"Vector3");
//pos += 6;
// TODO: What is in these 6 bytes?
return result.ToString();
}
private static string DecodeObjectCompressedData(string fieldName, object fieldData)
{
StringBuilder result = new StringBuilder();
byte[] block = (byte[])fieldData;
int i = 0;
// UUID
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
"ID",
new UUID(block, 0),
"UUID");
i += 16;
// Local ID
uint LocalID = (uint)(block[i++] + (block[i++] << 8) +
(block[i++] << 16) + (block[i++] << 24));
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
"LocalID",
LocalID,
"Uint32");
// PCode
PCode pcode = (PCode)block[i++];
result.AppendFormat("{0,30}: {1,-3} {2,-36} [{3}]" + Environment.NewLine,
"PCode",
(int)pcode,
"(" + pcode + ")",
"PCode");
// State
AttachmentPoint point = (AttachmentPoint)block[i++];
result.AppendFormat("{0,30}: {1,-3} {2,-36} [{3}]" + Environment.NewLine,
"State",
(byte)point,
"(" + point + ")",
"AttachmentPoint");
// TODO: CRC
i += 4;
// Material
result.AppendFormat("{0,30}: {1,-3} {2,-36} [{3}]" + Environment.NewLine,
"Material",
block[i],
"(" + (Material)block[i++] + ")",
"Material");
// Click action
result.AppendFormat("{0,30}: {1,-3} {2,-36} [{3}]" + Environment.NewLine,
"ClickAction",
block[i],
"(" + (ClickAction)block[i++] + ")",
"ClickAction");
// Scale
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
"Scale",
new Vector3(block, i),
"Vector3");
i += 12;
// Position
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
"Position",
new Vector3(block, i),
"Vector3");
i += 12;
// Rotation
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
"Rotation",
new Vector3(block, i),
"Vector3");
i += 12;
// Compressed flags
CompressedFlags flags = (CompressedFlags)Utils.BytesToUInt(block, i);
result.AppendFormat("{0,30}: {1,-10} {2,-29} [{3}]" + Environment.NewLine,
"CompressedFlags",
Utils.BytesToUInt(block, i),
"(" + (CompressedFlags)Utils.BytesToUInt(block, i) + ")",
"UInt");
i += 4;
// Owners ID
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
"OwnerID",
new UUID(block, i),
"UUID");
i += 16;
// Angular velocity
if ((flags & CompressedFlags.HasAngularVelocity) != 0)
{
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
"AngularVelocity",
new Vector3(block, i),
"Vector3");
i += 12;
}
// Parent ID
if ((flags & CompressedFlags.HasParent) != 0)
{
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
"ParentID",
(uint)(block[i++] + (block[i++] << 8) +
(block[i++] << 16) + (block[i++] << 24)),
"UInt");
}
// Tree data
if ((flags & CompressedFlags.Tree) != 0)
{
result.AppendFormat("{0,30}: {1,-2} {2,-37} [{3}]" + Environment.NewLine,
"TreeSpecies",
block[i++],
"(" + (Tree)block[i] + ")",
"Tree");
}
// Scratch pad
else if ((flags & CompressedFlags.ScratchPad) != 0)
{
int size = block[i++];
byte[] scratch = new byte[size];
Buffer.BlockCopy(block, i, scratch, 0, size);
result.AppendFormat("{0,30}: {1,-40} [ScratchPad[]]" + Environment.NewLine,
"ScratchPad",
Utils.BytesToHexString(scratch, String.Format("{0,30}", "Data")));
i += size;
}
// Floating text
if ((flags & CompressedFlags.HasText) != 0)
{
string text = String.Empty;
while (block[i] != 0)
{
text += (char)block[i];
i++;
}
i++;
// Floating text
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
"Text",
text,
"string");
// Text color
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
"TextColor",
new Color4(block, i, false),
"Color4");
i += 4;
}
// Media URL
if ((flags & CompressedFlags.MediaURL) != 0)
{
string text = String.Empty;
while (block[i] != 0)
{
text += (char)block[i];
i++;
}
i++;
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
"MediaURL",
text,
"string");
}
// Particle system
if ((flags & CompressedFlags.HasParticles) != 0)
{
Primitive.ParticleSystem p = new Primitive.ParticleSystem(block, i);
result.AppendLine(DecodeObjectParticleSystem("ParticleSystem", p));
i += 86;
}
// Extra parameters TODO:
Primitive prim = new Primitive();
i += prim.SetExtraParamsFromBytes(block, i);
//Sound data
if ((flags & CompressedFlags.HasSound) != 0)
{
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
"SoundID",
new UUID(block, i),
"UUID");
i += 16;
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
"SoundGain",
Utils.BytesToFloat(block, i),
"Float");
i += 4;
result.AppendFormat("{0,30}: {1,-2} {2,-37} [{3}]" + Environment.NewLine,
"SoundFlags",
block[i++],
"(" + (SoundFlags)block[i] + ")",
"SoundFlags");
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
"SoundRadius",
Utils.BytesToFloat(block, i),
"Float");
i += 4;
}
// Name values
if ((flags & CompressedFlags.HasNameValues) != 0)
{
string text = String.Empty;
while (block[i] != 0)
{
text += (char)block[i];
i++;
}
i++;
// Parse the name values
if (text.Length > 0)
{
string[] lines = text.Split('\n');
NameValue[] 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;
}
}
DecodeNameValue("NameValues", nameValues);
}
}
result.AppendFormat("{0,30}: {1,-2} {2,-37} [{3}]" + Environment.NewLine,
"PathCurve",
block[i],
"(" + (PathCurve)block[i++] + ")",
"PathCurve");
ushort pathBegin = Utils.BytesToUInt16(block, i);
i += 2;
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
"PathBegin",
Primitive.UnpackBeginCut(pathBegin),
"float");
ushort pathEnd = Utils.BytesToUInt16(block, i);
i += 2;
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
"PathEnd",
Primitive.UnpackEndCut(pathEnd),
"float");
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
"PathScaleX",
Primitive.UnpackPathScale(block[i++]),
"float");
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
"PathScaleY",
Primitive.UnpackPathScale(block[i++]),
"float");
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
"PathShearX",
Primitive.UnpackPathShear((sbyte)block[i++]),
"float");
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
"PathShearY",
Primitive.UnpackPathShear((sbyte)block[i++]),
"float");
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
"PathTwist",
Primitive.UnpackPathTwist((sbyte)block[i++]),
"float");
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
"PathTwistBegin",
Primitive.UnpackPathTwist((sbyte)block[i++]),
"float");
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
"PathRadiusOffset",
Primitive.UnpackPathTwist((sbyte)block[i++]),
"float");
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
"PathTaperX",
Primitive.UnpackPathTaper((sbyte)block[i++]),
"float");
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
"PathTaperY",
Primitive.UnpackPathTaper((sbyte)block[i++]),
"float");
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
"PathRevolutions",
Primitive.UnpackPathRevolutions(block[i++]),
"float");
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
"PathSkew",
Primitive.UnpackPathTwist((sbyte)block[i++]),
"float");
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
"ProfileCurve",
block[i++],
"float");
ushort profileBegin = Utils.BytesToUInt16(block, i);
i += 2;
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
"ProfileBegin",
Primitive.UnpackBeginCut(profileBegin),
"float");
ushort profileEnd = Utils.BytesToUInt16(block, i);
i += 2;
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
"ProfileEnd",
Primitive.UnpackEndCut(profileEnd),
"float");
ushort profileHollow = Utils.BytesToUInt16(block, i);
i += 2;
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
"ProfileHollow",
Primitive.UnpackProfileHollow(profileHollow),
"float");
int textureEntryLength = (int)Utils.BytesToUInt(block, i);
i += 4;
//prim.Textures = new Primitive.TextureEntry(block, i, textureEntryLength);
String s = DecodeTextureEntry("TextureEntry", new Primitive.TextureEntry(block, i, textureEntryLength));
result.AppendLine(s);
i += textureEntryLength;
// Texture animation
if ((flags & CompressedFlags.TextureAnimation) != 0)
{
i += 4;
string a = DecodeObjectTextureAnim("TextureAnimation", new Primitive.TextureAnimation(block, i));
result.AppendLine(a);
}
return result.ToString();
}
private static string DecodeObjectData(string fieldName, object fieldData)
{
byte[] data = (byte[])fieldData;
if (data.Length == 1)
{
return String.Format("{0,30}: {1,2} {2,-38} [{3}]",
fieldName + " (Tree Species)",
fieldData,
"(" + (Tree)(byte)fieldData + ")",
fieldData.GetType().Name);
}
else if (data.Length == 60)
{
/* TODO: these are likely useful packed fields,
* need to unpack them */
return Utils.BytesToHexString((byte[])fieldData, String.Format("{0,30}", fieldName));
}
else
{
return Utils.BytesToHexString((byte[])fieldData, String.Format("{0,30}", fieldName));
}
}
private static string DecodeObjectTextureAnim(string fieldName, object fieldData)
{
StringBuilder result = new StringBuilder();
Primitive.TextureAnimation TextureAnim;
if (fieldData is Primitive.TextureAnimation)
TextureAnim = (Primitive.TextureAnimation)fieldData;
else
TextureAnim = new Primitive.TextureAnimation((byte[])fieldData, 0);
result.AppendFormat("{0,30}", " <TextureAnimation>" + Environment.NewLine);
GenericTypeDecoder(TextureAnim, ref result);
result.AppendFormat("{0,30}", "</TextureAnimation>");
return result.ToString();
}
private static string DecodeEstateParameter(string fieldName, object fieldData)
{
byte[] bytes = (byte[])fieldData;
if (bytes.Length == 17)
{
return String.Format("{0,30}: {1,-40} [UUID]", fieldName, new UUID((byte[])fieldData, 0));
}
else
{
return String.Format("{0,30}: {1,-40} [Byte[]]", fieldName, Utils.BytesToString((byte[])fieldData));
}
}
private static string DecodeNameValue(string fieldName, object fieldData)
{
string nameValue = Utils.BytesToString((byte[])fieldData);
NameValue[] nameValues = null;
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]);
nameValues[i] = nv;
}
}
}
StringBuilder result = new StringBuilder();
result.AppendFormat("{0,30}", " <NameValues>" + Environment.NewLine);
if (nameValues != null)
{
for (int i = 0; i < nameValues.Length; i++)
{
result.AppendFormat(
"{0,30}: Name={1} Value={2} Class={3} Type={4} Sendto={5}" + Environment.NewLine, "NameValue",
nameValues[i].Name, nameValues[i].Value, nameValues[i].Class, nameValues[i].Type, nameValues[i].Sendto);
}
}
result.AppendFormat("{0,30}", "</NameValues>");
return result.ToString();
}
private static string DecodeObjectExtraParams(string fieldName, object fieldData)
{
byte[] data = (byte[])fieldData;
int i = 0;
//int totalLength = 1;
Primitive.FlexibleData Flexible = null;
Primitive.LightData Light = null;
Primitive.SculptData Sculpt = null;
byte extraParamCount = data[i++];
for (int k = 0; k < extraParamCount; k++)
{
ExtraParamType type = (ExtraParamType)Utils.BytesToUInt16(data, i);
i += 2;
uint paramLength = Utils.BytesToUInt(data, i);
i += 4;
if (type == ExtraParamType.Flexible)
Flexible = new Primitive.FlexibleData(data, i);
else if (type == ExtraParamType.Light)
Light = new Primitive.LightData(data, i);
else if (type == ExtraParamType.Sculpt)
Sculpt = new Primitive.SculptData(data, i);
i += (int)paramLength;
//totalLength += (int)paramLength + 6;
}
StringBuilder result = new StringBuilder();
result.AppendFormat("{0,30}", "<ExtraParams>" + Environment.NewLine);
if (Flexible != null)
{
result.AppendFormat("{0,30}", "<Flexible>" + Environment.NewLine);
GenericTypeDecoder(Flexible, ref result);
result.AppendFormat("{0,30}", "</Flexible>" + Environment.NewLine);
}
if (Sculpt != null)
{
result.AppendFormat("{0,30}", "<Sculpt>" + Environment.NewLine);
GenericTypeDecoder(Sculpt, ref result);
result.AppendFormat("{0,30}", "</Sculpt>" + Environment.NewLine);
}
if (Light != null)
{
result.AppendFormat("{0,30}", "<Light>" + Environment.NewLine);
GenericTypeDecoder(Light, ref result);
result.AppendFormat("{0,30}", "</Light>" + Environment.NewLine);
}
result.AppendFormat("{0,30}", "</ExtraParams>");
return result.ToString();
}
private static string DecodeObjectParticleSystem(string fieldName, object fieldData)
{
StringBuilder result = new StringBuilder();
Primitive.ParticleSystem ParticleSys;
if (fieldData is Primitive.ParticleSystem)
ParticleSys = (Primitive.ParticleSystem)fieldData;
else
ParticleSys = new Primitive.ParticleSystem((byte[])fieldData, 0);
result.AppendFormat("{0,30}", "<ParticleSystem>" + Environment.NewLine);
GenericTypeDecoder(ParticleSys, ref result);
result.AppendFormat("{0,30}", "</ParticleSystem>");
return result.ToString();
}
private static void GenericTypeDecoder(object obj, ref StringBuilder result)
{
FieldInfo[] fields = obj.GetType().GetFields();
foreach (FieldInfo field in fields)
{
String special;
if (SpecialDecoder("a" + "." + "b" + "." + field.Name,
field.GetValue(obj), out special))
{
result.AppendLine(special);
}
else
{
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
field.Name,
field.GetValue(obj),
field.FieldType.Name);
}
}
}
private static string DecodeObjectPCode(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-3} {2,-36} [PCode]",
fieldName,
fieldData,
"(" + (PCode)(byte)fieldData + ")");
}
private static string DecodeImageType(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-3} {2,-36} [ImageType]",
fieldName,
fieldData,
"(" + (ImageType)(byte)fieldData + ")");
}
private static string DecodeImageCodec(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-3} {2,-36} [ImageCodec]",
fieldName,
fieldData,
"(" + (ImageCodec)(byte)fieldData + ")");
}
private static string DecodeObjectMaterial(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-3} {2,-36} [Material]",
fieldName,
fieldData,
"(" + (Material)(byte)fieldData + ")");
}
private static string DecodeObjectClickAction(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-3} {2,-36} [ClickAction]",
fieldName,
fieldData,
"(" + (ClickAction)(byte)fieldData + ")");
}
private static string DecodeEventFlags(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-3} {2,-36} [EventFlags]",
fieldName,
fieldData,
"(" + (DirectoryManager.EventFlags)(uint)fieldData + ")");
}
private static string DecodeDirQueryFlags(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-10} {2,-29} [DirectoryManager.DirFindFlags]",
fieldName,
fieldData,
"(" + (DirectoryManager.DirFindFlags)(uint)fieldData + ")");
}
private static string DecodeDirClassifiedQueryFlags(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-10} {2,-29} [ClassifiedQueryFlags]",
fieldName,
fieldData,
"(" + (DirectoryManager.ClassifiedQueryFlags)(uint)fieldData + ")");
}
private static string DecodeDirClassifiedFlags(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-10} {2,-29} [ClassifiedFlags]",
fieldName,
fieldData,
"(" + (DirectoryManager.ClassifiedFlags)(byte)fieldData + ")");
}
private static string DecodeGroupPowers(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-20} {2,-19} [GroupPowers]",
fieldName,
fieldData,
"(" + (GroupPowers)(ulong)fieldData + ")");
}
private static string DecodeParcelACL(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-10} {2,-29} [AccessList]",
fieldName,
fieldData,
"(" + (AccessList)(uint)fieldData + ")");
}
private static string SearchTypeFlags(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-10} {2,-29} [DirectoryManager.SearchTypeFlags]",
fieldName,
fieldData,
"(" + (DirectoryManager.SearchTypeFlags)(uint)fieldData + ")");
}
private static string DecodeCategory(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-3} {2,-36} [ParcelCategory]",
fieldName,
fieldData,
"(" + fieldData + ")");
}
private static string DecodeObjectUpdateFlags(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-10} {2,-29} [PrimFlags]",
fieldName,
fieldData,
"(" + (PrimFlags)(uint)fieldData + ")");
}
private static string DecodeTeleportFlags(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-10} {2,-29} [TeleportFlags]",
fieldName,
fieldData,
"(" + (TeleportFlags)(uint)fieldData + ")");
}
private static string DecodeScriptControls(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-10} {2,-29} [AgentManager.ControlFlags]",
fieldName,
(uint)fieldData,
"(" + (AgentManager.ControlFlags)(uint)fieldData + ")");
}
private static string DecodeColorField(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-40} [Color4]",
fieldName,
fieldData.GetType().Name.Equals("Color4") ? (Color4)fieldData : new Color4((byte[])fieldData, 0, false));
}
private static string DecodeTimeStamp(string fieldName, object fieldData)
{
if (fieldData is Int32 && (int)fieldData > 0)
return String.Format("{0,30}: {1,-10} {2,-29} [{3}]",
fieldName,
fieldData,
"(" + Utils.UnixTimeToDateTime((int)fieldData) + ")",
fieldData.GetType().Name);
else if (fieldData is uint && (uint)fieldData > 0)
return String.Format("{0,30}: {1,-10} {2,-29} [{3}]",
fieldName,
fieldData,
"(" + Utils.UnixTimeToDateTime((uint)fieldData) + ")",
fieldData.GetType().Name);
else
return String.Format("{0,30}: {1,-40} [{2}]",
fieldName,
fieldData,
fieldData.GetType().Name);
}
private static string DecodeBinaryBucket(string fieldName, object fieldData)
{
byte[] bytes = (byte[])fieldData;
string bucket = String.Empty;
if (bytes.Length == 1)
{
bucket = String.Format("{0}", bytes[0]);
}
else if (bytes.Length == 17)
{
bucket = String.Format("{0,-36} {1} ({2})",
new UUID(bytes, 1),
bytes[0],
(AssetType)(sbyte)bytes[0]);
}
else if (bytes.Length == 16) // the folder ID for the asset to be stored into if we accept an inventory offer
{
bucket = new UUID(bytes, 0).ToString();
}
else
{
bucket = Utils.BytesToString(bytes); // we'll try a string lastly
}
return String.Format("{0,30}: {1,-40} [Byte[{2}]]", fieldName, bucket, bytes.Length);
}
private static string DecodeBinaryToHexString(string fieldName, object fieldData)
{
return String.Format("{0,30}",
Utils.BytesToHexString((byte[])fieldData,
String.Format("{0,30}", fieldName)));
}
private static string DecodeWearableType(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-2} {2,-37} [WearableType]",
fieldName,
(byte)fieldData,
"(" + (WearableType)fieldData + ")");
}
private static string DecodeInventoryType(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-2} {2,-37} [AssetType]",
fieldName,
(sbyte)fieldData,
"(" + (AssetType)(sbyte)fieldData + ")");
}
private static string DecodeInventorySort(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-2} {2,-37} [InventorySortOrder]",
fieldName,
fieldData,
"(" + (InventorySortOrder)(int)fieldData + ")");
}
private static string DecodeInventoryInvType(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-2} {2,-37} [InventoryType]",
fieldName,
(sbyte)fieldData,
"(" + (InventoryType)fieldData + ")");
}
private static string DecodeFolderType(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-2} {2,-37} [AssetType]",
fieldName,
(sbyte)fieldData,
"(" + (AssetType)fieldData + ")");
}
private static string DecodeInventoryFlags(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-2} {2,-37} [InventoryItemFlags]",
fieldName,
(uint)fieldData,
"(" + (InventoryItemFlags)(uint)fieldData + ")");
}
private static string DecodeObjectSaleType(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-2} {2,-37} [SaleType]",
fieldName,
(byte)fieldData,
"(" + (SaleType)fieldData + ")");
}
private static string DecodeRegionFlags(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-2} {2,-37} [RegionFlags]",
fieldName,
fieldData,
"(" + (RegionFlags)(uint)fieldData + ")");
}
private static string DecodeTransferParams(string fieldName, object fieldData)
{
byte[] paramData = (byte[])fieldData;
StringBuilder result = new StringBuilder();
result.AppendLine(" <Params>");
if (paramData.Length == 20)
{
result.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine,
"AssetID",
new UUID(paramData, 0));
result.AppendFormat("{0,30}: {1,-2} {2,-37} [AssetType]" + Environment.NewLine,
"AssetType",
(sbyte)paramData[16],
"(" + (AssetType)(sbyte)paramData[16] + ")");
}
else if (paramData.Length == 100)
{
//UUID agentID = new UUID(info.TransferInfo.Params, 0);
result.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine,
"AgentID",
new UUID(paramData, 0));
//UUID sessionID = new UUID(info.TransferInfo.Params, 16);
result.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine,
"SessionID",
new UUID(paramData, 16));
//UUID ownerID = new UUID(info.TransferInfo.Params, 32);
result.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine,
"OwnerID",
new UUID(paramData, 32));
//UUID taskID = new UUID(info.TransferInfo.Params, 48);
result.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine,
"TaskID",
new UUID(paramData, 48));
//UUID itemID = new UUID(info.TransferInfo.Params, 64);
result.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine,
"ItemID",
new UUID(paramData, 64));
result.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine,
"AssetID",
new UUID(paramData, 80));
result.AppendFormat("{0,30}: {1,-2} {2,-37} [AssetType]" + Environment.NewLine,
"AssetType",
(sbyte)paramData[96],
"(" + (AssetType)(sbyte)paramData[96] + ")");
}
else
{
Console.WriteLine("Oh Poop!");
}
result.Append("</Params>");
return result.ToString();
}
private static string DecodeTransferChannelType(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-2} {2,-37} [ChannelType]",
fieldName,
fieldData,
"(" + (ChannelType)(int)fieldData + ")");
}
private static string DecodeTransferSourceType(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-2} {2,-37} [SourceType]",
fieldName,
fieldData,
"(" + (SourceType)(int)fieldData + ")");
}
private static string DecodeTransferTargetType(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-2} {2,-37} [TargetType]",
fieldName,
fieldData,
"(" + (TargetType)(int)fieldData + ")");
}
private static string DecodeMapRequestFlags(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-2} {2,-37} [GridLayerType]",
fieldName,
fieldData,
"(" + (GridLayerType)(uint)fieldData + ")");
}
private static string DecodeGridItemType(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-2} {2,-37} [GridItemType]",
fieldName,
fieldData,
"(" + (GridItemType)(uint)fieldData + ")");
}
private static string DecodeLayerDataType(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-2} {2,-37} [LayerType]",
fieldName,
fieldData,
"(" + (TerrainPatch.LayerType)(byte)fieldData + ")");
}
private static string DecodeMapAccess(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-2} {2,-37} [SimAccess]",
fieldName,
fieldData,
"(" + (SimAccess)(byte)fieldData + ")");
}
private static string DecodeSimAccess(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-2} {2,-37} [SimAccess]",
fieldName,
(byte)fieldData,
"(" + (SimAccess)fieldData + ")");
}
private static string DecodeAttachedSoundFlags(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-2} {2,-37} [SoundFlags]",
fieldName,
(byte)fieldData,
"(" + (SoundFlags)fieldData + ")");
}
private static string DecodeChatSourceType(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-2} {2,-37} [SourceType]",
fieldName,
fieldData,
"(" + (SourceType)(byte)fieldData + ")");
}
private static string DecodeChatChatType(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-2} {2,-37} [ChatType]",
fieldName,
(byte)fieldData,
"(" + (ChatType)fieldData + ")");
}
private static string DecodeChatAudible(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-2} {2,-37} [ChatAudibleLevel]",
fieldName,
(byte)fieldData,
"(" + (ChatAudibleLevel)(byte)fieldData + ")");
}
private static string DecodeImageData(string fieldName, object fieldData)
{
return String.Format("{0,10}",
Utils.BytesToHexString((byte[])fieldData,
String.Format("{0,30}", fieldName)));
}
private static string DecodeTerseTextureEntry(string fieldName, object fieldData)
{
byte[] block = (byte[])fieldData;
Primitive.TextureEntry te = new Primitive.TextureEntry(block, 4, block.Length - 4);
StringBuilder result = new StringBuilder();
result.AppendFormat("{0,30}", " <TextureEntry>" + Environment.NewLine);
if (te.DefaultTexture != null)
{
result.AppendFormat("{0,30}", " <DefaultTexture>" + Environment.NewLine);
GenericFieldsDecoder(te.DefaultTexture, ref result);
GenericPropertiesDecoder(te.DefaultTexture, ref result);
result.AppendFormat("{0,30}", " </DefaultTexture>" + Environment.NewLine);
}
result.AppendFormat("{0,30}", " <FaceTextures>" + Environment.NewLine);
for (int i = 0; i < te.FaceTextures.Length; i++)
{
if (te.FaceTextures[i] != null)
{
result.AppendFormat("{0,30}[{1}]" + Environment.NewLine, "FaceTexture", i);
GenericFieldsDecoder(te.FaceTextures[i], ref result);
GenericPropertiesDecoder(te.FaceTextures[i], ref result);
}
}
result.AppendFormat("{0,30}", " </FaceTextures>" + Environment.NewLine);
result.AppendFormat("{0,30}", "</TextureEntry>");
return result.ToString();
}
private static string DecodeTextureEntry(string fieldName, object fieldData)
{
Primitive.TextureEntry te;
if (fieldData is Primitive.TextureEntry)
te = (Primitive.TextureEntry)fieldData;
else
{
byte[] tebytes = (byte[])fieldData;
te = new Primitive.TextureEntry(tebytes, 0, tebytes.Length);
}
StringBuilder result = new StringBuilder();
result.AppendFormat("{0,30}", " <TextureEntry>" + Environment.NewLine);
if (te.DefaultTexture != null)
{
result.AppendFormat("{0,30}", " <DefaultTexture>" + Environment.NewLine);
GenericFieldsDecoder(te.DefaultTexture, ref result);
GenericPropertiesDecoder(te.DefaultTexture, ref result);
result.AppendFormat("{0,30}", " </DefaultTexture>" + Environment.NewLine);
}
result.AppendFormat("{0,30}", " <FaceTextures>" + Environment.NewLine);
for (int i = 0; i < te.FaceTextures.Length; i++)
{
if (te.FaceTextures[i] != null)
{
result.AppendFormat("{0,30}[{1}]" + Environment.NewLine, "FaceTexture", i);
GenericFieldsDecoder(te.FaceTextures[i], ref result);
GenericPropertiesDecoder(te.FaceTextures[i], ref result);
}
}
result.AppendFormat("{0,30}", " </FaceTextures>" + Environment.NewLine);
result.AppendFormat("{0,30}", "</TextureEntry>");
return result.ToString();
}
private static void GenericFieldsDecoder(object obj, ref StringBuilder result)
{
Type parcelType = obj.GetType();
FieldInfo[] fields = parcelType.GetFields();
foreach (FieldInfo field in fields)
{
String special;
if (SpecialDecoder("a" + "." + "b" + "." + field.Name,
field.GetValue(obj), out special))
{
result.AppendLine(special);
}
else
{
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
field.Name,
field.GetValue(obj),
field.FieldType.Name);
}
}
}
private static void GenericPropertiesDecoder(object obj, ref StringBuilder result)
{
Type parcelType = obj.GetType();
PropertyInfo[] propertyInfos = parcelType.GetProperties();
foreach (PropertyInfo property in propertyInfos)
{
String special;
if (SpecialDecoder("a" + "." + "b" + "." + property.Name,
property.GetValue(obj, null), out special))
{
result.AppendLine(special);
}
else
{
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
property.Name,
property.GetValue(obj, null),
property.PropertyType.Name);
}
}
}
private static string DecodeDialog(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-2} {2,-37} [{3}]",
fieldName,
(byte)fieldData,
"(" + (InstantMessageDialog)fieldData + ")",
fieldData.GetType().Name);
}
private static string DecodeControlFlags(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-10} {2,-29} [{3}]",
fieldName,
fieldData,
"(" + (AgentManager.ControlFlags)(uint)fieldData + ")",
fieldData.GetType().Name);
}
private static string DecodePermissionMask(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-10} {2,-29} [{3}]",
fieldName,
(uint)fieldData,
"(" + (PermissionMask)fieldData + ")",
fieldData.GetType().Name);
}
private static string DecodeViewerEffectTypeData(string fieldName, object fieldData)
{
byte[] data = (byte[])fieldData;
StringBuilder sb = new StringBuilder();
if (data.Length == 56 || data.Length == 57)
{
UUID sourceAvatar = new UUID(data, 0);
UUID targetObject = new UUID(data, 16);
Vector3d targetPos = new Vector3d(data, 32);
sb.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine, fieldName, "Source AvatarID=" + sourceAvatar);
sb.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine, fieldName, "Target ObjectID=" + targetObject);
float lx, ly;
Helpers.GlobalPosToRegionHandle((float)targetPos.X, (float)targetPos.Y, out lx, out ly);
sb.AppendFormat("{0,30}: {1,-40} [Vector3d]", fieldName, targetPos);
if (data.Length == 57)
{
sb.AppendLine();
sb.AppendFormat("{0,30}: {1,-17} {2,-22} [Byte]", fieldName, "Point At Type=" + data[56],
"(" + (PointAtType)data[56] + ")");
}
return sb.ToString();
}
else
{
return String.Format("{0,30}: (No Decoder) Length={1}" + Environment.NewLine, fieldName, data.Length) + Utils.BytesToHexString(data, String.Format("{0,30}", ""));
}
}
private static string DecodeAgentState(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-2} {2,-37} [AgentState]",
fieldName,
fieldData,
"(" + (AgentState)(byte)fieldData + ")");
}
private static string DecodeAgentFlags(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-2} {2,-37} [AgentFlags]",
fieldName,
fieldData,
"(" + (AgentFlags)(byte)fieldData + ")");
}
private static string DecodeObjectState(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-2} {2,-37} [AttachmentPoint]",
fieldName,
fieldData,
"(" + (AttachmentPoint)(byte)fieldData + ")");
}
private static string DecodeViewerEffectType(string fieldName, object fieldData)
{
return String.Format("{0,30}: {1,-2} {2,-37} [{3}]",
fieldName,
fieldData,
"(" + (EffectType)(byte)fieldData + ")",
fieldData.GetType().Name);
}
private static string DecodeAnimToConst(string fieldName, object fieldData)
{
string animConst = "UUID";
Dictionary<UUID, string> animsDict = Animations.ToDictionary();
if (animsDict.ContainsKey((UUID)fieldData))
animConst = animsDict[(UUID)fieldData];
return String.Format("{0,30}: {1,-40} [{2}]",
fieldName,
fieldData,
animConst);
}
#endregion
/// <summary>
/// Creates a formatted string containing the values of a Packet
/// </summary>
/// <param name="packet">The Packet</param>
/// <returns>A formatted string of values of the nested items in the Packet object</returns>
public static string PacketToString(Packet packet)
{
StringBuilder result = new StringBuilder();
result.AppendFormat("Packet Type: {0} http://lib.openmetaverse.org/wiki/{0} http://wiki.secondlife.com/wiki/{0}" + Environment.NewLine, packet.Type);
result.AppendLine("[Packet Header]");
// payload
result.AppendFormat("Sequence: {0}" + Environment.NewLine, packet.Header.Sequence);
result.AppendFormat(" Options: {0}" + Environment.NewLine, InterpretOptions(packet.Header));
result.AppendLine();
result.AppendLine("[Packet Payload]");
FieldInfo[] fields = packet.GetType().GetFields();
for (int i = 0; i < fields.Length; i++)
{
// we're not interested in any of these here
if (fields[i].Name == "Type" || fields[i].Name == "Header" || fields[i].Name == "HasVariableBlocks")
continue;
if (fields[i].FieldType.IsArray)
{
result.AppendFormat("{0,30} []" + Environment.NewLine, "-- " + fields[i].Name + " --");
RecursePacketArray(fields[i], packet, ref result);
}
else
{
result.AppendFormat("{0,30}" + Environment.NewLine, "-- " + fields[i].Name + " --");
RecursePacketField(fields[i], packet, ref result);
}
}
return result.ToString();
}
public static string InterpretOptions(Header header)
{
return "["
+ (header.AppendedAcks ? "Ack" : " ")
+ " "
+ (header.Resent ? "Res" : " ")
+ " "
+ (header.Reliable ? "Rel" : " ")
+ " "
+ (header.Zerocoded ? "Zer" : " ")
+ "]"
;
}
private static void RecursePacketArray(FieldInfo fieldInfo, object packet, ref StringBuilder result)
{
var packetDataObject = fieldInfo.GetValue(packet);
foreach (object nestedArrayRecord in packetDataObject as Array)
{
FieldInfo[] fields = nestedArrayRecord.GetType().GetFields();
for (int i = 0; i < fields.Length; i++)
{
String special;
if (SpecialDecoder(packet.GetType().Name + "." + fieldInfo.Name + "." + fields[i].Name,
fields[i].GetValue(nestedArrayRecord), out special))
{
result.AppendLine(special);
}
else if (fields[i].FieldType.IsArray) // default for an array (probably a byte[])
{
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
fields[i].Name,
Utils.BytesToString((byte[])fields[i].GetValue(nestedArrayRecord)),
/*fields[i].GetValue(nestedArrayRecord).GetType().Name*/ "String");
}
else // default for a field
{
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
fields[i].Name,
fields[i].GetValue(nestedArrayRecord),
fields[i].GetValue(nestedArrayRecord).GetType().Name);
}
}
// Handle Properties
foreach (PropertyInfo propertyInfo in nestedArrayRecord.GetType().GetProperties())
{
if (propertyInfo.Name.Equals("Length"))
continue;
string special;
if (SpecialDecoder(packet.GetType().Name + "." + fieldInfo.Name + "." + propertyInfo.Name,
propertyInfo.GetValue(nestedArrayRecord, null),
out special))
{
result.AppendLine(special);
}
else
{
var p = propertyInfo.GetValue(nestedArrayRecord, null);
/* Leave the c for now at the end, it signifies something useful that still needs to be done i.e. a decoder written */
result.AppendFormat("{0, 30}: {1,-40} [{2}]c" + Environment.NewLine,
propertyInfo.Name,
Utils.BytesToString((byte[])propertyInfo.GetValue(nestedArrayRecord, null)),
propertyInfo.PropertyType.Name);
}
}
result.AppendFormat("{0,32}" + Environment.NewLine, "***");
}
}
private static void RecursePacketField(FieldInfo fieldInfo, object packet, ref StringBuilder result)
{
object packetDataObject = fieldInfo.GetValue(packet);
// handle Fields
foreach (FieldInfo packetValueField in fieldInfo.GetValue(packet).GetType().GetFields())
{
string special;
if (SpecialDecoder(packet.GetType().Name + "." + fieldInfo.Name + "." + packetValueField.Name,
packetValueField.GetValue(packetDataObject),
out special))
{
result.AppendLine(special);
}
else if (packetValueField.FieldType.IsArray)
{
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
packetValueField.Name,
Utils.BytesToString((byte[])packetValueField.GetValue(packetDataObject)),
/*packetValueField.FieldType.Name*/ "String");
}
else
{
result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
packetValueField.Name, packetValueField.GetValue(packetDataObject), packetValueField.FieldType.Name);
}
}
// Handle Properties
foreach (PropertyInfo propertyInfo in packetDataObject.GetType().GetProperties())
{
if (propertyInfo.Name.Equals("Length"))
continue;
string special;
if (SpecialDecoder(packet.GetType().Name + "." + fieldInfo.Name + "." + propertyInfo.Name,
propertyInfo.GetValue(packetDataObject, null),
out special))
{
result.AppendLine(special);
}
else if (propertyInfo.GetValue(packetDataObject, null).GetType() == typeof(byte[]))
{
result.AppendFormat("{0, 30}: {1,-40} [{2}]" + Environment.NewLine,
propertyInfo.Name,
Utils.BytesToString((byte[])propertyInfo.GetValue(packetDataObject, null)),
propertyInfo.PropertyType.Name);
}
else
{
result.AppendFormat("{0, 30}: {1,-40} [{2}]" + Environment.NewLine,
propertyInfo.Name,
propertyInfo.GetValue(packetDataObject, null),
propertyInfo.PropertyType.Name);
}
}
}
private static bool SpecialDecoder(string decoderKey, object fieldData, out string result)
{
result = string.Empty;
string[] keys = decoderKey.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
string[] keyList = { decoderKey, decoderKey.Replace("Packet", ""), keys[1] + "." + keys[2], keys[2] };
foreach (string key in keyList)
{
bool ok = true;
if (fieldData is byte[])
{
byte[] fd = (byte[])fieldData;
ok = fd.Length > 0;
if (!ok)
{
// bypass the decoder since we were passed an empty byte array
result = String.Format("{0,30}:", keys[2]);
return true;
}
}
if (ok && Callbacks.ContainsKey(key)) // fieldname e.g: Plane
{
foreach (CustomPacketDecoder decoder in Callbacks[key])
result = decoder(keys[2], fieldData);
return true;
}
}
return false;
}
/// <summary>
/// Decode an IMessage object into a beautifully formatted string
/// </summary>
/// <param name="message">The IMessage object</param>
/// <param name="recurseLevel">Recursion level (used for indenting)</param>
/// <returns>A formatted string containing the names and values of the source object</returns>
public static string MessageToString(object message, int recurseLevel)
{
if (message == null)
return String.Empty;
StringBuilder result = new StringBuilder();
// common/custom types
if (recurseLevel <= 0)
{
result.AppendFormat("Message Type: {0} http://lib.openmetaverse.org/wiki/{0}" + Environment.NewLine, message.GetType().Name);
}
else
{
string pad = " +--".PadLeft(recurseLevel + 3);
result.AppendFormat("{0} {1}" + Environment.NewLine, pad, message.GetType().Name);
}
recurseLevel++;
foreach (FieldInfo messageField in message.GetType().GetFields())
{
// an abstract message class
if (messageField.FieldType.IsAbstract)
{
result.AppendLine(MessageToString(messageField.GetValue(message), recurseLevel));
}
// a byte array
else if (messageField.GetValue(message) != null && messageField.GetValue(message).GetType() == typeof(Byte[]))
{
result.AppendFormat("{0, 30}:" + Environment.NewLine, messageField.Name);
result.AppendFormat("{0}" + Environment.NewLine,
Utils.BytesToHexString((byte[])messageField.GetValue(message),
String.Format("{0,30}", "")));
}
// an array of class objects
else if (messageField.FieldType.IsArray)
{
var messageObjectData = messageField.GetValue(message);
result.AppendFormat("-- {0} --" + Environment.NewLine, messageField.FieldType.Name);
foreach (object nestedArrayObject in messageObjectData as Array)
{
if (nestedArrayObject == null)
{
result.AppendFormat("{0,30}" + Environment.NewLine, "-- null --");
continue;
}
else
{
result.AppendFormat("{0,30}" + Environment.NewLine, "-- " + nestedArrayObject.GetType().Name + " --");
}
foreach (FieldInfo nestedField in nestedArrayObject.GetType().GetFields())
{
if (nestedField.FieldType.IsEnum)
{
result.AppendFormat("{0,30}: {1,-10} {2,-29} [{3}]" + Environment.NewLine,
nestedField.Name,
Enum.Format(nestedField.GetValue(nestedArrayObject).GetType(),
nestedField.GetValue(nestedArrayObject), "D"),
"(" + nestedField.GetValue(nestedArrayObject) + ")",
nestedField.GetValue(nestedArrayObject).GetType().Name);
}
else if (nestedField.FieldType.IsInterface)
{
result.AppendLine(MessageToString(nestedField.GetValue(nestedArrayObject), recurseLevel));
}
else
{
result.AppendFormat("{0, 30}: {1,-40} [{2}]" + Environment.NewLine,
nestedField.Name,
nestedField.GetValue(nestedArrayObject),
nestedField.FieldType.Name);
}
}
}
}
else
{
if (messageField.FieldType.IsEnum)
{
result.AppendFormat("{0,30}: {1,-2} {2,-37} [{3}]" + Environment.NewLine,
messageField.Name,
Enum.Format(messageField.GetValue(message).GetType(),
messageField.GetValue(message), "D"),
"(" + messageField.GetValue(message) + ")",
messageField.FieldType.Name);
}
else if (messageField.FieldType.IsInterface)
{
result.AppendLine(MessageToString(messageField.GetValue(message), recurseLevel));
}
else
{
result.AppendFormat("{0, 30}: {1,-40} [{2}]" + Environment.NewLine,
messageField.Name, messageField.GetValue(message), messageField.FieldType.Name);
}
}
}
return result.ToString();
}
}
}