diff --git a/libsecondlife-cs/Avatar.cs b/libsecondlife-cs/Avatar.cs
index e4880499..25f6dba2 100644
--- a/libsecondlife-cs/Avatar.cs
+++ b/libsecondlife-cs/Avatar.cs
@@ -78,21 +78,32 @@ namespace libsecondlife
public delegate void TeleportCallback(string message, TeleportStatus status);
///
- /// Name Conversion for Teleport Status flag/bit
+ /// Current teleport status
///
public enum TeleportStatus
{
+ ///
None,
+ ///
Start,
+ ///
Progress,
+ ///
Failed,
+ ///
Finished
}
+ ///
+ /// Special commands used in Instant Messages
+ ///
public enum InstantMessageDialog
{
+ ///
RequestTeleport = 22,
+ ///
AcceptTeleport = 23,
+ ///
DenyTeleport = 24
}
diff --git a/libsecondlife-cs/ObjectManager.cs b/libsecondlife-cs/ObjectManager.cs
index ee7b13b9..1c17bf61 100644
--- a/libsecondlife-cs/ObjectManager.cs
+++ b/libsecondlife-cs/ObjectManager.cs
@@ -26,6 +26,7 @@
using System;
using System.Collections.Generic;
+using System.Xml.Serialization;
using System.Text;
using libsecondlife.Packets;
@@ -151,19 +152,26 @@ namespace libsecondlife
///
///
///
+ [Serializable]
public enum PCode
{
///
+ [XmlEnum("Prim")]
Prim = 9,
///
+ [XmlEnum("Avatar")]
Avatar = 47,
///
+ [XmlEnum("Grass")]
Grass = 95,
///
+ [XmlEnum("NewTree")]
NewTree = 111,
///
+ [XmlEnum("ParticleSystem")]
ParticleSystem = 143,
///
+ [XmlEnum("Tree")]
Tree = 255
}
@@ -774,7 +782,7 @@ namespace libsecondlife
string name = Helpers.FieldToString(block.NameValue);
// New prim spotted
- PrimObject prim = new PrimObject(Client);
+ PrimObject prim = new PrimObject();
prim.Name = name;
@@ -1035,7 +1043,7 @@ namespace libsecondlife
foreach (ObjectUpdateCompressedPacket.ObjectDataBlock block in update.ObjectData)
{
int i = 0;
- prim = new PrimObject(Client);
+ prim = new PrimObject();
prim.Flags = (ObjectFlags)block.UpdateFlags;
diff --git a/libsecondlife-cs/ParticleSystem.cs b/libsecondlife-cs/ParticleSystem.cs
index 3cb67f13..567c557a 100644
--- a/libsecondlife-cs/ParticleSystem.cs
+++ b/libsecondlife-cs/ParticleSystem.cs
@@ -1,37 +1,45 @@
using System;
using System.Collections.Generic;
-using System.Text;
+using System.Xml.Serialization;
namespace libsecondlife
{
///
///
///
+ [Serializable]
public class ParticleSystem
{
///
///
///
+ [Serializable]
public enum SourcePattern : byte
{
///
+ [XmlEnum("None")]
None = 0,
///
+ [XmlEnum("Drop")]
Drop = 0x01,
///
+ [XmlEnum("Explode")]
Explode = 0x02,
///
+ [XmlEnum("Angle")]
Angle = 0x04,
///
+ [XmlEnum("AngleCone")]
AngleCone = 0x08,
///
+ [XmlEnum("AngleConeEmpty")]
AngleConeEmpty = 0x10
}
///
///
///
- [Flags]
+ [Flags, Serializable]
public enum ParticleFlags : ushort
{
///
@@ -57,48 +65,63 @@ namespace libsecondlife
}
///
+ [XmlAttribute]
public uint PartStartRGBA;
///
+ [XmlAttribute]
public uint PartEndRGBA;
///
+ [XmlAttribute]
+ public float PartMaxAge;
+ ///
+ [XmlAttribute]
+ public float SrcMaxAge;
+ ///
+ [XmlAttribute]
+ public float SrcAngleBegin;
+ ///
+ [XmlAttribute]
+ public float SrcAngleEnd;
+ ///
+ [XmlAttribute]
+ public int SrcBurstPartCount;
+ ///
+ [XmlAttribute]
+ public float SrcBurstRadius;
+ ///
+ [XmlAttribute]
+ public float SrcBurstRate;
+ ///
+ [XmlAttribute]
+ public float SrcBurstSpeedMin;
+ ///
+ [XmlAttribute]
+ public float SrcBurstSpeedMax;
+ /// Unknown
+ [XmlAttribute]
+ public uint Version;
+ /// Unknown
+ [XmlAttribute]
+ public uint StartTick;
+ ///
+ [XmlAttribute]
+ public SourcePattern SrcPattern;
+ /// Various options that describe the behavior of this system
+ [XmlAttribute]
+ public ParticleFlags PartFlags;
+ ///
public LLVector3 PartStartScale = LLVector3.Zero;
///
public LLVector3 PartEndScale = LLVector3.Zero;
///
- public float PartMaxAge;
- ///
- public float SrcMaxAge;
- ///
public LLVector3 SrcAccel = LLVector3.Zero;
///
- public float SrcAngleBegin;
- ///
- public float SrcAngleEnd;
- ///
- public int SrcBurstPartCount;
- ///
- public float SrcBurstRadius;
- ///
- public float SrcBurstRate;
- ///
- public float SrcBurstSpeedMin;
- ///
- public float SrcBurstSpeedMax;
- ///
public LLVector3 SrcOmega = LLVector3.Zero;
///
public LLUUID SrcTargetKey = LLUUID.Zero;
/// Texture that will be applied to the particles
public LLUUID SrcTexture = LLUUID.Zero;
- ///
- public SourcePattern SrcPattern;
- /// Various options that describe the behavior of this system
- public ParticleFlags PartFlags;
- /// Unknown
- public uint Version;
- /// Unknown
- public uint StartTick;
-
+
///
///
///
@@ -116,6 +139,10 @@ namespace libsecondlife
FromBytes(data, pos);
}
+ ///
+ ///
+ ///
+ ///
public byte[] GetBytes()
{
byte[] bytes = new byte[0];
@@ -145,7 +172,7 @@ namespace libsecondlife
SrcMaxAge = (data[i++] + (data[i++] << 8)) / 256.0f;
- //Unknown
+ // TODO: Unknown
i += 2;
SrcAngleBegin = (data[i++] / 100.0f) * (float)Math.PI;
@@ -176,7 +203,7 @@ namespace libsecondlife
PartMaxAge = (data[i++] + (data[i++] << 8)) / 256.0f;
- //Unknown
+ // TODO: Unknown
i += 2;
PartStartRGBA = (uint)(data[i++] + (data[i++] << 8) +
diff --git a/libsecondlife-cs/Prims.cs b/libsecondlife-cs/Prims.cs
index fd2ff007..5aaf3645 100644
--- a/libsecondlife-cs/Prims.cs
+++ b/libsecondlife-cs/Prims.cs
@@ -26,13 +26,14 @@
using System;
using System.Xml;
+using System.Xml.Serialization;
namespace libsecondlife
{
///
/// Primary parameters for primitives such as Physics Enabled or Phantom
///
- [Flags]
+ [Flags, Serializable]
public enum ObjectFlags
{
/// None of the primary flags are enabled
@@ -41,16 +42,41 @@ namespace libsecondlife
Physics = 1 << 0,
///
CreateSelected = 1 << 1,
- ///
+ Unknown1 = 1 << 2,
+ Unknown2 = 1 << 3,
+ Unknown3 = 1 << 4,
+ Unknown4 = 1 << 5,
Script = 1 << 6,
/// Whether this object contains an active touch script
Touch = 1 << 7,
+ Unknown5 = 1 << 8,
/// Whether this object can receive payments
Money = 1 << 9,
/// Whether this object is phantom (no collisions)
Phantom = 1 << 10,
+ Unknown6 = 1 << 11,
+ Unknown7 = 1 << 12,
+ Unknown8 = 1 << 13,
+ Unknown9 = 1 << 14,
+ Unknown10 = 1 << 15,
+ Unknown11 = 1 << 16,
+ Unknown12 = 1 << 17,
+ Unknown13 = 1 << 18,
+ Unknown14 = 1 << 19,
+ Unknown15 = 1 << 20,
+ Unknown16 = 1 << 21,
+ Unknown17 = 1 << 22,
+ Unknown18 = 1 << 23,
+ Unknown19 = 1 << 24,
+ Unknown20 = 1 << 25,
+ Unknown21 = 1 << 26,
+ Unknown22 = 1 << 27,
+ Unknown23 = 1 << 28,
+ Unknown24 = 1 << 29,
/// Whether this object is temporary
- Temp = 1 << 30
+ Temp = 1 << 30,
+ Unknown25 = 1 << 31,
+ Unknown26 = 1 << 32
}
///
@@ -58,132 +84,134 @@ namespace libsecondlife
/// been added after the original ObjectFlags that has all eight bits
/// reserved already
///
+ [Serializable]
public enum ExtraParamType : ushort
{
/// Whether this object has flexible parameters
+ [XmlEnum("Flexible")]
Flexible = 0x10,
/// Whether this object has light parameters
+ [XmlEnum("Light")]
Light = 0x20
}
///
///
///
- public class PrimObject
+ [Serializable]
+ public class PrimObject
{
///
+ [XmlAttribute]
public int PathTwistBegin = 0;
///
+ [XmlAttribute]
public float PathEnd = 0;
///
- public float ProfileBegin = 0;
+ [XmlAttribute]
+ public float ProfileBegin = 0;
///
- public float PathRadiusOffset = 0;
+ [XmlAttribute]
+ public float PathRadiusOffset = 0;
///
- public float PathSkew = 0;
+ [XmlAttribute]
+ public float PathSkew = 0;
///
- public LLVector3 Position = LLVector3.Zero;
- ///
- public ulong RegionHandle;
+ [XmlAttribute]
+ public uint ProfileCurve = 0;
///
- public uint ProfileCurve = 0;
+ [XmlAttribute]
+ public float PathScaleX = 0;
///
- public float PathScaleX = 0;
+ [XmlAttribute]
+ public float PathScaleY = 0;
///
- public float PathScaleY = 0;
+ [XmlAttribute]
+ public uint LocalID = 0;
+ ///
+ [XmlAttribute]
+ public uint ParentID = 0;
+ ///
+ [XmlAttribute]
+ public uint Material = 0;
+ ///
+ [XmlAttribute]
+ public string Name = "";
+ ///
+ [XmlAttribute]
+ public string Description = "";
+ ///
+ [XmlAttribute]
+ public float PathShearX = 0;
+ ///
+ [XmlAttribute]
+ public float PathShearY = 0;
+ ///
+ [XmlAttribute]
+ public float PathTaperX = 0;
+ ///
+ [XmlAttribute]
+ public float PathTaperY = 0;
+ ///
+ [XmlAttribute]
+ public float ProfileEnd = 0;
+ ///
+ [XmlAttribute]
+ public float PathBegin = 0;
+ ///
+ [XmlAttribute]
+ public uint PathCurve = 0;
+ ///
+ [XmlAttribute]
+ public int PathTwist = 0;
+ ///
+ [XmlAttribute]
+ public uint ProfileHollow = 0;
+ ///
+ [XmlAttribute]
+ public float PathRevolutions = 0;
+ ///
+ [XmlAttribute]
+ public uint State;
+ ///
+ [XmlAttribute]
+ public string Text;
+ ///
+ [XmlAttribute]
+ public ObjectManager.PCode PCode = ObjectManager.PCode.Prim;
+ ///
+ [XmlAttribute]
+ public ulong RegionHandle;
///
public LLUUID ID = LLUUID.Zero;
- ///
- public uint LocalID = 0;
- ///
- public uint ParentID = 0;
///
public LLUUID GroupID = LLUUID.Zero;
///
- public uint Material = 0;
- ///
- public string Name = "";
- ///
- public string Description = "";
- ///
- public float PathShearX = 0;
- ///
- public float PathShearY = 0;
- ///
- public float PathTaperX = 0;
- ///
- public float PathTaperY = 0;
- ///
- public float ProfileEnd = 0;
- ///
- public float PathBegin = 0;
- ///
- public uint PathCurve = 0;
+ public LLVector3 Position = LLVector3.Zero;
///
public LLVector3 Scale = LLVector3.Zero;
- ///
- public int PathTwist = 0;
- ///
- public uint ProfileHollow = 0;
- ///
- public float PathRevolutions = 0;
///
public LLQuaternion Rotation = LLQuaternion.Identity;
///
- public uint State;
- ///
- public string Text;
- ///
- public ObjectManager.PCode PCode;
- ///
public ObjectFlags Flags;
///
- public TextureEntry Textures;
+ public TextureEntry Textures = new TextureEntry();
///
- public TextureAnimation TextureAnim;
+ public TextureAnimation TextureAnim = new TextureAnimation();
///
- public PrimFlexibleData Flexible;
+ public PrimFlexibleData Flexible = new PrimFlexibleData();
///
- public PrimLightData Light;
+ public PrimLightData Light = new PrimLightData();
///
- public ParticleSystem ParticleSys;
-
- private SecondLife Client;
+ public ParticleSystem ParticleSys = new ParticleSystem();
///
- ///
+ /// Default constructor
///
- public PrimObject(SecondLife client)
+ public PrimObject()
{
- Client = client;
- PCode = ObjectManager.PCode.Prim;
- Flexible = new PrimFlexibleData();
- Light = new PrimLightData();
- ParticleSys = new ParticleSystem();
- Textures = new TextureEntry();
- TextureAnim = new TextureAnimation();
- Flexible = new PrimFlexibleData();
- Light = new PrimLightData();
- ParticleSys = new ParticleSystem();
}
- ///
- ///
- ///
- ///
- public PrimObject(SecondLife client, LLUUID texture)
- {
- Client = client;
- PCode = ObjectManager.PCode.Prim;
- Textures = new TextureEntry();
- Textures.DefaultTexture.TextureID = texture;
- }
-
- public GridRegion GridRegion
- {
- get { return Client.Grid.RegionsByHandle[RegionHandle]; }
- }
-
///
///
///
@@ -470,11 +498,24 @@ namespace libsecondlife
return output;
}
+
+ public void ToXml(XmlWriter xmlWriter)
+ {
+ XmlSerializer serializer = new XmlSerializer(typeof(PrimObject));
+ serializer.Serialize(xmlWriter, this);
+ }
+
+ public static PrimObject FromXml(XmlReader xmlReader)
+ {
+ XmlSerializer serializer = new XmlSerializer(typeof(PrimObject));
+ return (PrimObject)serializer.Deserialize(xmlReader);
+ }
}
///
///
///
+ [Serializable]
public class PrimFlexibleData
{
///
@@ -546,6 +587,7 @@ namespace libsecondlife
///
///
///
+ [Serializable]
public class PrimLightData
{
///
diff --git a/libsecondlife-cs/SerializableDictionary.cs b/libsecondlife-cs/SerializableDictionary.cs
new file mode 100644
index 00000000..07371eeb
--- /dev/null
+++ b/libsecondlife-cs/SerializableDictionary.cs
@@ -0,0 +1,101 @@
+/*
+ * Adapted from code by Paul Welter at
+ * http://weblogs.asp.net/pwelter34/archive/2006/05/03/444961.aspx
+ *
+ * - 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 Second Life Reverse Engineering Team 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.Text;
+using System.Xml.Serialization;
+
+///
+///
+///
+///
+///
+[XmlRoot("dictionary")]
+public class SerializableDictionary : Dictionary, IXmlSerializable
+{
+ #region IXmlSerializable Members
+
+ public System.Xml.Schema.XmlSchema GetSchema()
+ {
+ return null;
+ }
+
+ public void ReadXml(System.Xml.XmlReader reader)
+ {
+ XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));
+ XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));
+
+ bool wasEmpty = reader.IsEmptyElement;
+ reader.Read();
+
+ if (wasEmpty)
+ return;
+
+ while (reader.NodeType != System.Xml.XmlNodeType.EndElement)
+ {
+ reader.ReadStartElement("item");
+
+ reader.ReadStartElement("key");
+ TKey key = (TKey)keySerializer.Deserialize(reader);
+ reader.ReadEndElement();
+
+ reader.ReadStartElement("value");
+ TValue value = (TValue)valueSerializer.Deserialize(reader);
+ reader.ReadEndElement();
+
+ this.Add(key, value);
+
+ reader.ReadEndElement();
+ reader.MoveToContent();
+ }
+
+ reader.ReadEndElement();
+ }
+
+ public void WriteXml(System.Xml.XmlWriter writer)
+ {
+ XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));
+ XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));
+
+ foreach (TKey key in this.Keys)
+ {
+ writer.WriteStartElement("item");
+
+ writer.WriteStartElement("key");
+ keySerializer.Serialize(writer, key);
+ writer.WriteEndElement();
+
+ writer.WriteStartElement("value");
+ TValue value = this[key];
+ valueSerializer.Serialize(writer, value);
+ writer.WriteEndElement();
+ writer.WriteEndElement();
+ }
+ }
+
+ #endregion
+}
diff --git a/libsecondlife-cs/Textures.cs b/libsecondlife-cs/Textures.cs
index 1a62f9ee..9982a836 100644
--- a/libsecondlife-cs/Textures.cs
+++ b/libsecondlife-cs/Textures.cs
@@ -26,7 +26,7 @@
using System;
using System.Collections.Generic;
-using System.Text;
+using System.Xml.Serialization;
using System.IO;
namespace libsecondlife
@@ -36,23 +36,59 @@ namespace libsecondlife
///
public enum Bumpiness
{
+ ///
+ [XmlEnum("None")]
None = 0,
+ ///
+ [XmlEnum("Brightness")]
Brightness = 1,
+ ///
+ [XmlEnum("Darkness")]
Darkness = 2,
+ ///
+ [XmlEnum("Woodgrain")]
Woodgrain = 3,
+ ///
+ [XmlEnum("Bark")]
Bark = 4,
+ ///
+ [XmlEnum("Bricks")]
Bricks = 5,
+ ///
+ [XmlEnum("Checker")]
Checker = 6,
+ ///
+ [XmlEnum("Concrete")]
Concrete = 7,
+ ///
+ [XmlEnum("Crustytile")]
Crustytile = 8,
+ ///
+ [XmlEnum("Cutstone")]
Cutstone = 9,
+ ///
+ [XmlEnum("Discs")]
Discs = 10,
+ ///
+ [XmlEnum("Gravel")]
Gravel = 11,
+ ///
+ [XmlEnum("Petridish")]
Petridish = 12,
+ ///
+ [XmlEnum("Siding")]
Siding = 13,
+ ///
+ [XmlEnum("Stonetile")]
Stonetile = 14,
+ ///
+ [XmlEnum("Stucco")]
Stucco = 15,
+ ///
+ [XmlEnum("Suction")]
Suction = 16,
+ ///
+ [XmlEnum("Weave")]
Weave = 17
}
@@ -61,9 +97,17 @@ namespace libsecondlife
///
public enum Shininess
{
+ ///
+ [XmlEnum("None")]
None = 0,
+ ///
+ [XmlEnum("Low")]
Low = 0x40,
+ ///
+ [XmlEnum("Medium")]
Medium = 0x80,
+ ///
+ [XmlEnum("High")]
High = 0xC0
}
@@ -72,33 +116,35 @@ namespace libsecondlife
///
public enum Mapping
{
+ ///
+ [XmlEnum("Default")]
Default = 0,
+ ///
+ [XmlEnum("Planar")]
Planar = 2
}
///
///
///
+ [Serializable]
public class TextureEntry
{
///
- public TextureEntryFace DefaultTexture;
+ public TextureEntryFace DefaultTexture = null;
///
- public Dictionary FaceTextures;
+ public SerializableDictionary FaceTextures =
+ new SerializableDictionary();
///
///
///
public TextureEntry()
{
- FaceTextures = new Dictionary();
- //DefaultTexture = new TextureEntryFace(null);
- DefaultTexture = null;
}
public TextureEntry(LLUUID textureID)
{
- FaceTextures = new Dictionary();
DefaultTexture = new TextureEntryFace(null);
DefaultTexture.TextureID = textureID;
}
@@ -367,7 +413,7 @@ namespace libsecondlife
{
short value = (short)(byteArray[pos] | (byteArray[pos + 1] << 8));
float QV = (float)value;
- float QF = upper / 32767.0F;
+ float QF = upper / 32767.0f;
return (float)(QV * QF);
}
@@ -379,37 +425,37 @@ namespace libsecondlife
private short RepeatShort(float value)
{
- return QuantizeSigned(value - 1.0F, 101.0F);
+ return QuantizeSigned(value - 1.0f, 101.0f);
}
private short OffsetShort(float value)
{
- return QuantizeSigned(value, 1.0F);
+ return QuantizeSigned(value, 1.0f);
}
private short RotationShort(float value)
{
- return QuantizeSigned(value, 359.995F);
+ return QuantizeSigned(value, 359.995f);
}
private float RepeatFloat(byte[] data, int pos)
{
- return DequantizeSigned(data, pos, 101.0F) + 1.0F;
+ return DequantizeSigned(data, pos, 101.0f) + 1.0f;
}
private float OffsetFloat(byte[] data, int pos)
{
- return DequantizeSigned(data, pos, 1.0F);
+ return DequantizeSigned(data, pos, 1.0f);
}
private float RotationFloat(byte[] data, int pos)
{
- return DequantizeSigned(data, pos, 359.995F);
+ return DequantizeSigned(data, pos, 359.995f);
}
private void FromBytes(byte[] data, int pos, int length)
{
- FaceTextures = new Dictionary();
+ FaceTextures = new SerializableDictionary();
DefaultTexture = new TextureEntryFace(null);
if (length <= 0)
@@ -542,6 +588,7 @@ namespace libsecondlife
///
///
///
+ [Serializable]
public class TextureEntryFace
{
[Flags]
@@ -560,6 +607,13 @@ namespace libsecondlife
All = 0xFFFFFFFF
}
+ ///
+ ///
+ ///
+ public TextureEntryFace()
+ {
+ }
+
///
///
///
@@ -757,10 +811,10 @@ namespace libsecondlife
private byte _Flags2;
}
-
///
///
///
+ [Serializable]
public class TextureAnimation
{
///
@@ -830,4 +884,138 @@ namespace libsecondlife
Rate = BitConverter.ToSingle(data, i + 8);
}
}
+
+ ///
+ /// A serializable dictionary of TextureEntryFace objects, indexed by
+ /// the prim face they are mapped to
+ ///
+ [Serializable]
+ public class Faces : System.Collections.DictionaryBase, System.Xml.Serialization.IXmlSerializable
+ {
+ private const string NS = "http://www.libsecondlife.org/";
+
+ ///
+ /// Default constructor
+ ///
+ public Faces()
+ {
+ }
+
+ public virtual TextureEntryFace this[uint key]
+ {
+ get
+ {
+ return (TextureEntryFace)this.Dictionary[key];
+ }
+ set
+ {
+ this.Dictionary[key] = value;
+ }
+ }
+
+ public virtual void Add(uint key, TextureEntryFace value)
+ {
+ this.Dictionary.Add(key, value);
+ }
+
+ public virtual bool Contains(uint key)
+ {
+ return this.Dictionary.Contains(key);
+ }
+
+ public virtual bool ContainsKey(uint key)
+ {
+ return this.Dictionary.Contains(key);
+ }
+
+ public virtual bool ContainsValue(TextureEntryFace value)
+ {
+ foreach (TextureEntryFace item in this.Dictionary.Values)
+ {
+ if (item == value)
+ return true;
+ }
+ return false;
+ }
+
+ public virtual void Remove(uint key)
+ {
+ this.Dictionary.Remove(key);
+ }
+
+ public virtual System.Collections.ICollection Keys
+ {
+ get
+ {
+ return this.Dictionary.Keys;
+ }
+ }
+
+ public virtual System.Collections.ICollection Values
+ {
+ get
+ {
+ return this.Dictionary.Values;
+ }
+ }
+
+ void System.Xml.Serialization.IXmlSerializable.WriteXml(System.Xml.XmlWriter w)
+ {
+ System.Xml.Serialization.XmlSerializer keySer =
+ new System.Xml.Serialization.XmlSerializer(typeof(uint));
+ System.Xml.Serialization.XmlSerializer valueSer =
+ new System.Xml.Serialization.XmlSerializer(typeof(TextureEntryFace));
+ w.WriteStartElement("dictionary", NS);
+ foreach (object key in Dictionary.Keys)
+ {
+ w.WriteStartElement("item", NS);
+
+ w.WriteStartElement("key", NS);
+ keySer.Serialize(w, key);
+ w.WriteEndElement();
+
+ w.WriteStartElement("value", NS);
+ object value = Dictionary[key];
+ valueSer.Serialize(w, value);
+ w.WriteEndElement();
+
+ w.WriteEndElement();
+ }
+ w.WriteEndElement();
+ }
+
+ void System.Xml.Serialization.IXmlSerializable.ReadXml(System.Xml.XmlReader r)
+ {
+ System.Xml.Serialization.XmlSerializer keySer =
+ new System.Xml.Serialization.XmlSerializer(typeof(string));
+ System.Xml.Serialization.XmlSerializer valueSer =
+ new System.Xml.Serialization.XmlSerializer(typeof(TextureEntryFace));
+
+ r.Read();
+ r.ReadStartElement("dictionary", NS);
+ while (r.NodeType != System.Xml.XmlNodeType.EndElement)
+ {
+ r.ReadStartElement("item", NS);
+
+ r.ReadStartElement("key", NS);
+ object key = keySer.Deserialize(r);
+ r.ReadEndElement();
+
+ r.ReadStartElement("value", NS);
+ object value = valueSer.Deserialize(r);
+ r.ReadEndElement();
+
+ Dictionary.Add(key, value);
+
+ r.ReadEndElement();
+ r.MoveToContent();
+ }
+ r.ReadEndElement();
+ }
+
+ System.Xml.Schema.XmlSchema System.Xml.Serialization.IXmlSerializable.GetSchema()
+ {
+ return null;
+ }
+ }
}
diff --git a/libsecondlife-cs/Types.cs b/libsecondlife-cs/Types.cs
index 8b6de1b2..ba4ffeb5 100644
--- a/libsecondlife-cs/Types.cs
+++ b/libsecondlife-cs/Types.cs
@@ -26,6 +26,7 @@
using System;
using System.Net;
+using System.Xml.Serialization;
namespace libsecondlife
{
@@ -33,6 +34,7 @@ namespace libsecondlife
/// A 128-bit Universally Unique Identifier, used throughout the Second
/// Life networking protocol
///
+ [XmlRoot("uuid")]
public class LLUUID
{
/// Get a byte array of the 16 raw bytes making up the UUID
@@ -265,6 +267,7 @@ namespace libsecondlife
///
///
///
+ [XmlRoot("vector3")]
public class LLVector3
{
///
@@ -451,6 +454,7 @@ namespace libsecondlife
///
///
///
+ [XmlRoot("vector3d")]
public class LLVector3d
{
///
@@ -538,6 +542,7 @@ namespace libsecondlife
///
///
///
+ [XmlRoot("vector4")]
public class LLVector4
{
///
@@ -618,6 +623,7 @@ namespace libsecondlife
///
///
///
+ [XmlRoot("quaternion")]
public class LLQuaternion
{
///
diff --git a/libsecondlife-cs/examples/TestClient/Commands/ExportCommand.cs b/libsecondlife-cs/examples/TestClient/Commands/ExportCommand.cs
new file mode 100644
index 00000000..fb0d4e06
--- /dev/null
+++ b/libsecondlife-cs/examples/TestClient/Commands/ExportCommand.cs
@@ -0,0 +1,63 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Xml;
+using libsecondlife;
+using libsecondlife.Packets;
+
+namespace libsecondlife.TestClient
+{
+ public class ExportCommand : Command
+ {
+ public ExportCommand()
+ {
+ Name = "export";
+ Description = "Exports an object to an xml file. Usage: export uuid outputfile.xml";
+ }
+
+ public override string Execute(SecondLife Client, string[] args, LLUUID fromAgentID)
+ {
+ if (args.Length != 2)
+ return "Usage: export uuid outputfile.xml";
+
+ LLUUID id;
+ string file = args[1];
+
+ try
+ {
+ id = new LLUUID(args[0]);
+ }
+ catch (Exception)
+ {
+ return "Usage: export uuid outputfile.xml";
+ }
+
+ foreach (PrimObject prim in TestClient.Prims.Values)
+ {
+ if (prim.ID == id)
+ {
+ try
+ {
+ XmlWriter writer = XmlWriter.Create(file);
+ prim.ToXml(writer);
+ writer.Close();
+ }
+ catch (Exception e)
+ {
+ string ret = "Failed to write to " + file + ":" + e.ToString();
+ if (ret.Length > 1000)
+ {
+ ret = ret.Remove(1000);
+ }
+ return ret;
+ }
+
+ return "";
+ }
+ }
+
+ return "Couldn't find UUID " + id.ToString() + " in the " + TestClient.Prims.Count +
+ "objects currently indexed";
+ }
+ }
+}
diff --git a/libsecondlife-cs/examples/TestClient/TestClient.cs b/libsecondlife-cs/examples/TestClient/TestClient.cs
index 5e2435e6..c88fe3df 100644
--- a/libsecondlife-cs/examples/TestClient/TestClient.cs
+++ b/libsecondlife-cs/examples/TestClient/TestClient.cs
@@ -186,33 +186,49 @@ Begin:
if (Commands.ContainsKey(firstToken))
{
- foreach (SecondLife client in Clients.Values)
+ if (firstToken == "login")
{
- if (client.Network.Connected)
+ // Special login case: Only call it once, and allow it with
+ // no logged in avatars
+ string[] args = new string[tokens.Length - 1];
+ Array.Copy(tokens, 1, args, 0, args.Length);
+ string response = Commands["login"].Execute(null, args, null);
+
+ if (response.Length > 0)
{
- string[] args = new string[tokens.Length - 1];
- Array.Copy(tokens, 1, args, 0, args.Length);
- string response = Commands[firstToken].Execute(client, args, fromAgentID);
-
- if (response.Length > 0)
- {
- if (fromAgentID != null && client.Network.Connected)
- client.Self.InstantMessage(fromAgentID, response, imSessionID);
- Console.WriteLine(response);
- }
-
- if (firstToken == "login")
- {
- // Special login case: Only call it once
- break;
- }
+ Console.WriteLine(response);
}
-
- if (avatars != Clients.Count)
+ }
+ else if (firstToken == "quit")
+ {
+ // Special quit case: This allows us to quit even when there
+ // are zero avatars logged in
+ Commands["quit"].Execute(null, null, null);
+ }
+ else
+ {
+ foreach (SecondLife client in Clients.Values)
{
- // The dictionary size changed, start over since the
- // foreach is shot
- goto Begin;
+ if (client.Network.Connected)
+ {
+ string[] args = new string[tokens.Length - 1];
+ Array.Copy(tokens, 1, args, 0, args.Length);
+ string response = Commands[firstToken].Execute(client, args, fromAgentID);
+
+ if (response.Length > 0)
+ {
+ if (fromAgentID != null && client.Network.Connected)
+ client.Self.InstantMessage(fromAgentID, response, imSessionID);
+ Console.WriteLine(response);
+ }
+ }
+
+ if (avatars != Clients.Count)
+ {
+ // The dictionary size changed, start over since the
+ // foreach is shot
+ goto Begin;
+ }
}
}
}
diff --git a/libsecondlife-cs/examples/TestClient/TestClient.csproj b/libsecondlife-cs/examples/TestClient/TestClient.csproj
index fcefb433..e52af961 100644
--- a/libsecondlife-cs/examples/TestClient/TestClient.csproj
+++ b/libsecondlife-cs/examples/TestClient/TestClient.csproj
@@ -36,6 +36,7 @@
+
diff --git a/libsecondlife-cs/libsecondlife.csproj b/libsecondlife-cs/libsecondlife.csproj
index 79274c7e..0064e8e6 100644
--- a/libsecondlife-cs/libsecondlife.csproj
+++ b/libsecondlife-cs/libsecondlife.csproj
@@ -157,6 +157,7 @@
Code
+
Code