corrade-vassal – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | vero | 1 | /* |
2 | * Copyright (c) 2006-2014, openmetaverse.org |
||
3 | * All rights reserved. |
||
4 | * |
||
5 | * - Redistribution and use in source and binary forms, with or without |
||
6 | * modification, are permitted provided that the following conditions are met: |
||
7 | * |
||
8 | * - Redistributions of source code must retain the above copyright notice, this |
||
9 | * list of conditions and the following disclaimer. |
||
10 | * - Neither the name of the openmetaverse.org nor the names |
||
11 | * of its contributors may be used to endorse or promote products derived from |
||
12 | * this software without specific prior written permission. |
||
13 | * |
||
14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
||
15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||
16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||
17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
||
18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
||
19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
||
20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
||
21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
||
22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
||
23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
||
24 | * POSSIBILITY OF SUCH DAMAGE. |
||
25 | */ |
||
26 | |||
27 | using System; |
||
28 | using System.Collections.Generic; |
||
29 | using System.Reflection; |
||
30 | using System.Text; |
||
31 | |||
32 | namespace OpenMetaverse.Packets |
||
33 | { |
||
34 | |||
35 | public static class PacketDecoder |
||
36 | { |
||
37 | /// <summary> |
||
38 | /// A custom decoder callback |
||
39 | /// </summary> |
||
40 | /// <param name="fieldName">The key of the object</param> |
||
41 | /// <param name="fieldData">the data to decode</param> |
||
42 | /// <returns>A string represending the fieldData</returns> |
||
43 | public delegate string CustomPacketDecoder(string fieldName, object fieldData); |
||
44 | |||
45 | private static Dictionary<string, List<CustomPacketDecoder>> Callbacks = new Dictionary<string, List<CustomPacketDecoder>>(); |
||
46 | |||
47 | |||
48 | static PacketDecoder() |
||
49 | { |
||
50 | AddCallback("Color", DecodeColorField); |
||
51 | AddCallback("TextColor", DecodeColorField); |
||
52 | AddCallback("Timestamp", DecodeTimeStamp); |
||
53 | AddCallback("EstateCovenantReply.Data.CovenantTimestamp", DecodeTimeStamp); |
||
54 | AddCallback("CreationDate", DecodeTimeStamp); |
||
55 | AddCallback("BinaryBucket", DecodeBinaryBucket); |
||
56 | AddCallback("ParcelData.Data", DecodeBinaryToHexString); |
||
57 | AddCallback("LayerData.Data", DecodeBinaryToHexString); |
||
58 | AddCallback("ImageData.Data", DecodeImageData); |
||
59 | AddCallback("TransferData.Data", DecodeBinaryToHexString); |
||
60 | AddCallback("ObjectData.TextureEntry", DecodeTextureEntry); |
||
61 | AddCallback("ImprovedInstantMessage.MessageBlock.Dialog", DecodeDialog); |
||
62 | |||
63 | // Inventory/Permissions |
||
64 | AddCallback("BaseMask", DecodePermissionMask); |
||
65 | AddCallback("OwnerMask", DecodePermissionMask); |
||
66 | AddCallback("EveryoneMask", DecodePermissionMask); |
||
67 | AddCallback("NextOwnerMask", DecodePermissionMask); |
||
68 | AddCallback("GroupMask", DecodePermissionMask); |
||
69 | |||
70 | // FetchInventoryDescendents |
||
71 | AddCallback("InventoryData.SortOrder", DecodeInventorySort); |
||
72 | |||
73 | AddCallback("WearableType", DecodeWearableType); |
||
74 | // |
||
75 | AddCallback("InventoryData.Type", DecodeInventoryType); |
||
76 | AddCallback("InvType", DecodeInventoryInvType); |
||
77 | AddCallback("InventoryData.Flags", DecodeInventoryFlags); |
||
78 | // BulkUpdateInventory |
||
79 | AddCallback("ItemData.Type", DecodeInventoryType); |
||
80 | AddCallback("ItemData.Flags", DecodeInventoryFlags); |
||
81 | |||
82 | AddCallback("SaleType", DecodeObjectSaleType); |
||
83 | |||
84 | AddCallback("ScriptControlChange.Data.Controls", DecodeScriptControls); |
||
85 | |||
86 | AddCallback("RegionFlags", DecodeRegionFlags); |
||
87 | AddCallback("SimAccess", DecodeSimAccess); |
||
88 | AddCallback("ControlFlags", DecodeControlFlags); |
||
89 | |||
90 | // AgentUpdate |
||
91 | AddCallback("AgentUpdate.AgentData.State", DecodeAgentState); |
||
92 | AddCallback("AgentUpdate.AgentData.Flags", DecodeAgentFlags); |
||
93 | |||
94 | // ViewerEffect TypeData |
||
95 | AddCallback("ViewerEffect.Effect.TypeData", DecodeViewerEffectTypeData); |
||
96 | AddCallback("ViewerEffect.Effect.Type", DecodeViewerEffectType); |
||
97 | |||
98 | // Prim/ObjectUpdate decoders |
||
99 | AddCallback("ObjectUpdate.ObjectData.PCode", DecodeObjectPCode); |
||
100 | AddCallback("ObjectUpdate.ObjectData.Material", DecodeObjectMaterial); |
||
101 | AddCallback("ObjectUpdate.ObjectData.ClickAction", DecodeObjectClickAction); |
||
102 | AddCallback("ObjectData.UpdateFlags", DecodeObjectUpdateFlags); |
||
103 | |||
104 | AddCallback("ObjectUpdate.ObjectData.ObjectData", DecodeObjectData); |
||
105 | AddCallback("TextureAnim", DecodeObjectTextureAnim); |
||
106 | AddCallback("ObjectUpdate.ObjectData.NameValue", DecodeNameValue); |
||
107 | AddCallback("ObjectUpdate.ObjectData.Data", DecodeObjectData); |
||
108 | |||
109 | AddCallback("ObjectUpdate.ObjectData.PSBlock", DecodeObjectParticleSystem); |
||
110 | AddCallback("ParticleSys", DecodeObjectParticleSystem); |
||
111 | AddCallback("ObjectUpdate.ObjectData.ExtraParams", DecodeObjectExtraParams); |
||
112 | |||
113 | AddCallback("ImprovedTerseObjectUpdate.ObjectData.Data", DecodeTerseUpdate); |
||
114 | AddCallback("ImprovedTerseObjectUpdate.ObjectData.TextureEntry", DecodeTerseTextureEntry); |
||
115 | |||
116 | AddCallback("ObjectUpdateCompressed.ObjectData.Data", DecodeObjectCompressedData); |
||
117 | |||
118 | // ImprovedTerseObjectUpdate & ObjectUpdate AttachmentPoint & ObjectUpdateCompressed |
||
119 | AddCallback("ObjectData.State", DecodeObjectState); |
||
120 | //AddCallback("ObjectUpdateCompressed.ObjectData.State", DecodeObjectState); |
||
121 | //AddCallback("ImprovedTerseObjectUpdate.ObjectData.State", DecodeObjectState); |
||
122 | |||
123 | |||
124 | // ChatFromSimulator |
||
125 | AddCallback("ChatData.SourceType", DecodeChatSourceType); |
||
126 | AddCallback("ChatData.ChatType", DecodeChatChatType); |
||
127 | AddCallback("ChatData.Audible", DecodeChatAudible); |
||
128 | AddCallback("AttachedSound.DataBlock.Flags", DecodeAttachedSoundFlags); |
||
129 | |||
130 | AddCallback("RequestImage.Type", DecodeImageType); |
||
131 | |||
132 | AddCallback("EstateOwnerMessage.ParamList.Parameter", DecodeEstateParameter); |
||
133 | |||
134 | AddCallback("Codec", DecodeImageCodec); |
||
135 | AddCallback("Info.TeleportFlags", DecodeTeleportFlags); |
||
136 | |||
137 | // map |
||
138 | AddCallback("MapBlockRequest.AgentData.Flags", DecodeMapRequestFlags); |
||
139 | AddCallback("MapItemRequest.AgentData.Flags", DecodeMapRequestFlags); |
||
140 | AddCallback("MapBlockReply.Data.Access", DecodeMapAccess); |
||
141 | AddCallback("FolderData.Type", DecodeFolderType); |
||
142 | AddCallback("RequestData.ItemType", DecodeGridItemType); |
||
143 | |||
144 | // TransferRequest/TransferInfo |
||
145 | AddCallback("TransferInfo.Params", DecodeTransferParams); |
||
146 | AddCallback("TransferInfo.ChannelType", DecodeTransferChannelType); |
||
147 | AddCallback("TransferInfo.SourceType", DecodeTransferSourceType); |
||
148 | AddCallback("TransferInfo.TargetType", DecodeTransferTargetType); |
||
149 | AddCallback("TransferData.ChannelType", DecodeTransferChannelType); |
||
150 | // SendXferPacket |
||
151 | AddCallback("DataPacket.Data", DecodeBinaryToHexString); |
||
152 | // Directory Manager |
||
153 | AddCallback("DirClassifiedQuery.QueryData.QueryFlags", DecodeDirClassifiedQueryFlags); |
||
154 | AddCallback("QueryData.QueryFlags", DecodeDirQueryFlags); |
||
155 | AddCallback("Category", DecodeCategory); |
||
156 | AddCallback("QueryData.SearchType", SearchTypeFlags); |
||
157 | |||
158 | AddCallback("ClassifiedFlags", DecodeDirClassifiedFlags); |
||
159 | AddCallback("EventFlags", DecodeEventFlags); |
||
160 | |||
161 | AddCallback("ParcelAccessListRequest.Data.Flags", DecodeParcelACL); |
||
162 | AddCallback("ParcelAccessListReply.Data.Flags", DecodeParcelACL); |
||
163 | //AddCallback("ParcelAccessListReply.List.Flags", DecodeParcelACLReply); |
||
164 | |||
165 | // AgentAnimation |
||
166 | AddCallback("AnimID", DecodeAnimToConst); |
||
167 | |||
168 | AddCallback("LayerData.LayerID.Type", DecodeLayerDataType); |
||
169 | |||
170 | AddCallback("GroupPowers", DecodeGroupPowers); |
||
171 | } |
||
172 | |||
173 | /// <summary> |
||
174 | /// Add a custom decoder callback |
||
175 | /// </summary> |
||
176 | /// <param name="key">The key of the field to decode</param> |
||
177 | /// <param name="customPacketHandler">The custom decode handler</param> |
||
178 | public static void AddCallback(string key, CustomPacketDecoder customPacketHandler) |
||
179 | { |
||
180 | if (Callbacks.ContainsKey(key)) |
||
181 | { |
||
182 | lock (Callbacks) |
||
183 | Callbacks[key].Add(customPacketHandler); |
||
184 | } |
||
185 | else |
||
186 | { |
||
187 | lock (Callbacks) |
||
188 | Callbacks.Add(key, new List<CustomPacketDecoder>() { customPacketHandler }); |
||
189 | } |
||
190 | } |
||
191 | |||
192 | /// <summary> |
||
193 | /// Remove a custom decoder callback |
||
194 | /// </summary> |
||
195 | /// <param name="key">The key of the field to decode</param> |
||
196 | /// <param name="customPacketHandler">The custom decode handler</param> |
||
197 | public static void RemoveCustomHandler(string key, CustomPacketDecoder customPacketHandler) |
||
198 | { |
||
199 | if (Callbacks.ContainsKey(key)) |
||
200 | lock (Callbacks) |
||
201 | { |
||
202 | if (Callbacks[key].Contains(customPacketHandler)) |
||
203 | Callbacks[key].Remove(customPacketHandler); |
||
204 | } |
||
205 | } |
||
206 | |||
207 | #region Custom Decoders |
||
208 | |||
209 | private static string DecodeTerseUpdate(string fieldName, object fieldData) |
||
210 | { |
||
211 | byte[] block = (byte[])fieldData; |
||
212 | int i = 4; |
||
213 | |||
214 | StringBuilder result = new StringBuilder(); |
||
215 | |||
216 | // LocalID |
||
217 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
218 | "LocalID", |
||
219 | Utils.BytesToUInt(block, 0), |
||
220 | "Uint32"); |
||
221 | |||
222 | |||
223 | |||
224 | // State |
||
225 | byte point = block[i++]; |
||
226 | result.AppendFormat("{0,30}: {1,-3} {2,-36} [{3}]" + Environment.NewLine, |
||
227 | "State", |
||
228 | point, |
||
229 | "(" + (AttachmentPoint)point + ")", |
||
230 | "AttachmentPoint"); |
||
231 | |||
232 | // Avatar boolean |
||
233 | bool isAvatar = (block[i++] != 0); |
||
234 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
235 | "IsAvatar", |
||
236 | isAvatar, |
||
237 | "Boolean"); |
||
238 | |||
239 | // Collision normal for avatar |
||
240 | if (isAvatar) |
||
241 | { |
||
242 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
243 | "CollisionPlane", |
||
244 | new Vector4(block, i), |
||
245 | "Vector4"); |
||
246 | |||
247 | i += 16; |
||
248 | } |
||
249 | |||
250 | // Position |
||
251 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
252 | "Position", |
||
253 | new Vector3(block, i), |
||
254 | "Vector3"); |
||
255 | i += 12; |
||
256 | |||
257 | // Velocity |
||
258 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
259 | "Velocity", |
||
260 | new Vector3( |
||
261 | Utils.UInt16ToFloat(block, i, -128.0f, 128.0f), |
||
262 | Utils.UInt16ToFloat(block, i + 2, -128.0f, 128.0f), |
||
263 | Utils.UInt16ToFloat(block, i + 4, -128.0f, 128.0f)), |
||
264 | "Vector3"); |
||
265 | i += 6; |
||
266 | |||
267 | // Acceleration |
||
268 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
269 | "Acceleration", |
||
270 | new Vector3( |
||
271 | Utils.UInt16ToFloat(block, i, -64.0f, 64.0f), |
||
272 | Utils.UInt16ToFloat(block, i + 2, -64.0f, 64.0f), |
||
273 | Utils.UInt16ToFloat(block, i + 4, -64.0f, 64.0f)), |
||
274 | "Vector3"); |
||
275 | |||
276 | i += 6; |
||
277 | // Rotation (theta) |
||
278 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
279 | "Rotation", |
||
280 | new Quaternion( |
||
281 | Utils.UInt16ToFloat(block, i, -1.0f, 1.0f), |
||
282 | Utils.UInt16ToFloat(block, i + 2, -1.0f, 1.0f), |
||
283 | Utils.UInt16ToFloat(block, i + 4, -1.0f, 1.0f), |
||
284 | Utils.UInt16ToFloat(block, i + 6, -1.0f, 1.0f)), |
||
285 | "Quaternion"); |
||
286 | i += 8; |
||
287 | // Angular velocity (omega) |
||
288 | result.AppendFormat("{0,30}: {1,-40} [{2}]", |
||
289 | "AngularVelocity", |
||
290 | new Vector3( |
||
291 | Utils.UInt16ToFloat(block, i, -64.0f, 64.0f), |
||
292 | Utils.UInt16ToFloat(block, i + 2, -64.0f, 64.0f), |
||
293 | Utils.UInt16ToFloat(block, i + 4, -64.0f, 64.0f)), |
||
294 | "Vector3"); |
||
295 | //pos += 6; |
||
296 | // TODO: What is in these 6 bytes? |
||
297 | return result.ToString(); |
||
298 | } |
||
299 | |||
300 | private static string DecodeObjectCompressedData(string fieldName, object fieldData) |
||
301 | { |
||
302 | StringBuilder result = new StringBuilder(); |
||
303 | byte[] block = (byte[])fieldData; |
||
304 | int i = 0; |
||
305 | |||
306 | // UUID |
||
307 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
308 | "ID", |
||
309 | new UUID(block, 0), |
||
310 | "UUID"); |
||
311 | i += 16; |
||
312 | |||
313 | // Local ID |
||
314 | uint LocalID = (uint)(block[i++] + (block[i++] << 8) + |
||
315 | (block[i++] << 16) + (block[i++] << 24)); |
||
316 | |||
317 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
318 | "LocalID", |
||
319 | LocalID, |
||
320 | "Uint32"); |
||
321 | // PCode |
||
322 | PCode pcode = (PCode)block[i++]; |
||
323 | |||
324 | result.AppendFormat("{0,30}: {1,-3} {2,-36} [{3}]" + Environment.NewLine, |
||
325 | "PCode", |
||
326 | (int)pcode, |
||
327 | "(" + pcode + ")", |
||
328 | "PCode"); |
||
329 | |||
330 | // State |
||
331 | AttachmentPoint point = (AttachmentPoint)block[i++]; |
||
332 | result.AppendFormat("{0,30}: {1,-3} {2,-36} [{3}]" + Environment.NewLine, |
||
333 | "State", |
||
334 | (byte)point, |
||
335 | "(" + point + ")", |
||
336 | "AttachmentPoint"); |
||
337 | |||
338 | // TODO: CRC |
||
339 | |||
340 | i += 4; |
||
341 | // Material |
||
342 | result.AppendFormat("{0,30}: {1,-3} {2,-36} [{3}]" + Environment.NewLine, |
||
343 | "Material", |
||
344 | block[i], |
||
345 | "(" + (Material)block[i++] + ")", |
||
346 | "Material"); |
||
347 | |||
348 | // Click action |
||
349 | result.AppendFormat("{0,30}: {1,-3} {2,-36} [{3}]" + Environment.NewLine, |
||
350 | "ClickAction", |
||
351 | block[i], |
||
352 | "(" + (ClickAction)block[i++] + ")", |
||
353 | "ClickAction"); |
||
354 | |||
355 | // Scale |
||
356 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
357 | "Scale", |
||
358 | new Vector3(block, i), |
||
359 | "Vector3"); |
||
360 | i += 12; |
||
361 | |||
362 | // Position |
||
363 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
364 | "Position", |
||
365 | new Vector3(block, i), |
||
366 | "Vector3"); |
||
367 | i += 12; |
||
368 | |||
369 | // Rotation |
||
370 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
371 | "Rotation", |
||
372 | new Vector3(block, i), |
||
373 | "Vector3"); |
||
374 | |||
375 | i += 12; |
||
376 | // Compressed flags |
||
377 | CompressedFlags flags = (CompressedFlags)Utils.BytesToUInt(block, i); |
||
378 | result.AppendFormat("{0,30}: {1,-10} {2,-29} [{3}]" + Environment.NewLine, |
||
379 | "CompressedFlags", |
||
380 | Utils.BytesToUInt(block, i), |
||
381 | "(" + (CompressedFlags)Utils.BytesToUInt(block, i) + ")", |
||
382 | "UInt"); |
||
383 | i += 4; |
||
384 | |||
385 | // Owners ID |
||
386 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
387 | "OwnerID", |
||
388 | new UUID(block, i), |
||
389 | "UUID"); |
||
390 | i += 16; |
||
391 | |||
392 | // Angular velocity |
||
393 | if ((flags & CompressedFlags.HasAngularVelocity) != 0) |
||
394 | { |
||
395 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
396 | "AngularVelocity", |
||
397 | new Vector3(block, i), |
||
398 | "Vector3"); |
||
399 | i += 12; |
||
400 | } |
||
401 | |||
402 | // Parent ID |
||
403 | if ((flags & CompressedFlags.HasParent) != 0) |
||
404 | { |
||
405 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
406 | "ParentID", |
||
407 | (uint)(block[i++] + (block[i++] << 8) + |
||
408 | (block[i++] << 16) + (block[i++] << 24)), |
||
409 | "UInt"); |
||
410 | } |
||
411 | |||
412 | // Tree data |
||
413 | if ((flags & CompressedFlags.Tree) != 0) |
||
414 | { |
||
415 | result.AppendFormat("{0,30}: {1,-2} {2,-37} [{3}]" + Environment.NewLine, |
||
416 | "TreeSpecies", |
||
417 | block[i++], |
||
418 | "(" + (Tree)block[i] + ")", |
||
419 | "Tree"); |
||
420 | } |
||
421 | |||
422 | // Scratch pad |
||
423 | else if ((flags & CompressedFlags.ScratchPad) != 0) |
||
424 | { |
||
425 | int size = block[i++]; |
||
426 | byte[] scratch = new byte[size]; |
||
427 | Buffer.BlockCopy(block, i, scratch, 0, size); |
||
428 | result.AppendFormat("{0,30}: {1,-40} [ScratchPad[]]" + Environment.NewLine, |
||
429 | "ScratchPad", |
||
430 | Utils.BytesToHexString(scratch, String.Format("{0,30}", "Data"))); |
||
431 | i += size; |
||
432 | } |
||
433 | |||
434 | // Floating text |
||
435 | if ((flags & CompressedFlags.HasText) != 0) |
||
436 | { |
||
437 | string text = String.Empty; |
||
438 | while (block[i] != 0) |
||
439 | { |
||
440 | text += (char)block[i]; |
||
441 | i++; |
||
442 | } |
||
443 | i++; |
||
444 | |||
445 | // Floating text |
||
446 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
447 | "Text", |
||
448 | text, |
||
449 | "string"); |
||
450 | |||
451 | // Text color |
||
452 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
453 | "TextColor", |
||
454 | new Color4(block, i, false), |
||
455 | "Color4"); |
||
456 | i += 4; |
||
457 | } |
||
458 | |||
459 | // Media URL |
||
460 | if ((flags & CompressedFlags.MediaURL) != 0) |
||
461 | { |
||
462 | string text = String.Empty; |
||
463 | while (block[i] != 0) |
||
464 | { |
||
465 | text += (char)block[i]; |
||
466 | i++; |
||
467 | } |
||
468 | i++; |
||
469 | |||
470 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
471 | "MediaURL", |
||
472 | text, |
||
473 | "string"); |
||
474 | } |
||
475 | |||
476 | // Particle system |
||
477 | if ((flags & CompressedFlags.HasParticles) != 0) |
||
478 | { |
||
479 | Primitive.ParticleSystem p = new Primitive.ParticleSystem(block, i); |
||
480 | result.AppendLine(DecodeObjectParticleSystem("ParticleSystem", p)); |
||
481 | i += 86; |
||
482 | } |
||
483 | |||
484 | // Extra parameters TODO: |
||
485 | Primitive prim = new Primitive(); |
||
486 | i += prim.SetExtraParamsFromBytes(block, i); |
||
487 | |||
488 | //Sound data |
||
489 | if ((flags & CompressedFlags.HasSound) != 0) |
||
490 | { |
||
491 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
492 | "SoundID", |
||
493 | new UUID(block, i), |
||
494 | "UUID"); |
||
495 | i += 16; |
||
496 | |||
497 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
498 | "SoundGain", |
||
499 | Utils.BytesToFloat(block, i), |
||
500 | "Float"); |
||
501 | i += 4; |
||
502 | |||
503 | result.AppendFormat("{0,30}: {1,-2} {2,-37} [{3}]" + Environment.NewLine, |
||
504 | "SoundFlags", |
||
505 | block[i++], |
||
506 | "(" + (SoundFlags)block[i] + ")", |
||
507 | "SoundFlags"); |
||
508 | |||
509 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
510 | "SoundRadius", |
||
511 | Utils.BytesToFloat(block, i), |
||
512 | "Float"); |
||
513 | i += 4; |
||
514 | } |
||
515 | |||
516 | // Name values |
||
517 | if ((flags & CompressedFlags.HasNameValues) != 0) |
||
518 | { |
||
519 | string text = String.Empty; |
||
520 | while (block[i] != 0) |
||
521 | { |
||
522 | text += (char)block[i]; |
||
523 | i++; |
||
524 | } |
||
525 | i++; |
||
526 | |||
527 | // Parse the name values |
||
528 | if (text.Length > 0) |
||
529 | { |
||
530 | string[] lines = text.Split('\n'); |
||
531 | NameValue[] nameValues = new NameValue[lines.Length]; |
||
532 | |||
533 | for (int j = 0; j < lines.Length; j++) |
||
534 | { |
||
535 | if (!String.IsNullOrEmpty(lines[j])) |
||
536 | { |
||
537 | NameValue nv = new NameValue(lines[j]); |
||
538 | nameValues[j] = nv; |
||
539 | } |
||
540 | } |
||
541 | DecodeNameValue("NameValues", nameValues); |
||
542 | } |
||
543 | } |
||
544 | |||
545 | result.AppendFormat("{0,30}: {1,-2} {2,-37} [{3}]" + Environment.NewLine, |
||
546 | "PathCurve", |
||
547 | block[i], |
||
548 | "(" + (PathCurve)block[i++] + ")", |
||
549 | "PathCurve"); |
||
550 | |||
551 | ushort pathBegin = Utils.BytesToUInt16(block, i); |
||
552 | i += 2; |
||
553 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
554 | "PathBegin", |
||
555 | Primitive.UnpackBeginCut(pathBegin), |
||
556 | "float"); |
||
557 | |||
558 | ushort pathEnd = Utils.BytesToUInt16(block, i); |
||
559 | i += 2; |
||
560 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
561 | "PathEnd", |
||
562 | Primitive.UnpackEndCut(pathEnd), |
||
563 | "float"); |
||
564 | |||
565 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
566 | "PathScaleX", |
||
567 | Primitive.UnpackPathScale(block[i++]), |
||
568 | "float"); |
||
569 | |||
570 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
571 | "PathScaleY", |
||
572 | Primitive.UnpackPathScale(block[i++]), |
||
573 | "float"); |
||
574 | |||
575 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
576 | "PathShearX", |
||
577 | Primitive.UnpackPathShear((sbyte)block[i++]), |
||
578 | "float"); |
||
579 | |||
580 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
581 | "PathShearY", |
||
582 | Primitive.UnpackPathShear((sbyte)block[i++]), |
||
583 | "float"); |
||
584 | |||
585 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
586 | "PathTwist", |
||
587 | Primitive.UnpackPathTwist((sbyte)block[i++]), |
||
588 | "float"); |
||
589 | |||
590 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
591 | "PathTwistBegin", |
||
592 | Primitive.UnpackPathTwist((sbyte)block[i++]), |
||
593 | "float"); |
||
594 | |||
595 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
596 | "PathRadiusOffset", |
||
597 | Primitive.UnpackPathTwist((sbyte)block[i++]), |
||
598 | "float"); |
||
599 | |||
600 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
601 | "PathTaperX", |
||
602 | Primitive.UnpackPathTaper((sbyte)block[i++]), |
||
603 | "float"); |
||
604 | |||
605 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
606 | "PathTaperY", |
||
607 | Primitive.UnpackPathTaper((sbyte)block[i++]), |
||
608 | "float"); |
||
609 | |||
610 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
611 | "PathRevolutions", |
||
612 | Primitive.UnpackPathRevolutions(block[i++]), |
||
613 | "float"); |
||
614 | |||
615 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
616 | "PathSkew", |
||
617 | Primitive.UnpackPathTwist((sbyte)block[i++]), |
||
618 | "float"); |
||
619 | |||
620 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
621 | "ProfileCurve", |
||
622 | block[i++], |
||
623 | "float"); |
||
624 | |||
625 | ushort profileBegin = Utils.BytesToUInt16(block, i); |
||
626 | i += 2; |
||
627 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
628 | "ProfileBegin", |
||
629 | Primitive.UnpackBeginCut(profileBegin), |
||
630 | "float"); |
||
631 | |||
632 | ushort profileEnd = Utils.BytesToUInt16(block, i); |
||
633 | i += 2; |
||
634 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
635 | "ProfileEnd", |
||
636 | Primitive.UnpackEndCut(profileEnd), |
||
637 | "float"); |
||
638 | |||
639 | ushort profileHollow = Utils.BytesToUInt16(block, i); |
||
640 | i += 2; |
||
641 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
642 | "ProfileHollow", |
||
643 | Primitive.UnpackProfileHollow(profileHollow), |
||
644 | "float"); |
||
645 | |||
646 | int textureEntryLength = (int)Utils.BytesToUInt(block, i); |
||
647 | i += 4; |
||
648 | //prim.Textures = new Primitive.TextureEntry(block, i, textureEntryLength); |
||
649 | String s = DecodeTextureEntry("TextureEntry", new Primitive.TextureEntry(block, i, textureEntryLength)); |
||
650 | result.AppendLine(s); |
||
651 | i += textureEntryLength; |
||
652 | |||
653 | // Texture animation |
||
654 | if ((flags & CompressedFlags.TextureAnimation) != 0) |
||
655 | { |
||
656 | i += 4; |
||
657 | string a = DecodeObjectTextureAnim("TextureAnimation", new Primitive.TextureAnimation(block, i)); |
||
658 | result.AppendLine(a); |
||
659 | } |
||
660 | |||
661 | return result.ToString(); |
||
662 | } |
||
663 | |||
664 | private static string DecodeObjectData(string fieldName, object fieldData) |
||
665 | { |
||
666 | byte[] data = (byte[])fieldData; |
||
667 | if (data.Length == 1) |
||
668 | { |
||
669 | return String.Format("{0,30}: {1,2} {2,-38} [{3}]", |
||
670 | fieldName + " (Tree Species)", |
||
671 | fieldData, |
||
672 | "(" + (Tree)(byte)fieldData + ")", |
||
673 | fieldData.GetType().Name); |
||
674 | } |
||
675 | else if (data.Length == 60) |
||
676 | { |
||
677 | /* TODO: these are likely useful packed fields, |
||
678 | * need to unpack them */ |
||
679 | return Utils.BytesToHexString((byte[])fieldData, String.Format("{0,30}", fieldName)); |
||
680 | } |
||
681 | else |
||
682 | { |
||
683 | return Utils.BytesToHexString((byte[])fieldData, String.Format("{0,30}", fieldName)); |
||
684 | } |
||
685 | } |
||
686 | |||
687 | private static string DecodeObjectTextureAnim(string fieldName, object fieldData) |
||
688 | { |
||
689 | StringBuilder result = new StringBuilder(); |
||
690 | Primitive.TextureAnimation TextureAnim; |
||
691 | if (fieldData is Primitive.TextureAnimation) |
||
692 | TextureAnim = (Primitive.TextureAnimation)fieldData; |
||
693 | else |
||
694 | TextureAnim = new Primitive.TextureAnimation((byte[])fieldData, 0); |
||
695 | |||
696 | result.AppendFormat("{0,30}", " <TextureAnimation>" + Environment.NewLine); |
||
697 | GenericTypeDecoder(TextureAnim, ref result); |
||
698 | result.AppendFormat("{0,30}", "</TextureAnimation>"); |
||
699 | |||
700 | return result.ToString(); |
||
701 | } |
||
702 | |||
703 | private static string DecodeEstateParameter(string fieldName, object fieldData) |
||
704 | { |
||
705 | byte[] bytes = (byte[])fieldData; |
||
706 | |||
707 | if (bytes.Length == 17) |
||
708 | { |
||
709 | return String.Format("{0,30}: {1,-40} [UUID]", fieldName, new UUID((byte[])fieldData, 0)); |
||
710 | } |
||
711 | else |
||
712 | { |
||
713 | return String.Format("{0,30}: {1,-40} [Byte[]]", fieldName, Utils.BytesToString((byte[])fieldData)); |
||
714 | } |
||
715 | } |
||
716 | |||
717 | private static string DecodeNameValue(string fieldName, object fieldData) |
||
718 | { |
||
719 | string nameValue = Utils.BytesToString((byte[])fieldData); |
||
720 | NameValue[] nameValues = null; |
||
721 | if (nameValue.Length > 0) |
||
722 | { |
||
723 | string[] lines = nameValue.Split('\n'); |
||
724 | nameValues = new NameValue[lines.Length]; |
||
725 | |||
726 | for (int i = 0; i < lines.Length; i++) |
||
727 | { |
||
728 | if (!String.IsNullOrEmpty(lines[i])) |
||
729 | { |
||
730 | NameValue nv = new NameValue(lines[i]); |
||
731 | nameValues[i] = nv; |
||
732 | } |
||
733 | } |
||
734 | } |
||
735 | |||
736 | StringBuilder result = new StringBuilder(); |
||
737 | result.AppendFormat("{0,30}", " <NameValues>" + Environment.NewLine); |
||
738 | if (nameValues != null) |
||
739 | { |
||
740 | for (int i = 0; i < nameValues.Length; i++) |
||
741 | { |
||
742 | result.AppendFormat( |
||
743 | "{0,30}: Name={1} Value={2} Class={3} Type={4} Sendto={5}" + Environment.NewLine, "NameValue", |
||
744 | nameValues[i].Name, nameValues[i].Value, nameValues[i].Class, nameValues[i].Type, nameValues[i].Sendto); |
||
745 | } |
||
746 | } |
||
747 | result.AppendFormat("{0,30}", "</NameValues>"); |
||
748 | return result.ToString(); |
||
749 | } |
||
750 | |||
751 | private static string DecodeObjectExtraParams(string fieldName, object fieldData) |
||
752 | { |
||
753 | |||
754 | byte[] data = (byte[])fieldData; |
||
755 | |||
756 | int i = 0; |
||
757 | //int totalLength = 1; |
||
758 | |||
759 | Primitive.FlexibleData Flexible = null; |
||
760 | Primitive.LightData Light = null; |
||
761 | Primitive.SculptData Sculpt = null; |
||
762 | |||
763 | byte extraParamCount = data[i++]; |
||
764 | |||
765 | for (int k = 0; k < extraParamCount; k++) |
||
766 | { |
||
767 | ExtraParamType type = (ExtraParamType)Utils.BytesToUInt16(data, i); |
||
768 | i += 2; |
||
769 | |||
770 | uint paramLength = Utils.BytesToUInt(data, i); |
||
771 | i += 4; |
||
772 | |||
773 | if (type == ExtraParamType.Flexible) |
||
774 | Flexible = new Primitive.FlexibleData(data, i); |
||
775 | else if (type == ExtraParamType.Light) |
||
776 | Light = new Primitive.LightData(data, i); |
||
777 | else if (type == ExtraParamType.Sculpt) |
||
778 | Sculpt = new Primitive.SculptData(data, i); |
||
779 | |||
780 | i += (int)paramLength; |
||
781 | //totalLength += (int)paramLength + 6; |
||
782 | } |
||
783 | |||
784 | StringBuilder result = new StringBuilder(); |
||
785 | result.AppendFormat("{0,30}", "<ExtraParams>" + Environment.NewLine); |
||
786 | if (Flexible != null) |
||
787 | { |
||
788 | result.AppendFormat("{0,30}", "<Flexible>" + Environment.NewLine); |
||
789 | GenericTypeDecoder(Flexible, ref result); |
||
790 | result.AppendFormat("{0,30}", "</Flexible>" + Environment.NewLine); |
||
791 | } |
||
792 | |||
793 | if (Sculpt != null) |
||
794 | { |
||
795 | result.AppendFormat("{0,30}", "<Sculpt>" + Environment.NewLine); |
||
796 | GenericTypeDecoder(Sculpt, ref result); |
||
797 | result.AppendFormat("{0,30}", "</Sculpt>" + Environment.NewLine); |
||
798 | } |
||
799 | |||
800 | if (Light != null) |
||
801 | { |
||
802 | result.AppendFormat("{0,30}", "<Light>" + Environment.NewLine); |
||
803 | GenericTypeDecoder(Light, ref result); |
||
804 | result.AppendFormat("{0,30}", "</Light>" + Environment.NewLine); |
||
805 | } |
||
806 | |||
807 | result.AppendFormat("{0,30}", "</ExtraParams>"); |
||
808 | return result.ToString(); |
||
809 | } |
||
810 | |||
811 | private static string DecodeObjectParticleSystem(string fieldName, object fieldData) |
||
812 | { |
||
813 | StringBuilder result = new StringBuilder(); |
||
814 | Primitive.ParticleSystem ParticleSys; |
||
815 | if (fieldData is Primitive.ParticleSystem) |
||
816 | ParticleSys = (Primitive.ParticleSystem)fieldData; |
||
817 | else |
||
818 | ParticleSys = new Primitive.ParticleSystem((byte[])fieldData, 0); |
||
819 | |||
820 | result.AppendFormat("{0,30}", "<ParticleSystem>" + Environment.NewLine); |
||
821 | GenericTypeDecoder(ParticleSys, ref result); |
||
822 | result.AppendFormat("{0,30}", "</ParticleSystem>"); |
||
823 | |||
824 | return result.ToString(); |
||
825 | } |
||
826 | |||
827 | private static void GenericTypeDecoder(object obj, ref StringBuilder result) |
||
828 | { |
||
829 | FieldInfo[] fields = obj.GetType().GetFields(); |
||
830 | |||
831 | foreach (FieldInfo field in fields) |
||
832 | { |
||
833 | String special; |
||
834 | if (SpecialDecoder("a" + "." + "b" + "." + field.Name, |
||
835 | field.GetValue(obj), out special)) |
||
836 | { |
||
837 | result.AppendLine(special); |
||
838 | } |
||
839 | else |
||
840 | { |
||
841 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
842 | field.Name, |
||
843 | field.GetValue(obj), |
||
844 | field.FieldType.Name); |
||
845 | } |
||
846 | } |
||
847 | } |
||
848 | |||
849 | private static string DecodeObjectPCode(string fieldName, object fieldData) |
||
850 | { |
||
851 | return String.Format("{0,30}: {1,-3} {2,-36} [PCode]", |
||
852 | fieldName, |
||
853 | fieldData, |
||
854 | "(" + (PCode)(byte)fieldData + ")"); |
||
855 | } |
||
856 | |||
857 | private static string DecodeImageType(string fieldName, object fieldData) |
||
858 | { |
||
859 | return String.Format("{0,30}: {1,-3} {2,-36} [ImageType]", |
||
860 | fieldName, |
||
861 | fieldData, |
||
862 | "(" + (ImageType)(byte)fieldData + ")"); |
||
863 | } |
||
864 | |||
865 | private static string DecodeImageCodec(string fieldName, object fieldData) |
||
866 | { |
||
867 | return String.Format("{0,30}: {1,-3} {2,-36} [ImageCodec]", |
||
868 | fieldName, |
||
869 | fieldData, |
||
870 | "(" + (ImageCodec)(byte)fieldData + ")"); |
||
871 | } |
||
872 | |||
873 | private static string DecodeObjectMaterial(string fieldName, object fieldData) |
||
874 | { |
||
875 | return String.Format("{0,30}: {1,-3} {2,-36} [Material]", |
||
876 | fieldName, |
||
877 | fieldData, |
||
878 | "(" + (Material)(byte)fieldData + ")"); |
||
879 | } |
||
880 | |||
881 | private static string DecodeObjectClickAction(string fieldName, object fieldData) |
||
882 | { |
||
883 | return String.Format("{0,30}: {1,-3} {2,-36} [ClickAction]", |
||
884 | fieldName, |
||
885 | fieldData, |
||
886 | "(" + (ClickAction)(byte)fieldData + ")"); |
||
887 | } |
||
888 | |||
889 | private static string DecodeEventFlags(string fieldName, object fieldData) |
||
890 | { |
||
891 | return String.Format("{0,30}: {1,-3} {2,-36} [EventFlags]", |
||
892 | fieldName, |
||
893 | fieldData, |
||
894 | "(" + (DirectoryManager.EventFlags)(uint)fieldData + ")"); |
||
895 | } |
||
896 | |||
897 | private static string DecodeDirQueryFlags(string fieldName, object fieldData) |
||
898 | { |
||
899 | return String.Format("{0,30}: {1,-10} {2,-29} [DirectoryManager.DirFindFlags]", |
||
900 | fieldName, |
||
901 | fieldData, |
||
902 | "(" + (DirectoryManager.DirFindFlags)(uint)fieldData + ")"); |
||
903 | } |
||
904 | |||
905 | private static string DecodeDirClassifiedQueryFlags(string fieldName, object fieldData) |
||
906 | { |
||
907 | return String.Format("{0,30}: {1,-10} {2,-29} [ClassifiedQueryFlags]", |
||
908 | fieldName, |
||
909 | fieldData, |
||
910 | "(" + (DirectoryManager.ClassifiedQueryFlags)(uint)fieldData + ")"); |
||
911 | } |
||
912 | |||
913 | private static string DecodeDirClassifiedFlags(string fieldName, object fieldData) |
||
914 | { |
||
915 | return String.Format("{0,30}: {1,-10} {2,-29} [ClassifiedFlags]", |
||
916 | fieldName, |
||
917 | fieldData, |
||
918 | "(" + (DirectoryManager.ClassifiedFlags)(byte)fieldData + ")"); |
||
919 | } |
||
920 | |||
921 | private static string DecodeGroupPowers(string fieldName, object fieldData) |
||
922 | { |
||
923 | return String.Format("{0,30}: {1,-20} {2,-19} [GroupPowers]", |
||
924 | fieldName, |
||
925 | fieldData, |
||
926 | "(" + (GroupPowers)(ulong)fieldData + ")"); |
||
927 | } |
||
928 | |||
929 | private static string DecodeParcelACL(string fieldName, object fieldData) |
||
930 | { |
||
931 | return String.Format("{0,30}: {1,-10} {2,-29} [AccessList]", |
||
932 | fieldName, |
||
933 | fieldData, |
||
934 | "(" + (AccessList)(uint)fieldData + ")"); |
||
935 | } |
||
936 | |||
937 | private static string SearchTypeFlags(string fieldName, object fieldData) |
||
938 | { |
||
939 | return String.Format("{0,30}: {1,-10} {2,-29} [DirectoryManager.SearchTypeFlags]", |
||
940 | fieldName, |
||
941 | fieldData, |
||
942 | "(" + (DirectoryManager.SearchTypeFlags)(uint)fieldData + ")"); |
||
943 | } |
||
944 | |||
945 | private static string DecodeCategory(string fieldName, object fieldData) |
||
946 | { |
||
947 | return String.Format("{0,30}: {1,-3} {2,-36} [ParcelCategory]", |
||
948 | fieldName, |
||
949 | fieldData, |
||
950 | "(" + fieldData + ")"); |
||
951 | } |
||
952 | |||
953 | private static string DecodeObjectUpdateFlags(string fieldName, object fieldData) |
||
954 | { |
||
955 | return String.Format("{0,30}: {1,-10} {2,-29} [PrimFlags]", |
||
956 | fieldName, |
||
957 | fieldData, |
||
958 | "(" + (PrimFlags)(uint)fieldData + ")"); |
||
959 | } |
||
960 | |||
961 | private static string DecodeTeleportFlags(string fieldName, object fieldData) |
||
962 | { |
||
963 | return String.Format("{0,30}: {1,-10} {2,-29} [TeleportFlags]", |
||
964 | fieldName, |
||
965 | fieldData, |
||
966 | "(" + (TeleportFlags)(uint)fieldData + ")"); |
||
967 | } |
||
968 | |||
969 | private static string DecodeScriptControls(string fieldName, object fieldData) |
||
970 | { |
||
971 | return String.Format("{0,30}: {1,-10} {2,-29} [AgentManager.ControlFlags]", |
||
972 | fieldName, |
||
973 | (uint)fieldData, |
||
974 | "(" + (AgentManager.ControlFlags)(uint)fieldData + ")"); |
||
975 | } |
||
976 | |||
977 | private static string DecodeColorField(string fieldName, object fieldData) |
||
978 | { |
||
979 | return String.Format("{0,30}: {1,-40} [Color4]", |
||
980 | fieldName, |
||
981 | fieldData.GetType().Name.Equals("Color4") ? (Color4)fieldData : new Color4((byte[])fieldData, 0, false)); |
||
982 | } |
||
983 | |||
984 | private static string DecodeTimeStamp(string fieldName, object fieldData) |
||
985 | { |
||
986 | if (fieldData is Int32 && (int)fieldData > 0) |
||
987 | return String.Format("{0,30}: {1,-10} {2,-29} [{3}]", |
||
988 | fieldName, |
||
989 | fieldData, |
||
990 | "(" + Utils.UnixTimeToDateTime((int)fieldData) + ")", |
||
991 | fieldData.GetType().Name); |
||
992 | else if (fieldData is uint && (uint)fieldData > 0) |
||
993 | return String.Format("{0,30}: {1,-10} {2,-29} [{3}]", |
||
994 | fieldName, |
||
995 | fieldData, |
||
996 | "(" + Utils.UnixTimeToDateTime((uint)fieldData) + ")", |
||
997 | fieldData.GetType().Name); |
||
998 | else |
||
999 | return String.Format("{0,30}: {1,-40} [{2}]", |
||
1000 | fieldName, |
||
1001 | fieldData, |
||
1002 | fieldData.GetType().Name); |
||
1003 | } |
||
1004 | |||
1005 | private static string DecodeBinaryBucket(string fieldName, object fieldData) |
||
1006 | { |
||
1007 | byte[] bytes = (byte[])fieldData; |
||
1008 | string bucket = String.Empty; |
||
1009 | if (bytes.Length == 1) |
||
1010 | { |
||
1011 | bucket = String.Format("{0}", bytes[0]); |
||
1012 | } |
||
1013 | else if (bytes.Length == 17) |
||
1014 | { |
||
1015 | bucket = String.Format("{0,-36} {1} ({2})", |
||
1016 | new UUID(bytes, 1), |
||
1017 | bytes[0], |
||
1018 | (AssetType)(sbyte)bytes[0]); |
||
1019 | } |
||
1020 | else if (bytes.Length == 16) // the folder ID for the asset to be stored into if we accept an inventory offer |
||
1021 | { |
||
1022 | bucket = new UUID(bytes, 0).ToString(); |
||
1023 | } |
||
1024 | else |
||
1025 | { |
||
1026 | bucket = Utils.BytesToString(bytes); // we'll try a string lastly |
||
1027 | } |
||
1028 | |||
1029 | return String.Format("{0,30}: {1,-40} [Byte[{2}]]", fieldName, bucket, bytes.Length); |
||
1030 | } |
||
1031 | |||
1032 | private static string DecodeBinaryToHexString(string fieldName, object fieldData) |
||
1033 | { |
||
1034 | return String.Format("{0,30}", |
||
1035 | Utils.BytesToHexString((byte[])fieldData, |
||
1036 | String.Format("{0,30}", fieldName))); |
||
1037 | } |
||
1038 | |||
1039 | private static string DecodeWearableType(string fieldName, object fieldData) |
||
1040 | { |
||
1041 | return String.Format("{0,30}: {1,-2} {2,-37} [WearableType]", |
||
1042 | fieldName, |
||
1043 | (byte)fieldData, |
||
1044 | "(" + (WearableType)fieldData + ")"); |
||
1045 | } |
||
1046 | |||
1047 | private static string DecodeInventoryType(string fieldName, object fieldData) |
||
1048 | { |
||
1049 | return String.Format("{0,30}: {1,-2} {2,-37} [AssetType]", |
||
1050 | fieldName, |
||
1051 | (sbyte)fieldData, |
||
1052 | "(" + (AssetType)(sbyte)fieldData + ")"); |
||
1053 | } |
||
1054 | |||
1055 | private static string DecodeInventorySort(string fieldName, object fieldData) |
||
1056 | { |
||
1057 | return String.Format("{0,30}: {1,-2} {2,-37} [InventorySortOrder]", |
||
1058 | fieldName, |
||
1059 | fieldData, |
||
1060 | "(" + (InventorySortOrder)(int)fieldData + ")"); |
||
1061 | } |
||
1062 | |||
1063 | private static string DecodeInventoryInvType(string fieldName, object fieldData) |
||
1064 | { |
||
1065 | return String.Format("{0,30}: {1,-2} {2,-37} [InventoryType]", |
||
1066 | fieldName, |
||
1067 | (sbyte)fieldData, |
||
1068 | "(" + (InventoryType)fieldData + ")"); |
||
1069 | } |
||
1070 | |||
1071 | private static string DecodeFolderType(string fieldName, object fieldData) |
||
1072 | { |
||
1073 | return String.Format("{0,30}: {1,-2} {2,-37} [AssetType]", |
||
1074 | fieldName, |
||
1075 | (sbyte)fieldData, |
||
1076 | "(" + (AssetType)fieldData + ")"); |
||
1077 | } |
||
1078 | |||
1079 | private static string DecodeInventoryFlags(string fieldName, object fieldData) |
||
1080 | { |
||
1081 | return String.Format("{0,30}: {1,-2} {2,-37} [InventoryItemFlags]", |
||
1082 | fieldName, |
||
1083 | (uint)fieldData, |
||
1084 | "(" + (InventoryItemFlags)(uint)fieldData + ")"); |
||
1085 | } |
||
1086 | |||
1087 | private static string DecodeObjectSaleType(string fieldName, object fieldData) |
||
1088 | { |
||
1089 | return String.Format("{0,30}: {1,-2} {2,-37} [SaleType]", |
||
1090 | fieldName, |
||
1091 | (byte)fieldData, |
||
1092 | "(" + (SaleType)fieldData + ")"); |
||
1093 | } |
||
1094 | |||
1095 | private static string DecodeRegionFlags(string fieldName, object fieldData) |
||
1096 | { |
||
1097 | return String.Format("{0,30}: {1,-2} {2,-37} [RegionFlags]", |
||
1098 | fieldName, |
||
1099 | fieldData, |
||
1100 | "(" + (RegionFlags)(uint)fieldData + ")"); |
||
1101 | } |
||
1102 | |||
1103 | private static string DecodeTransferParams(string fieldName, object fieldData) |
||
1104 | { |
||
1105 | byte[] paramData = (byte[])fieldData; |
||
1106 | StringBuilder result = new StringBuilder(); |
||
1107 | result.AppendLine(" <Params>"); |
||
1108 | if (paramData.Length == 20) |
||
1109 | { |
||
1110 | result.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine, |
||
1111 | "AssetID", |
||
1112 | new UUID(paramData, 0)); |
||
1113 | |||
1114 | result.AppendFormat("{0,30}: {1,-2} {2,-37} [AssetType]" + Environment.NewLine, |
||
1115 | "AssetType", |
||
1116 | (sbyte)paramData[16], |
||
1117 | "(" + (AssetType)(sbyte)paramData[16] + ")"); |
||
1118 | |||
1119 | } |
||
1120 | else if (paramData.Length == 100) |
||
1121 | { |
||
1122 | //UUID agentID = new UUID(info.TransferInfo.Params, 0); |
||
1123 | result.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine, |
||
1124 | "AgentID", |
||
1125 | new UUID(paramData, 0)); |
||
1126 | |||
1127 | //UUID sessionID = new UUID(info.TransferInfo.Params, 16); |
||
1128 | result.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine, |
||
1129 | "SessionID", |
||
1130 | new UUID(paramData, 16)); |
||
1131 | //UUID ownerID = new UUID(info.TransferInfo.Params, 32); |
||
1132 | result.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine, |
||
1133 | "OwnerID", |
||
1134 | new UUID(paramData, 32)); |
||
1135 | //UUID taskID = new UUID(info.TransferInfo.Params, 48); |
||
1136 | result.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine, |
||
1137 | "TaskID", |
||
1138 | new UUID(paramData, 48)); |
||
1139 | //UUID itemID = new UUID(info.TransferInfo.Params, 64); |
||
1140 | result.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine, |
||
1141 | "ItemID", |
||
1142 | new UUID(paramData, 64)); |
||
1143 | |||
1144 | result.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine, |
||
1145 | "AssetID", |
||
1146 | new UUID(paramData, 80)); |
||
1147 | |||
1148 | result.AppendFormat("{0,30}: {1,-2} {2,-37} [AssetType]" + Environment.NewLine, |
||
1149 | "AssetType", |
||
1150 | (sbyte)paramData[96], |
||
1151 | "(" + (AssetType)(sbyte)paramData[96] + ")"); |
||
1152 | } |
||
1153 | else |
||
1154 | { |
||
1155 | Console.WriteLine("Oh Poop!"); |
||
1156 | } |
||
1157 | |||
1158 | result.Append("</Params>"); |
||
1159 | |||
1160 | return result.ToString(); |
||
1161 | } |
||
1162 | |||
1163 | private static string DecodeTransferChannelType(string fieldName, object fieldData) |
||
1164 | { |
||
1165 | return String.Format("{0,30}: {1,-2} {2,-37} [ChannelType]", |
||
1166 | fieldName, |
||
1167 | fieldData, |
||
1168 | "(" + (ChannelType)(int)fieldData + ")"); |
||
1169 | } |
||
1170 | |||
1171 | private static string DecodeTransferSourceType(string fieldName, object fieldData) |
||
1172 | { |
||
1173 | return String.Format("{0,30}: {1,-2} {2,-37} [SourceType]", |
||
1174 | fieldName, |
||
1175 | fieldData, |
||
1176 | "(" + (SourceType)(int)fieldData + ")"); |
||
1177 | } |
||
1178 | |||
1179 | private static string DecodeTransferTargetType(string fieldName, object fieldData) |
||
1180 | { |
||
1181 | return String.Format("{0,30}: {1,-2} {2,-37} [TargetType]", |
||
1182 | fieldName, |
||
1183 | fieldData, |
||
1184 | "(" + (TargetType)(int)fieldData + ")"); |
||
1185 | } |
||
1186 | |||
1187 | private static string DecodeMapRequestFlags(string fieldName, object fieldData) |
||
1188 | { |
||
1189 | return String.Format("{0,30}: {1,-2} {2,-37} [GridLayerType]", |
||
1190 | fieldName, |
||
1191 | fieldData, |
||
1192 | "(" + (GridLayerType)(uint)fieldData + ")"); |
||
1193 | } |
||
1194 | |||
1195 | private static string DecodeGridItemType(string fieldName, object fieldData) |
||
1196 | { |
||
1197 | return String.Format("{0,30}: {1,-2} {2,-37} [GridItemType]", |
||
1198 | fieldName, |
||
1199 | fieldData, |
||
1200 | "(" + (GridItemType)(uint)fieldData + ")"); |
||
1201 | |||
1202 | } |
||
1203 | |||
1204 | private static string DecodeLayerDataType(string fieldName, object fieldData) |
||
1205 | { |
||
1206 | return String.Format("{0,30}: {1,-2} {2,-37} [LayerType]", |
||
1207 | fieldName, |
||
1208 | fieldData, |
||
1209 | "(" + (TerrainPatch.LayerType)(byte)fieldData + ")"); |
||
1210 | } |
||
1211 | |||
1212 | private static string DecodeMapAccess(string fieldName, object fieldData) |
||
1213 | { |
||
1214 | return String.Format("{0,30}: {1,-2} {2,-37} [SimAccess]", |
||
1215 | fieldName, |
||
1216 | fieldData, |
||
1217 | "(" + (SimAccess)(byte)fieldData + ")"); |
||
1218 | } |
||
1219 | |||
1220 | private static string DecodeSimAccess(string fieldName, object fieldData) |
||
1221 | { |
||
1222 | return String.Format("{0,30}: {1,-2} {2,-37} [SimAccess]", |
||
1223 | fieldName, |
||
1224 | (byte)fieldData, |
||
1225 | "(" + (SimAccess)fieldData + ")"); |
||
1226 | } |
||
1227 | |||
1228 | private static string DecodeAttachedSoundFlags(string fieldName, object fieldData) |
||
1229 | { |
||
1230 | return String.Format("{0,30}: {1,-2} {2,-37} [SoundFlags]", |
||
1231 | fieldName, |
||
1232 | (byte)fieldData, |
||
1233 | "(" + (SoundFlags)fieldData + ")"); |
||
1234 | } |
||
1235 | |||
1236 | |||
1237 | private static string DecodeChatSourceType(string fieldName, object fieldData) |
||
1238 | { |
||
1239 | return String.Format("{0,30}: {1,-2} {2,-37} [SourceType]", |
||
1240 | fieldName, |
||
1241 | fieldData, |
||
1242 | "(" + (SourceType)(byte)fieldData + ")"); |
||
1243 | } |
||
1244 | |||
1245 | private static string DecodeChatChatType(string fieldName, object fieldData) |
||
1246 | { |
||
1247 | return String.Format("{0,30}: {1,-2} {2,-37} [ChatType]", |
||
1248 | fieldName, |
||
1249 | (byte)fieldData, |
||
1250 | "(" + (ChatType)fieldData + ")"); |
||
1251 | } |
||
1252 | |||
1253 | private static string DecodeChatAudible(string fieldName, object fieldData) |
||
1254 | { |
||
1255 | return String.Format("{0,30}: {1,-2} {2,-37} [ChatAudibleLevel]", |
||
1256 | fieldName, |
||
1257 | (byte)fieldData, |
||
1258 | "(" + (ChatAudibleLevel)(byte)fieldData + ")"); |
||
1259 | } |
||
1260 | |||
1261 | private static string DecodeImageData(string fieldName, object fieldData) |
||
1262 | { |
||
1263 | return String.Format("{0,10}", |
||
1264 | Utils.BytesToHexString((byte[])fieldData, |
||
1265 | String.Format("{0,30}", fieldName))); |
||
1266 | } |
||
1267 | |||
1268 | private static string DecodeTerseTextureEntry(string fieldName, object fieldData) |
||
1269 | { |
||
1270 | byte[] block = (byte[])fieldData; |
||
1271 | |||
1272 | Primitive.TextureEntry te = new Primitive.TextureEntry(block, 4, block.Length - 4); |
||
1273 | |||
1274 | StringBuilder result = new StringBuilder(); |
||
1275 | |||
1276 | result.AppendFormat("{0,30}", " <TextureEntry>" + Environment.NewLine); |
||
1277 | if (te.DefaultTexture != null) |
||
1278 | { |
||
1279 | result.AppendFormat("{0,30}", " <DefaultTexture>" + Environment.NewLine); |
||
1280 | GenericFieldsDecoder(te.DefaultTexture, ref result); |
||
1281 | GenericPropertiesDecoder(te.DefaultTexture, ref result); |
||
1282 | result.AppendFormat("{0,30}", " </DefaultTexture>" + Environment.NewLine); |
||
1283 | } |
||
1284 | result.AppendFormat("{0,30}", " <FaceTextures>" + Environment.NewLine); |
||
1285 | for (int i = 0; i < te.FaceTextures.Length; i++) |
||
1286 | { |
||
1287 | if (te.FaceTextures[i] != null) |
||
1288 | { |
||
1289 | result.AppendFormat("{0,30}[{1}]" + Environment.NewLine, "FaceTexture", i); |
||
1290 | GenericFieldsDecoder(te.FaceTextures[i], ref result); |
||
1291 | GenericPropertiesDecoder(te.FaceTextures[i], ref result); |
||
1292 | } |
||
1293 | } |
||
1294 | result.AppendFormat("{0,30}", " </FaceTextures>" + Environment.NewLine); |
||
1295 | result.AppendFormat("{0,30}", "</TextureEntry>"); |
||
1296 | |||
1297 | return result.ToString(); |
||
1298 | } |
||
1299 | |||
1300 | private static string DecodeTextureEntry(string fieldName, object fieldData) |
||
1301 | { |
||
1302 | Primitive.TextureEntry te; |
||
1303 | if (fieldData is Primitive.TextureEntry) |
||
1304 | te = (Primitive.TextureEntry)fieldData; |
||
1305 | else |
||
1306 | { |
||
1307 | byte[] tebytes = (byte[])fieldData; |
||
1308 | te = new Primitive.TextureEntry(tebytes, 0, tebytes.Length); |
||
1309 | } |
||
1310 | |||
1311 | StringBuilder result = new StringBuilder(); |
||
1312 | |||
1313 | result.AppendFormat("{0,30}", " <TextureEntry>" + Environment.NewLine); |
||
1314 | if (te.DefaultTexture != null) |
||
1315 | { |
||
1316 | result.AppendFormat("{0,30}", " <DefaultTexture>" + Environment.NewLine); |
||
1317 | GenericFieldsDecoder(te.DefaultTexture, ref result); |
||
1318 | GenericPropertiesDecoder(te.DefaultTexture, ref result); |
||
1319 | result.AppendFormat("{0,30}", " </DefaultTexture>" + Environment.NewLine); |
||
1320 | } |
||
1321 | result.AppendFormat("{0,30}", " <FaceTextures>" + Environment.NewLine); |
||
1322 | for (int i = 0; i < te.FaceTextures.Length; i++) |
||
1323 | { |
||
1324 | if (te.FaceTextures[i] != null) |
||
1325 | { |
||
1326 | result.AppendFormat("{0,30}[{1}]" + Environment.NewLine, "FaceTexture", i); |
||
1327 | GenericFieldsDecoder(te.FaceTextures[i], ref result); |
||
1328 | GenericPropertiesDecoder(te.FaceTextures[i], ref result); |
||
1329 | } |
||
1330 | } |
||
1331 | result.AppendFormat("{0,30}", " </FaceTextures>" + Environment.NewLine); |
||
1332 | result.AppendFormat("{0,30}", "</TextureEntry>"); |
||
1333 | |||
1334 | return result.ToString(); |
||
1335 | } |
||
1336 | |||
1337 | private static void GenericFieldsDecoder(object obj, ref StringBuilder result) |
||
1338 | { |
||
1339 | Type parcelType = obj.GetType(); |
||
1340 | FieldInfo[] fields = parcelType.GetFields(); |
||
1341 | foreach (FieldInfo field in fields) |
||
1342 | { |
||
1343 | String special; |
||
1344 | if (SpecialDecoder("a" + "." + "b" + "." + field.Name, |
||
1345 | field.GetValue(obj), out special)) |
||
1346 | { |
||
1347 | result.AppendLine(special); |
||
1348 | } |
||
1349 | else |
||
1350 | { |
||
1351 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
1352 | field.Name, |
||
1353 | field.GetValue(obj), |
||
1354 | field.FieldType.Name); |
||
1355 | } |
||
1356 | } |
||
1357 | } |
||
1358 | |||
1359 | private static void GenericPropertiesDecoder(object obj, ref StringBuilder result) |
||
1360 | { |
||
1361 | Type parcelType = obj.GetType(); |
||
1362 | PropertyInfo[] propertyInfos = parcelType.GetProperties(); |
||
1363 | foreach (PropertyInfo property in propertyInfos) |
||
1364 | { |
||
1365 | String special; |
||
1366 | if (SpecialDecoder("a" + "." + "b" + "." + property.Name, |
||
1367 | property.GetValue(obj, null), out special)) |
||
1368 | { |
||
1369 | result.AppendLine(special); |
||
1370 | } |
||
1371 | else |
||
1372 | { |
||
1373 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
1374 | property.Name, |
||
1375 | property.GetValue(obj, null), |
||
1376 | property.PropertyType.Name); |
||
1377 | } |
||
1378 | } |
||
1379 | } |
||
1380 | |||
1381 | private static string DecodeDialog(string fieldName, object fieldData) |
||
1382 | { |
||
1383 | return String.Format("{0,30}: {1,-2} {2,-37} [{3}]", |
||
1384 | fieldName, |
||
1385 | (byte)fieldData, |
||
1386 | "(" + (InstantMessageDialog)fieldData + ")", |
||
1387 | fieldData.GetType().Name); |
||
1388 | } |
||
1389 | |||
1390 | private static string DecodeControlFlags(string fieldName, object fieldData) |
||
1391 | { |
||
1392 | return String.Format("{0,30}: {1,-10} {2,-29} [{3}]", |
||
1393 | fieldName, |
||
1394 | fieldData, |
||
1395 | "(" + (AgentManager.ControlFlags)(uint)fieldData + ")", |
||
1396 | fieldData.GetType().Name); |
||
1397 | } |
||
1398 | |||
1399 | private static string DecodePermissionMask(string fieldName, object fieldData) |
||
1400 | { |
||
1401 | return String.Format("{0,30}: {1,-10} {2,-29} [{3}]", |
||
1402 | fieldName, |
||
1403 | (uint)fieldData, |
||
1404 | "(" + (PermissionMask)fieldData + ")", |
||
1405 | fieldData.GetType().Name); |
||
1406 | } |
||
1407 | |||
1408 | private static string DecodeViewerEffectTypeData(string fieldName, object fieldData) |
||
1409 | { |
||
1410 | byte[] data = (byte[])fieldData; |
||
1411 | StringBuilder sb = new StringBuilder(); |
||
1412 | if (data.Length == 56 || data.Length == 57) |
||
1413 | { |
||
1414 | UUID sourceAvatar = new UUID(data, 0); |
||
1415 | UUID targetObject = new UUID(data, 16); |
||
1416 | Vector3d targetPos = new Vector3d(data, 32); |
||
1417 | sb.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine, fieldName, "Source AvatarID=" + sourceAvatar); |
||
1418 | sb.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine, fieldName, "Target ObjectID=" + targetObject); |
||
1419 | |||
1420 | |||
1421 | float lx, ly; |
||
1422 | Helpers.GlobalPosToRegionHandle((float)targetPos.X, (float)targetPos.Y, out lx, out ly); |
||
1423 | |||
1424 | sb.AppendFormat("{0,30}: {1,-40} [Vector3d]", fieldName, targetPos); |
||
1425 | |||
1426 | if (data.Length == 57) |
||
1427 | { |
||
1428 | sb.AppendLine(); |
||
1429 | sb.AppendFormat("{0,30}: {1,-17} {2,-22} [Byte]", fieldName, "Point At Type=" + data[56], |
||
1430 | "(" + (PointAtType)data[56] + ")"); |
||
1431 | } |
||
1432 | |||
1433 | return sb.ToString(); |
||
1434 | } |
||
1435 | else |
||
1436 | { |
||
1437 | return String.Format("{0,30}: (No Decoder) Length={1}" + Environment.NewLine, fieldName, data.Length) + Utils.BytesToHexString(data, String.Format("{0,30}", "")); |
||
1438 | } |
||
1439 | } |
||
1440 | |||
1441 | private static string DecodeAgentState(string fieldName, object fieldData) |
||
1442 | { |
||
1443 | return String.Format("{0,30}: {1,-2} {2,-37} [AgentState]", |
||
1444 | fieldName, |
||
1445 | fieldData, |
||
1446 | "(" + (AgentState)(byte)fieldData + ")"); |
||
1447 | } |
||
1448 | |||
1449 | private static string DecodeAgentFlags(string fieldName, object fieldData) |
||
1450 | { |
||
1451 | return String.Format("{0,30}: {1,-2} {2,-37} [AgentFlags]", |
||
1452 | fieldName, |
||
1453 | fieldData, |
||
1454 | "(" + (AgentFlags)(byte)fieldData + ")"); |
||
1455 | } |
||
1456 | |||
1457 | private static string DecodeObjectState(string fieldName, object fieldData) |
||
1458 | { |
||
1459 | return String.Format("{0,30}: {1,-2} {2,-37} [AttachmentPoint]", |
||
1460 | fieldName, |
||
1461 | fieldData, |
||
1462 | "(" + (AttachmentPoint)(byte)fieldData + ")"); |
||
1463 | } |
||
1464 | |||
1465 | private static string DecodeViewerEffectType(string fieldName, object fieldData) |
||
1466 | { |
||
1467 | return String.Format("{0,30}: {1,-2} {2,-37} [{3}]", |
||
1468 | fieldName, |
||
1469 | fieldData, |
||
1470 | "(" + (EffectType)(byte)fieldData + ")", |
||
1471 | fieldData.GetType().Name); |
||
1472 | } |
||
1473 | |||
1474 | private static string DecodeAnimToConst(string fieldName, object fieldData) |
||
1475 | { |
||
1476 | string animConst = "UUID"; |
||
1477 | Dictionary<UUID, string> animsDict = Animations.ToDictionary(); |
||
1478 | if (animsDict.ContainsKey((UUID)fieldData)) |
||
1479 | animConst = animsDict[(UUID)fieldData]; |
||
1480 | return String.Format("{0,30}: {1,-40} [{2}]", |
||
1481 | fieldName, |
||
1482 | fieldData, |
||
1483 | animConst); |
||
1484 | } |
||
1485 | #endregion |
||
1486 | |||
1487 | /// <summary> |
||
1488 | /// Creates a formatted string containing the values of a Packet |
||
1489 | /// </summary> |
||
1490 | /// <param name="packet">The Packet</param> |
||
1491 | /// <returns>A formatted string of values of the nested items in the Packet object</returns> |
||
1492 | public static string PacketToString(Packet packet) |
||
1493 | { |
||
1494 | StringBuilder result = new StringBuilder(); |
||
1495 | |||
1496 | result.AppendFormat("Packet Type: {0} http://lib.openmetaverse.org/wiki/{0} http://wiki.secondlife.com/wiki/{0}" + Environment.NewLine, packet.Type); |
||
1497 | result.AppendLine("[Packet Header]"); |
||
1498 | // payload |
||
1499 | result.AppendFormat("Sequence: {0}" + Environment.NewLine, packet.Header.Sequence); |
||
1500 | result.AppendFormat(" Options: {0}" + Environment.NewLine, InterpretOptions(packet.Header)); |
||
1501 | result.AppendLine(); |
||
1502 | |||
1503 | result.AppendLine("[Packet Payload]"); |
||
1504 | |||
1505 | FieldInfo[] fields = packet.GetType().GetFields(); |
||
1506 | |||
1507 | for (int i = 0; i < fields.Length; i++) |
||
1508 | { |
||
1509 | // we're not interested in any of these here |
||
1510 | if (fields[i].Name == "Type" || fields[i].Name == "Header" || fields[i].Name == "HasVariableBlocks") |
||
1511 | continue; |
||
1512 | |||
1513 | if (fields[i].FieldType.IsArray) |
||
1514 | { |
||
1515 | result.AppendFormat("{0,30} []" + Environment.NewLine, "-- " + fields[i].Name + " --"); |
||
1516 | RecursePacketArray(fields[i], packet, ref result); |
||
1517 | } |
||
1518 | else |
||
1519 | { |
||
1520 | result.AppendFormat("{0,30}" + Environment.NewLine, "-- " + fields[i].Name + " --"); |
||
1521 | RecursePacketField(fields[i], packet, ref result); |
||
1522 | } |
||
1523 | } |
||
1524 | return result.ToString(); |
||
1525 | } |
||
1526 | |||
1527 | public static string InterpretOptions(Header header) |
||
1528 | { |
||
1529 | return "[" |
||
1530 | + (header.AppendedAcks ? "Ack" : " ") |
||
1531 | + " " |
||
1532 | + (header.Resent ? "Res" : " ") |
||
1533 | + " " |
||
1534 | + (header.Reliable ? "Rel" : " ") |
||
1535 | + " " |
||
1536 | + (header.Zerocoded ? "Zer" : " ") |
||
1537 | + "]" |
||
1538 | ; |
||
1539 | } |
||
1540 | |||
1541 | private static void RecursePacketArray(FieldInfo fieldInfo, object packet, ref StringBuilder result) |
||
1542 | { |
||
1543 | var packetDataObject = fieldInfo.GetValue(packet); |
||
1544 | |||
1545 | foreach (object nestedArrayRecord in packetDataObject as Array) |
||
1546 | { |
||
1547 | FieldInfo[] fields = nestedArrayRecord.GetType().GetFields(); |
||
1548 | |||
1549 | for (int i = 0; i < fields.Length; i++) |
||
1550 | { |
||
1551 | String special; |
||
1552 | if (SpecialDecoder(packet.GetType().Name + "." + fieldInfo.Name + "." + fields[i].Name, |
||
1553 | fields[i].GetValue(nestedArrayRecord), out special)) |
||
1554 | { |
||
1555 | result.AppendLine(special); |
||
1556 | } |
||
1557 | else if (fields[i].FieldType.IsArray) // default for an array (probably a byte[]) |
||
1558 | { |
||
1559 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
1560 | fields[i].Name, |
||
1561 | Utils.BytesToString((byte[])fields[i].GetValue(nestedArrayRecord)), |
||
1562 | /*fields[i].GetValue(nestedArrayRecord).GetType().Name*/ "String"); |
||
1563 | } |
||
1564 | else // default for a field |
||
1565 | { |
||
1566 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
1567 | fields[i].Name, |
||
1568 | fields[i].GetValue(nestedArrayRecord), |
||
1569 | fields[i].GetValue(nestedArrayRecord).GetType().Name); |
||
1570 | } |
||
1571 | } |
||
1572 | |||
1573 | // Handle Properties |
||
1574 | foreach (PropertyInfo propertyInfo in nestedArrayRecord.GetType().GetProperties()) |
||
1575 | { |
||
1576 | if (propertyInfo.Name.Equals("Length")) |
||
1577 | continue; |
||
1578 | |||
1579 | string special; |
||
1580 | if (SpecialDecoder(packet.GetType().Name + "." + fieldInfo.Name + "." + propertyInfo.Name, |
||
1581 | propertyInfo.GetValue(nestedArrayRecord, null), |
||
1582 | out special)) |
||
1583 | { |
||
1584 | result.AppendLine(special); |
||
1585 | } |
||
1586 | else |
||
1587 | { |
||
1588 | var p = propertyInfo.GetValue(nestedArrayRecord, null); |
||
1589 | /* Leave the c for now at the end, it signifies something useful that still needs to be done i.e. a decoder written */ |
||
1590 | result.AppendFormat("{0, 30}: {1,-40} [{2}]c" + Environment.NewLine, |
||
1591 | propertyInfo.Name, |
||
1592 | Utils.BytesToString((byte[])propertyInfo.GetValue(nestedArrayRecord, null)), |
||
1593 | propertyInfo.PropertyType.Name); |
||
1594 | } |
||
1595 | } |
||
1596 | result.AppendFormat("{0,32}" + Environment.NewLine, "***"); |
||
1597 | } |
||
1598 | } |
||
1599 | |||
1600 | private static void RecursePacketField(FieldInfo fieldInfo, object packet, ref StringBuilder result) |
||
1601 | { |
||
1602 | object packetDataObject = fieldInfo.GetValue(packet); |
||
1603 | |||
1604 | // handle Fields |
||
1605 | foreach (FieldInfo packetValueField in fieldInfo.GetValue(packet).GetType().GetFields()) |
||
1606 | { |
||
1607 | string special; |
||
1608 | if (SpecialDecoder(packet.GetType().Name + "." + fieldInfo.Name + "." + packetValueField.Name, |
||
1609 | packetValueField.GetValue(packetDataObject), |
||
1610 | out special)) |
||
1611 | { |
||
1612 | result.AppendLine(special); |
||
1613 | } |
||
1614 | else if (packetValueField.FieldType.IsArray) |
||
1615 | { |
||
1616 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
1617 | packetValueField.Name, |
||
1618 | Utils.BytesToString((byte[])packetValueField.GetValue(packetDataObject)), |
||
1619 | /*packetValueField.FieldType.Name*/ "String"); |
||
1620 | } |
||
1621 | else |
||
1622 | { |
||
1623 | result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine, |
||
1624 | packetValueField.Name, packetValueField.GetValue(packetDataObject), packetValueField.FieldType.Name); |
||
1625 | |||
1626 | } |
||
1627 | } |
||
1628 | |||
1629 | // Handle Properties |
||
1630 | foreach (PropertyInfo propertyInfo in packetDataObject.GetType().GetProperties()) |
||
1631 | { |
||
1632 | if (propertyInfo.Name.Equals("Length")) |
||
1633 | continue; |
||
1634 | |||
1635 | string special; |
||
1636 | if (SpecialDecoder(packet.GetType().Name + "." + fieldInfo.Name + "." + propertyInfo.Name, |
||
1637 | propertyInfo.GetValue(packetDataObject, null), |
||
1638 | out special)) |
||
1639 | { |
||
1640 | result.AppendLine(special); |
||
1641 | } |
||
1642 | else if (propertyInfo.GetValue(packetDataObject, null).GetType() == typeof(byte[])) |
||
1643 | { |
||
1644 | result.AppendFormat("{0, 30}: {1,-40} [{2}]" + Environment.NewLine, |
||
1645 | propertyInfo.Name, |
||
1646 | Utils.BytesToString((byte[])propertyInfo.GetValue(packetDataObject, null)), |
||
1647 | propertyInfo.PropertyType.Name); |
||
1648 | } |
||
1649 | else |
||
1650 | { |
||
1651 | result.AppendFormat("{0, 30}: {1,-40} [{2}]" + Environment.NewLine, |
||
1652 | propertyInfo.Name, |
||
1653 | propertyInfo.GetValue(packetDataObject, null), |
||
1654 | propertyInfo.PropertyType.Name); |
||
1655 | } |
||
1656 | } |
||
1657 | } |
||
1658 | |||
1659 | private static bool SpecialDecoder(string decoderKey, object fieldData, out string result) |
||
1660 | { |
||
1661 | result = string.Empty; |
||
1662 | string[] keys = decoderKey.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries); |
||
1663 | string[] keyList = { decoderKey, decoderKey.Replace("Packet", ""), keys[1] + "." + keys[2], keys[2] }; |
||
1664 | foreach (string key in keyList) |
||
1665 | { |
||
1666 | |||
1667 | bool ok = true; |
||
1668 | if (fieldData is byte[]) |
||
1669 | { |
||
1670 | byte[] fd = (byte[])fieldData; |
||
1671 | ok = fd.Length > 0; |
||
1672 | if (!ok) |
||
1673 | { |
||
1674 | // bypass the decoder since we were passed an empty byte array |
||
1675 | result = String.Format("{0,30}:", keys[2]); |
||
1676 | return true; |
||
1677 | } |
||
1678 | } |
||
1679 | |||
1680 | if (ok && Callbacks.ContainsKey(key)) // fieldname e.g: Plane |
||
1681 | { |
||
1682 | foreach (CustomPacketDecoder decoder in Callbacks[key]) |
||
1683 | result = decoder(keys[2], fieldData); |
||
1684 | return true; |
||
1685 | } |
||
1686 | } |
||
1687 | return false; |
||
1688 | } |
||
1689 | |||
1690 | /// <summary> |
||
1691 | /// Decode an IMessage object into a beautifully formatted string |
||
1692 | /// </summary> |
||
1693 | /// <param name="message">The IMessage object</param> |
||
1694 | /// <param name="recurseLevel">Recursion level (used for indenting)</param> |
||
1695 | /// <returns>A formatted string containing the names and values of the source object</returns> |
||
1696 | public static string MessageToString(object message, int recurseLevel) |
||
1697 | { |
||
1698 | if (message == null) |
||
1699 | return String.Empty; |
||
1700 | |||
1701 | StringBuilder result = new StringBuilder(); |
||
1702 | // common/custom types |
||
1703 | if (recurseLevel <= 0) |
||
1704 | { |
||
1705 | result.AppendFormat("Message Type: {0} http://lib.openmetaverse.org/wiki/{0}" + Environment.NewLine, message.GetType().Name); |
||
1706 | } |
||
1707 | else |
||
1708 | { |
||
1709 | string pad = " +--".PadLeft(recurseLevel + 3); |
||
1710 | result.AppendFormat("{0} {1}" + Environment.NewLine, pad, message.GetType().Name); |
||
1711 | } |
||
1712 | |||
1713 | recurseLevel++; |
||
1714 | |||
1715 | foreach (FieldInfo messageField in message.GetType().GetFields()) |
||
1716 | { |
||
1717 | // an abstract message class |
||
1718 | if (messageField.FieldType.IsAbstract) |
||
1719 | { |
||
1720 | result.AppendLine(MessageToString(messageField.GetValue(message), recurseLevel)); |
||
1721 | } |
||
1722 | // a byte array |
||
1723 | else if (messageField.GetValue(message) != null && messageField.GetValue(message).GetType() == typeof(Byte[])) |
||
1724 | { |
||
1725 | result.AppendFormat("{0, 30}:" + Environment.NewLine, messageField.Name); |
||
1726 | |||
1727 | result.AppendFormat("{0}" + Environment.NewLine, |
||
1728 | Utils.BytesToHexString((byte[])messageField.GetValue(message), |
||
1729 | String.Format("{0,30}", ""))); |
||
1730 | } |
||
1731 | |||
1732 | // an array of class objects |
||
1733 | else if (messageField.FieldType.IsArray) |
||
1734 | { |
||
1735 | var messageObjectData = messageField.GetValue(message); |
||
1736 | result.AppendFormat("-- {0} --" + Environment.NewLine, messageField.FieldType.Name); |
||
1737 | foreach (object nestedArrayObject in messageObjectData as Array) |
||
1738 | { |
||
1739 | if (nestedArrayObject == null) |
||
1740 | { |
||
1741 | result.AppendFormat("{0,30}" + Environment.NewLine, "-- null --"); |
||
1742 | continue; |
||
1743 | } |
||
1744 | else |
||
1745 | { |
||
1746 | result.AppendFormat("{0,30}" + Environment.NewLine, "-- " + nestedArrayObject.GetType().Name + " --"); |
||
1747 | } |
||
1748 | foreach (FieldInfo nestedField in nestedArrayObject.GetType().GetFields()) |
||
1749 | { |
||
1750 | if (nestedField.FieldType.IsEnum) |
||
1751 | { |
||
1752 | result.AppendFormat("{0,30}: {1,-10} {2,-29} [{3}]" + Environment.NewLine, |
||
1753 | nestedField.Name, |
||
1754 | Enum.Format(nestedField.GetValue(nestedArrayObject).GetType(), |
||
1755 | nestedField.GetValue(nestedArrayObject), "D"), |
||
1756 | "(" + nestedField.GetValue(nestedArrayObject) + ")", |
||
1757 | nestedField.GetValue(nestedArrayObject).GetType().Name); |
||
1758 | } |
||
1759 | else if (nestedField.FieldType.IsInterface) |
||
1760 | { |
||
1761 | result.AppendLine(MessageToString(nestedField.GetValue(nestedArrayObject), recurseLevel)); |
||
1762 | } |
||
1763 | else |
||
1764 | { |
||
1765 | result.AppendFormat("{0, 30}: {1,-40} [{2}]" + Environment.NewLine, |
||
1766 | nestedField.Name, |
||
1767 | nestedField.GetValue(nestedArrayObject), |
||
1768 | nestedField.FieldType.Name); |
||
1769 | } |
||
1770 | } |
||
1771 | } |
||
1772 | } |
||
1773 | else |
||
1774 | { |
||
1775 | if (messageField.FieldType.IsEnum) |
||
1776 | { |
||
1777 | result.AppendFormat("{0,30}: {1,-2} {2,-37} [{3}]" + Environment.NewLine, |
||
1778 | messageField.Name, |
||
1779 | Enum.Format(messageField.GetValue(message).GetType(), |
||
1780 | messageField.GetValue(message), "D"), |
||
1781 | "(" + messageField.GetValue(message) + ")", |
||
1782 | messageField.FieldType.Name); |
||
1783 | } |
||
1784 | else if (messageField.FieldType.IsInterface) |
||
1785 | { |
||
1786 | result.AppendLine(MessageToString(messageField.GetValue(message), recurseLevel)); |
||
1787 | } |
||
1788 | else |
||
1789 | { |
||
1790 | result.AppendFormat("{0, 30}: {1,-40} [{2}]" + Environment.NewLine, |
||
1791 | messageField.Name, messageField.GetValue(message), messageField.FieldType.Name); |
||
1792 | } |
||
1793 | } |
||
1794 | } |
||
1795 | |||
1796 | return result.ToString(); |
||
1797 | } |
||
1798 | } |
||
1799 | } |