libsecondlife:

* Added a SerializableDictionary class, implements a generic Dictionary<,> that can be serialized to xml
* Added all possible values for ObjectFlags to allow serializing
* Added a few initial xml serialization attributes to prim-related classes and structures
* Created ToXml() and FromXml() functions for PrimObject
TestClient:
* ExportCommand exports a single prim to an xml file
* quit and login commands now work when no avatars are logged in

git-svn-id: http://libopenmetaverse.googlecode.com/svn/trunk@662 52acb1d6-8a22-11de-b505-999d5b087335
This commit is contained in:
John Hurliman
2006-11-30 03:35:36 +00:00
parent 70b10f6cad
commit ed6b88a017
11 changed files with 621 additions and 157 deletions

View File

@@ -78,21 +78,32 @@ namespace libsecondlife
public delegate void TeleportCallback(string message, TeleportStatus status);
/// <summary>
/// Name Conversion for Teleport Status flag/bit
/// Current teleport status
/// </summary>
public enum TeleportStatus
{
/// <summary></summary>
None,
/// <summary></summary>
Start,
/// <summary></summary>
Progress,
/// <summary></summary>
Failed,
/// <summary></summary>
Finished
}
/// <summary>
/// Special commands used in Instant Messages
/// </summary>
public enum InstantMessageDialog
{
/// <summary></summary>
RequestTeleport = 22,
/// <summary></summary>
AcceptTeleport = 23,
/// <summary></summary>
DenyTeleport = 24
}

View File

@@ -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
/// <summary>
///
/// </summary>
[Serializable]
public enum PCode
{
/// <summary></summary>
[XmlEnum("Prim")]
Prim = 9,
/// <summary></summary>
[XmlEnum("Avatar")]
Avatar = 47,
/// <summary></summary>
[XmlEnum("Grass")]
Grass = 95,
/// <summary></summary>
[XmlEnum("NewTree")]
NewTree = 111,
/// <summary></summary>
[XmlEnum("ParticleSystem")]
ParticleSystem = 143,
/// <summary></summary>
[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;

View File

@@ -1,37 +1,45 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;
namespace libsecondlife
{
/// <summary>
///
/// </summary>
[Serializable]
public class ParticleSystem
{
/// <summary>
///
/// </summary>
[Serializable]
public enum SourcePattern : byte
{
/// <summary></summary>
[XmlEnum("None")]
None = 0,
/// <summary></summary>
[XmlEnum("Drop")]
Drop = 0x01,
/// <summary></summary>
[XmlEnum("Explode")]
Explode = 0x02,
/// <summary></summary>
[XmlEnum("Angle")]
Angle = 0x04,
/// <summary></summary>
[XmlEnum("AngleCone")]
AngleCone = 0x08,
/// <summary></summary>
[XmlEnum("AngleConeEmpty")]
AngleConeEmpty = 0x10
}
/// <summary>
///
/// </summary>
[Flags]
[Flags, Serializable]
public enum ParticleFlags : ushort
{
/// <summary></summary>
@@ -57,48 +65,63 @@ namespace libsecondlife
}
/// <summary></summary>
[XmlAttribute]
public uint PartStartRGBA;
/// <summary></summary>
[XmlAttribute]
public uint PartEndRGBA;
/// <summary></summary>
[XmlAttribute]
public float PartMaxAge;
/// <summary></summary>
[XmlAttribute]
public float SrcMaxAge;
/// <summary></summary>
[XmlAttribute]
public float SrcAngleBegin;
/// <summary></summary>
[XmlAttribute]
public float SrcAngleEnd;
/// <summary></summary>
[XmlAttribute]
public int SrcBurstPartCount;
/// <summary></summary>
[XmlAttribute]
public float SrcBurstRadius;
/// <summary></summary>
[XmlAttribute]
public float SrcBurstRate;
/// <summary></summary>
[XmlAttribute]
public float SrcBurstSpeedMin;
/// <summary></summary>
[XmlAttribute]
public float SrcBurstSpeedMax;
/// <summary>Unknown</summary>
[XmlAttribute]
public uint Version;
/// <summary>Unknown</summary>
[XmlAttribute]
public uint StartTick;
/// <summary></summary>
[XmlAttribute]
public SourcePattern SrcPattern;
/// <summary>Various options that describe the behavior of this system</summary>
[XmlAttribute]
public ParticleFlags PartFlags;
/// <summary></summary>
public LLVector3 PartStartScale = LLVector3.Zero;
/// <summary></summary>
public LLVector3 PartEndScale = LLVector3.Zero;
/// <summary></summary>
public float PartMaxAge;
/// <summary></summary>
public float SrcMaxAge;
/// <summary></summary>
public LLVector3 SrcAccel = LLVector3.Zero;
/// <summary></summary>
public float SrcAngleBegin;
/// <summary></summary>
public float SrcAngleEnd;
/// <summary></summary>
public int SrcBurstPartCount;
/// <summary></summary>
public float SrcBurstRadius;
/// <summary></summary>
public float SrcBurstRate;
/// <summary></summary>
public float SrcBurstSpeedMin;
/// <summary></summary>
public float SrcBurstSpeedMax;
/// <summary></summary>
public LLVector3 SrcOmega = LLVector3.Zero;
/// <summary></summary>
public LLUUID SrcTargetKey = LLUUID.Zero;
/// <summary>Texture that will be applied to the particles</summary>
public LLUUID SrcTexture = LLUUID.Zero;
/// <summary></summary>
public SourcePattern SrcPattern;
/// <summary>Various options that describe the behavior of this system</summary>
public ParticleFlags PartFlags;
/// <summary>Unknown</summary>
public uint Version;
/// <summary>Unknown</summary>
public uint StartTick;
/// <summary>
///
/// </summary>
@@ -116,6 +139,10 @@ namespace libsecondlife
FromBytes(data, pos);
}
/// <summary>
///
/// </summary>
/// <returns></returns>
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) +

View File

@@ -26,13 +26,14 @@
using System;
using System.Xml;
using System.Xml.Serialization;
namespace libsecondlife
{
/// <summary>
/// Primary parameters for primitives such as Physics Enabled or Phantom
/// </summary>
[Flags]
[Flags, Serializable]
public enum ObjectFlags
{
/// <summary>None of the primary flags are enabled</summary>
@@ -41,16 +42,41 @@ namespace libsecondlife
Physics = 1 << 0,
/// <summary></summary>
CreateSelected = 1 << 1,
/// <summary></summary>
Unknown1 = 1 << 2,
Unknown2 = 1 << 3,
Unknown3 = 1 << 4,
Unknown4 = 1 << 5,
Script = 1 << 6,
/// <summary>Whether this object contains an active touch script</summary>
Touch = 1 << 7,
Unknown5 = 1 << 8,
/// <summary>Whether this object can receive payments</summary>
Money = 1 << 9,
/// <summary>Whether this object is phantom (no collisions)</summary>
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,
/// <summary>Whether this object is temporary</summary>
Temp = 1 << 30
Temp = 1 << 30,
Unknown25 = 1 << 31,
Unknown26 = 1 << 32
}
/// <summary>
@@ -58,132 +84,134 @@ namespace libsecondlife
/// been added after the original ObjectFlags that has all eight bits
/// reserved already
/// </summary>
[Serializable]
public enum ExtraParamType : ushort
{
/// <summary>Whether this object has flexible parameters</summary>
[XmlEnum("Flexible")]
Flexible = 0x10,
/// <summary>Whether this object has light parameters</summary>
[XmlEnum("Light")]
Light = 0x20
}
/// <summary>
///
/// </summary>
public class PrimObject
[Serializable]
public class PrimObject
{
/// <summary></summary>
[XmlAttribute]
public int PathTwistBegin = 0;
/// <summary></summary>
[XmlAttribute]
public float PathEnd = 0;
/// <summary></summary>
public float ProfileBegin = 0;
[XmlAttribute]
public float ProfileBegin = 0;
/// <summary></summary>
public float PathRadiusOffset = 0;
[XmlAttribute]
public float PathRadiusOffset = 0;
/// <summary></summary>
public float PathSkew = 0;
[XmlAttribute]
public float PathSkew = 0;
/// <summary></summary>
public LLVector3 Position = LLVector3.Zero;
/// <summary> </summary>
public ulong RegionHandle;
[XmlAttribute]
public uint ProfileCurve = 0;
/// <summary></summary>
public uint ProfileCurve = 0;
[XmlAttribute]
public float PathScaleX = 0;
/// <summary></summary>
public float PathScaleX = 0;
[XmlAttribute]
public float PathScaleY = 0;
/// <summary></summary>
public float PathScaleY = 0;
[XmlAttribute]
public uint LocalID = 0;
/// <summary></summary>
[XmlAttribute]
public uint ParentID = 0;
/// <summary></summary>
[XmlAttribute]
public uint Material = 0;
/// <summary></summary>
[XmlAttribute]
public string Name = "";
/// <summary></summary>
[XmlAttribute]
public string Description = "";
/// <summary></summary>
[XmlAttribute]
public float PathShearX = 0;
/// <summary></summary>
[XmlAttribute]
public float PathShearY = 0;
/// <summary></summary>
[XmlAttribute]
public float PathTaperX = 0;
/// <summary></summary>
[XmlAttribute]
public float PathTaperY = 0;
/// <summary></summary>
[XmlAttribute]
public float ProfileEnd = 0;
/// <summary></summary>
[XmlAttribute]
public float PathBegin = 0;
/// <summary></summary>
[XmlAttribute]
public uint PathCurve = 0;
/// <summary></summary>
[XmlAttribute]
public int PathTwist = 0;
/// <summary></summary>
[XmlAttribute]
public uint ProfileHollow = 0;
/// <summary></summary>
[XmlAttribute]
public float PathRevolutions = 0;
/// <summary></summary>
[XmlAttribute]
public uint State;
/// <summary></summary>
[XmlAttribute]
public string Text;
/// <summary></summary>
[XmlAttribute]
public ObjectManager.PCode PCode = ObjectManager.PCode.Prim;
/// <summary></summary>
[XmlAttribute]
public ulong RegionHandle;
/// <summary></summary>
public LLUUID ID = LLUUID.Zero;
/// <summary></summary>
public uint LocalID = 0;
/// <summary></summary>
public uint ParentID = 0;
/// <summary></summary>
public LLUUID GroupID = LLUUID.Zero;
/// <summary></summary>
public uint Material = 0;
/// <summary></summary>
public string Name = "";
/// <summary></summary>
public string Description = "";
/// <summary></summary>
public float PathShearX = 0;
/// <summary></summary>
public float PathShearY = 0;
/// <summary></summary>
public float PathTaperX = 0;
/// <summary></summary>
public float PathTaperY = 0;
/// <summary></summary>
public float ProfileEnd = 0;
/// <summary></summary>
public float PathBegin = 0;
/// <summary></summary>
public uint PathCurve = 0;
public LLVector3 Position = LLVector3.Zero;
/// <summary></summary>
public LLVector3 Scale = LLVector3.Zero;
/// <summary></summary>
public int PathTwist = 0;
/// <summary></summary>
public uint ProfileHollow = 0;
/// <summary></summary>
public float PathRevolutions = 0;
/// <summary></summary>
public LLQuaternion Rotation = LLQuaternion.Identity;
/// <summary></summary>
public uint State;
/// <summary></summary>
public string Text;
/// <summary></summary>
public ObjectManager.PCode PCode;
/// <summary></summary>
public ObjectFlags Flags;
/// <summary></summary>
public TextureEntry Textures;
public TextureEntry Textures = new TextureEntry();
/// <summary></summary>
public TextureAnimation TextureAnim;
public TextureAnimation TextureAnim = new TextureAnimation();
/// <summary></summary>
public PrimFlexibleData Flexible;
public PrimFlexibleData Flexible = new PrimFlexibleData();
/// <summary></summary>
public PrimLightData Light;
public PrimLightData Light = new PrimLightData();
/// <summary></summary>
public ParticleSystem ParticleSys;
private SecondLife Client;
public ParticleSystem ParticleSys = new ParticleSystem();
/// <summary>
///
/// Default constructor
/// </summary>
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();
}
/// <summary>
///
/// </summary>
/// <param name="texture"></param>
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]; }
}
/// <summary>
///
/// </summary>
@@ -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);
}
}
/// <summary>
///
/// </summary>
[Serializable]
public class PrimFlexibleData
{
/// <summary></summary>
@@ -546,6 +587,7 @@ namespace libsecondlife
/// <summary>
///
/// </summary>
[Serializable]
public class PrimLightData
{
/// <summary></summary>

View File

@@ -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;
/// <summary>
///
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
[XmlRoot("dictionary")]
public class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, 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
}

View File

@@ -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
/// </summary>
public enum Bumpiness
{
/// <summary></summary>
[XmlEnum("None")]
None = 0,
/// <summary></summary>
[XmlEnum("Brightness")]
Brightness = 1,
/// <summary></summary>
[XmlEnum("Darkness")]
Darkness = 2,
/// <summary></summary>
[XmlEnum("Woodgrain")]
Woodgrain = 3,
/// <summary></summary>
[XmlEnum("Bark")]
Bark = 4,
/// <summary></summary>
[XmlEnum("Bricks")]
Bricks = 5,
/// <summary></summary>
[XmlEnum("Checker")]
Checker = 6,
/// <summary></summary>
[XmlEnum("Concrete")]
Concrete = 7,
/// <summary></summary>
[XmlEnum("Crustytile")]
Crustytile = 8,
/// <summary></summary>
[XmlEnum("Cutstone")]
Cutstone = 9,
/// <summary></summary>
[XmlEnum("Discs")]
Discs = 10,
/// <summary></summary>
[XmlEnum("Gravel")]
Gravel = 11,
/// <summary></summary>
[XmlEnum("Petridish")]
Petridish = 12,
/// <summary></summary>
[XmlEnum("Siding")]
Siding = 13,
/// <summary></summary>
[XmlEnum("Stonetile")]
Stonetile = 14,
/// <summary></summary>
[XmlEnum("Stucco")]
Stucco = 15,
/// <summary></summary>
[XmlEnum("Suction")]
Suction = 16,
/// <summary></summary>
[XmlEnum("Weave")]
Weave = 17
}
@@ -61,9 +97,17 @@ namespace libsecondlife
/// </summary>
public enum Shininess
{
/// <summary></summary>
[XmlEnum("None")]
None = 0,
/// <summary></summary>
[XmlEnum("Low")]
Low = 0x40,
/// <summary></summary>
[XmlEnum("Medium")]
Medium = 0x80,
/// <summary></summary>
[XmlEnum("High")]
High = 0xC0
}
@@ -72,33 +116,35 @@ namespace libsecondlife
/// </summary>
public enum Mapping
{
/// <summary></summary>
[XmlEnum("Default")]
Default = 0,
/// <summary></summary>
[XmlEnum("Planar")]
Planar = 2
}
/// <summary>
///
/// </summary>
[Serializable]
public class TextureEntry
{
/// <summary></summary>
public TextureEntryFace DefaultTexture;
public TextureEntryFace DefaultTexture = null;
/// <summary></summary>
public Dictionary<uint, TextureEntryFace> FaceTextures;
public SerializableDictionary<uint, TextureEntryFace> FaceTextures =
new SerializableDictionary<uint,TextureEntryFace>();
/// <summary>
///
/// </summary>
public TextureEntry()
{
FaceTextures = new Dictionary<uint, TextureEntryFace>();
//DefaultTexture = new TextureEntryFace(null);
DefaultTexture = null;
}
public TextureEntry(LLUUID textureID)
{
FaceTextures = new Dictionary<uint, TextureEntryFace>();
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<uint, TextureEntryFace>();
FaceTextures = new SerializableDictionary<uint, TextureEntryFace>();
DefaultTexture = new TextureEntryFace(null);
if (length <= 0)
@@ -542,6 +588,7 @@ namespace libsecondlife
/// <summary>
///
/// </summary>
[Serializable]
public class TextureEntryFace
{
[Flags]
@@ -560,6 +607,13 @@ namespace libsecondlife
All = 0xFFFFFFFF
}
/// <summary>
///
/// </summary>
public TextureEntryFace()
{
}
/// <summary>
///
/// </summary>
@@ -757,10 +811,10 @@ namespace libsecondlife
private byte _Flags2;
}
/// <summary>
///
/// </summary>
[Serializable]
public class TextureAnimation
{
/// <summary></summary>
@@ -830,4 +884,138 @@ namespace libsecondlife
Rate = BitConverter.ToSingle(data, i + 8);
}
}
/// <summary>
/// A serializable dictionary of TextureEntryFace objects, indexed by
/// the prim face they are mapped to
/// </summary>
[Serializable]
public class Faces : System.Collections.DictionaryBase, System.Xml.Serialization.IXmlSerializable
{
private const string NS = "http://www.libsecondlife.org/";
/// <summary>
/// Default constructor
/// </summary>
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;
}
}
}

View File

@@ -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
/// </summary>
[XmlRoot("uuid")]
public class LLUUID
{
/// <summary>Get a byte array of the 16 raw bytes making up the UUID</summary>
@@ -265,6 +267,7 @@ namespace libsecondlife
/// <summary>
///
/// </summary>
[XmlRoot("vector3")]
public class LLVector3
{
/// <summary></summary>
@@ -451,6 +454,7 @@ namespace libsecondlife
/// <summary>
///
/// </summary>
[XmlRoot("vector3d")]
public class LLVector3d
{
/// <summary></summary>
@@ -538,6 +542,7 @@ namespace libsecondlife
/// <summary>
///
/// </summary>
[XmlRoot("vector4")]
public class LLVector4
{
/// <summary></summary>
@@ -618,6 +623,7 @@ namespace libsecondlife
/// <summary>
///
/// </summary>
[XmlRoot("quaternion")]
public class LLQuaternion
{
/// <summary></summary>

View File

@@ -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";
}
}
}

View File

@@ -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;
}
}
}
}

View File

@@ -36,6 +36,7 @@
<Compile Include="Arguments.cs" />
<Compile Include="Command.cs" />
<Compile Include="Commands\BalanceCommand.cs" />
<Compile Include="Commands\ExportCommand.cs" />
<Compile Include="Commands\LoadCommand.cs" />
<Compile Include="Commands\LoginCommand.cs" />
<Compile Include="Commands\LogoutCommand.cs" />

View File

@@ -157,6 +157,7 @@
<Compile Include="SecondLife.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="SerializableDictionary.cs" />
<Compile Include="Textures.cs">
<SubType>Code</SubType>
</Compile>